/** * Interactive TUI for managing AI assets. * * Tabs: [Assets] [Sources] [Libraries] [Pending] [Sync] * * - Assets — browse and queue install/remove for assets, grouped in a * `origin → publisher → domain → asset` tree. `origin` is the feed * the asset came from (Library / Sources / Skaile Factory Assets * / Store), the outermost collapsible band so it's clear where * each skill comes from. * `domain` is the sidecar `DOMAIN.md` grouping (display-only). * - Sources — third-party github repos registered via `skaile source add`, * shown as a `Sources → org → repo → domain → asset` tree (the * source-origin slice of the Assets feed, with an extra github-org * band). Domains default *collapsed*; install/remove works the * same as the Assets tab. CRUD stays in `skaile source …`. * - Libraries — user authoring places registered via `skaile library init`. * - Pending — staged adds/removes (rich rendering deferred to AF-LIB-TUI-RICH). * - Sync — bulk sync sources + libraries (deferred to AF-LIB-TUI-RICH). * * Keys: ↑↓/jk navigate, PgUp/PgDn/Home/End jump, ←/→ collapse/expand, * space/+/- select, a/Enter apply, d domain info, / search (assets), * 1/2/3 filter to one origin · 0 clear, s sync, i info, * Tab switch, q/Esc quit * * NOTE: rich rendering (status glyphs, behind/ahead counters, in-line sync) for * the Sources/Libraries/Pending/Sync tabs is deferred to AF-LIB-TUI-RICH (see * workspaces/issues.md). The current implementation is a minimal scaffold. */ import { type CatalogEntry } from "@skaile/workspaces/core"; import { Command } from "commander"; import type { AssetOrigin } from "../asset-feeds.ts"; /** * A single row in the manage TUI asset list: an origin header, a publisher * header, a domain header, a domain info line, or an individual asset entry. * * The tree is `origin → publisher → domain → asset`. `origin` (the feed the * asset was gathered from — store / source / library / factory) is the outermost * band and is carried on **every** row, because the same group can appear * under more than one origin and must not collapse together. `source` holds the * **second-level group** — the publisher namespace for most origins, but the * source's short repo name under the Sources band (see {@link OriginEntry.group}); * it is set on header rows **and** asset rows so grouping stays consistent. * `domainSlug` is the * navigational group from a sidecar `DOMAIN.md` (`""` = the synthetic "no * domain" group). A `repo` (`"/"`) is no longer a grouping axis — * it rides on the asset row as a dim provenance badge only. * * A `domain-header` is **navigational**: it collapses/expands and toggles its * info region, but never bulk-installs (unlike origin/publisher headers). * * @docLink cli/commands/manage#make-manage-command */ export interface AssetRow { type: "origin-header" | "publisher-header" | "domain-header" | "domain-info" | "asset" | "source-root" | "org-header" | "repo-header" | "library-root" | "library-header"; origin?: AssetOrigin; source?: string; org?: string; domainSlug?: string; repo?: string; entry?: CatalogEntry; installed?: boolean; underDomain?: boolean; seq?: number; } /** * Filter the full asset row list to only rows that should be visible given the * current collapsed origin / publisher / domain sets, the per-domain info-expand * set, and the active origin filter. The tree is flat (`origin → publisher → * domain → asset`, domain slugs not nested), so collapse checks are exact set * membership — no prefix walking. Collapse keys are origin-namespaced so the * same publisher under two origins collapses independently. * * - Every row is hidden when an `originFilter` is set and the row's origin * doesn't match it. * - An `origin-header` is otherwise always visible. * - A `publisher-header` is hidden when its origin is collapsed. * - A `domain-header` is hidden when its origin or its `"origin:publisher"` key * is collapsed. * - A `domain-info` line follows the same rule as the domain's assets (shown * when the band is open). The `[d]` toggle changes only how it *renders* * (truncated ↔ full), not whether it shows. * - An asset under a real domain is hidden when that `"…:dom:"` key is * collapsed; a "no domain" asset only depends on its origin + publisher. * * A non-empty `query` switches to **search mode**: only assets whose name, * publisher, or description contains it (case-insensitively) are kept, together * with the header / `domain-info` rows on their path. The collapse sets are * **ignored** while searching — search flattens the tree, otherwise matches * inside a default-collapsed band (e.g. `store`) would be invisible. The * `originFilter` still applies to every row (the two combine). * * @param rows - Complete flat list of asset rows. * @param collapsedOrigins - Set of origins whose children are hidden. * @param collapsedSources - Set of `"origin:publisher"` keys whose children are hidden. * @param collapsedDomains - Set of `"origin:publisher:dom:"` keys whose assets are hidden. * @param originFilter - When set, only rows of this origin are kept. * @param query - When non-empty, keep only matching assets + their ancestors (ignores collapse). * @returns Filtered array of visible rows. * @docLink cli/commands/manage#make-manage-command */ export declare function buildVisibleRows(rows: AssetRow[], collapsedOrigins: Set, collapsedSources: Set, collapsedDomains: Set, originFilter?: AssetOrigin | null, query?: string): AssetRow[]; /** * Split one raw stdin chunk into individual key presses. * * Holding a key coalesces its bytes into a single chunk (`"\x1b[B\x1b[B\x1b[B"`), * which matches no binding — so the whole burst would be dropped. Splitting keeps * navigation lossless: * * - `\x1b[` + `[0-9;]*` + a final byte is one key (`\x1b[A`…`\x1b[D`, `\x1b[5~`, `\x1b[H`). * - `\x1bO` + one char is one key (the SS3 arrows some terminals send) — never a * bare `\x1b`, which is the quit binding. * - A trailing incomplete escape is emitted as one key, except a lone trailing * `\x1b` after another key: that is a sequence the reader split mid-escape * (`"\x1b[B\x1b"`), and dispatching it would quit the TUI, so it is dropped. * - Anything else is one key per character (a chunk that is only `\x1b` = Esc). * * @docLink cli/commands/manage#make-manage-command */ export declare function splitKeys(chunk: string): string[]; /** * Return `kind:name` refs for all asset rows belonging to a specific origin. * * @docLink cli/commands/manage#make-manage-command */ export declare function originAssetRefs(rows: AssetRow[], origin: AssetOrigin): string[]; /** * Return `kind:name` refs for all asset rows belonging to a specific * origin + publisher + domain slug (`""` = the "no domain" group). * * @docLink cli/commands/manage#make-manage-command */ export declare function domainAssetRefs(rows: AssetRow[], origin: AssetOrigin, publisher: string, slug: string): string[]; /** * Return `kind:name` refs for all asset rows belonging to a specific * origin + publisher (across its repos). * * @docLink cli/commands/manage#make-manage-command */ export declare function sourceAssetRefs(rows: AssetRow[], origin: AssetOrigin, source: string): string[]; /** * Build the flat Sources-tree row list from the source-origin asset rows. * Hierarchy: a single static "Sources" root → per github org → per repo → "no * domain" assets (directly under the repo) → per real domain (header + optional * info + assets). `registered` injects org/repo bands for sources that have no * discoverable assets yet, so a freshly-added source still shows up. * * @docLink cli/commands/manage#make-manage-command */ export declare function buildSourceTreeRows(assetRows: AssetRow[], registered?: { org: string; repo: string; }[]): AssetRow[]; /** * Filter the flat Sources-tree rows to those visible given the collapsed * org / repo / domain sets. The root is always visible; an org-header hides * when no set applies above it; a repo-header hides under a collapsed org; a * domain-header hides under a collapsed org/repo; a domain-info / domained * asset hides under a collapsed domain (or any collapsed ancestor). * * @docLink cli/commands/manage#make-manage-command */ export declare function buildVisibleSourceRows(rows: AssetRow[], collapsedOrgs: Set, collapsedRepos: Set, collapsedDomains: Set): AssetRow[]; /** Refs of all source-tree asset rows in a github org. */ export declare function sourceOrgRefs(rows: AssetRow[], org: string): string[]; /** Refs of all source-tree asset rows in a specific org + repo. */ export declare function sourceRepoRefs(rows: AssetRow[], org: string, repo: string): string[]; /** Refs of all source-tree asset rows in a specific org + repo + domain slug. */ export declare function sourceDomainRefs(rows: AssetRow[], org: string, repo: string, slug: string): string[]; /** * Build the flat Libraries-tree row list from the library-origin asset rows. * Hierarchy: a single static "Libraries" root → per library band → "no domain" * assets (directly under the library) → per real domain (header + optional info * + assets). `registered` injects a band for each library that has no * discoverable assets yet, so a freshly-created library still shows up. * * @docLink cli/commands/manage#make-manage-command */ export declare function buildLibraryTreeRows(assetRows: AssetRow[], registered?: string[]): AssetRow[]; /** * Filter the flat Libraries-tree rows to those visible given the collapsed * group / domain sets. The root + library headers are always visible; everything * under a collapsed library hides; a domain-info / domained asset hides under a * collapsed domain (a "no domain" asset hangs directly under the library). * * @docLink cli/commands/manage#make-manage-command */ export declare function buildVisibleLibraryRows(rows: AssetRow[], collapsedGroups: Set, collapsedDomains: Set): AssetRow[]; /** Refs of all library-tree asset rows in a specific library band. */ export declare function libraryGroupRefs(rows: AssetRow[], group: string): string[]; /** * Creates the `skaile manage` command. * * Opens an interactive terminal TUI (five tabs: Assets, Sources, Libraries, * Pending, Sync) for browsing, installing, and removing assets. The Sources tab * renders registered github sources as a `Sources → org → repo → domain → asset` * tree (domains default collapsed) and supports the same install/remove flow as * Assets. CRUD for sources and libraries remains in the shell * (`skaile source …` / `skaile library …`); the Libraries tab is still a * read-only scaffold pending AF-LIB-TUI-RICH. * * @returns Configured {@link Command} ready for `program.addCommand()`. * @docLink cli/commands/manage#make-manage-command */ export declare function makeManageCommand(): Command; //# sourceMappingURL=manage.d.ts.map