@skaile/workspaces 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/asset-manager/index.js +2 -2
  3. package/dist/asset-manager/installer.js +1 -1
  4. package/dist/asset-manager/src/index.d.ts.map +1 -1
  5. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  6. package/dist/base-assets/connectors/flow/run-flow.js +1 -1
  7. package/dist/{chunk-SO43XRWF.js → chunk-67TJEQJE.js} +2 -2
  8. package/dist/{chunk-SO43XRWF.js.map → chunk-67TJEQJE.js.map} +1 -1
  9. package/dist/{chunk-7R4WLTZW.js → chunk-DEZVZSBN.js} +11 -16
  10. package/dist/chunk-DEZVZSBN.js.map +1 -0
  11. package/dist/{chunk-4GEVGRWB.js → chunk-ERCOCLW5.js} +9 -11
  12. package/dist/chunk-ERCOCLW5.js.map +1 -0
  13. package/dist/{chunk-2NIOMFSQ.js → chunk-FNCYNUGS.js} +78 -81
  14. package/dist/chunk-FNCYNUGS.js.map +1 -0
  15. package/dist/{chunk-Z24KPZKU.js → chunk-HJV7MHG5.js} +2 -2
  16. package/dist/{chunk-Z24KPZKU.js.map → chunk-HJV7MHG5.js.map} +1 -1
  17. package/dist/{chunk-6EN5IJ2Y.js → chunk-IY4X7PZN.js} +3 -3
  18. package/dist/{chunk-6EN5IJ2Y.js.map → chunk-IY4X7PZN.js.map} +1 -1
  19. package/dist/cli/index.js +146 -98
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/cli/src/commands/manage.d.ts +31 -20
  22. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  23. package/dist/library/index.js +1 -1
  24. package/dist/library/src/local/db.d.ts.map +1 -1
  25. package/dist/library/src/local/store-paths.d.ts.map +1 -1
  26. package/dist/{open-library-XD7QYLMW.js → open-library-T6RXQJTQ.js} +4 -4
  27. package/dist/{open-library-XD7QYLMW.js.map → open-library-T6RXQJTQ.js.map} +1 -1
  28. package/dist/runner/index.js +1 -1
  29. package/dist/sdk/asset-manager.js +2 -2
  30. package/dist/sdk/index.js +1 -1
  31. package/dist/sdk/runner.js +1 -1
  32. package/dist/tui/index.js +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunk-2NIOMFSQ.js.map +0 -1
  35. package/dist/chunk-4GEVGRWB.js.map +0 -1
  36. package/dist/chunk-7R4WLTZW.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { logErr } from './chunk-4NDWKA64.js';
2
- import { knowledgeKindProvider } from './chunk-2NIOMFSQ.js';
2
+ import { knowledgeKindProvider } from './chunk-FNCYNUGS.js';
3
3
  import { createDefaultRegistry } from './chunk-GKIA2PU5.js';
4
4
  import { flowKindProvider } from './chunk-ICS76R4T.js';
5
5
 
@@ -97,5 +97,5 @@ async function openLibraryManager() {
97
97
  }
98
98
 
99
99
  export { createFullRegistry, openCatalogSource, openLibrary, openLibraryManager, resolveCatalogSource };
100
- //# sourceMappingURL=chunk-6EN5IJ2Y.js.map
101
- //# sourceMappingURL=chunk-6EN5IJ2Y.js.map
100
+ //# sourceMappingURL=chunk-IY4X7PZN.js.map
101
+ //# sourceMappingURL=chunk-IY4X7PZN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/open-registry.ts","../cli/src/open-library.ts"],"names":["source"],"mappings":"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","file":"chunk-6EN5IJ2Y.js","sourcesContent":["/**\n * open-registry.ts — shared helper to create a full AssetKindRegistry.\n *\n * Bootstraps the registry with all built-in providers (9 core + preset)\n * from @skaile/discovery, plus the extension kind providers (flow from\n * @skaile/workspaces/base-assets/connectors/flow/engine, knowledge from @skaile/library).\n *\n * This is the single registration point for the CLI. All code paths\n * that need a registry (source sync, lib-status, etc.) should use this.\n */\n\nimport { flowKindProvider } from \"@skaile/workspaces/base-assets/connectors/flow/engine\";\nimport type { AssetKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { createDefaultRegistry } from \"@skaile/workspaces/discovery\";\nimport { knowledgeKindProvider } from \"@skaile/workspaces/library\";\n\n/**\n * Create a fully-configured AssetKindRegistry with all known providers.\n *\n * Registers:\n * - 9 core kinds (skill, agent, connector, mount, mcp-server, contract, prompt, persona, ruleset)\n * - preset (composition entity)\n * - flow (extension, from @skaile/workspaces/base-assets/connectors/flow/engine)\n * - knowledge (extension, from @skaile/library)\n *\n * @returns An unfrozen registry (auto-freezes on first read)\n */\nexport function createFullRegistry(): AssetKindRegistry {\n const registry = createDefaultRegistry();\n registry.register(flowKindProvider);\n registry.register(knowledgeKindProvider);\n return registry;\n}\n","/**\n * open-library.ts — shared helpers to open the LocalIndex and the configured\n * Catalog source.\n *\n * Lazy-loads the `@skaile/workspaces/library` subpath and returns the\n * LocalIndex instance (backed by `@libsql/client`; runs on Node and Bun).\n * The catalog-source helper reads\n * `~/.skaile/config.yaml` (and project-level overlay if `projectDir` is given)\n * to decide between {@link RemoteCatalogSource} (default — points at\n * `https://skaile.store`) and a {@link LocalCatalogSource} bound to the most\n * recent local library registered via `skaile source add`.\n */\n\nimport { logErr } from \"./helpers.ts\";\nimport { createFullRegistry } from \"./open-registry.ts\";\n\n/**\n * Open the LocalIndex with the full kind registry. Exits with code 1\n * if the library directory cannot be created.\n *\n * @returns A `LocalIndex` instance ready for use.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibrary() {\n try {\n const { LocalIndex } = await import(\"@skaile/workspaces/library\");\n return new LocalIndex({ kindRegistry: createFullRegistry() });\n } catch (err) {\n logErr(`Could not open LocalIndex: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\n/**\n * Resolve the configured **remote** Catalog source for the CLI.\n *\n * Reads `~/.skaile/config.yaml` (plus the optional project-level overlay) and\n * returns a {@link RemoteCatalogSource} pointing at `catalog.url` (default:\n * `https://skaile.store`). The `cache_ttl: 0` config flag flips the source\n * into air-gapped mode: network reads are disabled, only `skaile update`\n * performs refreshes.\n *\n * **Local-mode rejection.** If the resolved config has `catalog.url: local`\n * this helper throws — callers wanting the dispatched local-or-remote source\n * must use {@link resolveCatalogSource}. Remote-only consumers like\n * `skaile update --catalog-only` rely on this strict behaviour.\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A configured {@link RemoteCatalogSource}.\n * @throws When `catalog.url` is the `local` sentinel.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<\n | import(\"@skaile/workspaces/library\").RemoteCatalogSource\n | import(\"@skaile/workspaces/library\").RestCatalogSource\n> {\n const { resolveConfig, RemoteCatalogSource, RestCatalogSource, isLocalCatalogUrl } = await import(\n \"@skaile/workspaces/library\"\n );\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n if (isLocalCatalogUrl(baseUrl)) {\n throw new Error(\n \"catalog.url is set to 'local' — remote catalog is disabled. \" +\n \"Use `skaile source add <path>` + `skaile source sync` for local sources, \" +\n \"or set `catalog.url: https://skaile.store` in ~/.skaile/config.yaml.\",\n );\n }\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n if (cfg.catalog.framing === \"rest\") {\n return new RestCatalogSource({ baseUrl, cacheTtlMs });\n }\n return new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n}\n\n/**\n * Resolved catalog source plus a close handle for releasing any underlying\n * resources (e.g. the `LocalIndex` SQLite connection in local mode).\n *\n * Callers MUST invoke `close()` when done — typically in a `finally` block.\n * For remote-mode sources `close()` is a no-op, but the contract is uniform\n * so consumers don't have to branch.\n *\n * @docLink cli/dev-guide#open-library\n */\nexport interface ResolvedCatalogSource {\n /** The {@link ICatalogSource} ready for use. */\n source: import(\"@skaile/workspaces/library\").ICatalogSource;\n /** Release any underlying resources (SQLite handle in local mode). */\n close(): void;\n}\n\n/**\n * Resolve the configured Catalog source — local or remote — based on\n * `~/.skaile/config.yaml`.\n *\n * Dispatch:\n * - `catalog.url: local` → opens {@link LocalIndex}, picks the most recently\n * registered local library whose `path` still exists on disk, and returns a\n * {@link LocalCatalogSource} bound to that library. Throws if no usable\n * local library is registered.\n * - any URL → returns {@link RemoteCatalogSource} (same as\n * {@link openCatalogSource}).\n *\n * The returned `close()` releases the underlying `LocalIndex` SQLite handle\n * in local mode (no-op in remote mode). Callers MUST invoke it — typically in\n * a `finally` block — to satisfy `library/CLAUDE.md` § \"Notes for Consumers\".\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A `ResolvedCatalogSource` carrying the source and a close handle.\n * @throws When `local` is configured but no usable local library is registered.\n * @docLink cli/dev-guide#open-library\n */\nexport async function resolveCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<ResolvedCatalogSource> {\n const {\n resolveConfig,\n RemoteCatalogSource,\n RestCatalogSource,\n LocalCatalogSource,\n isLocalCatalogUrl,\n } = await import(\"@skaile/workspaces/library\");\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n\n if (isLocalCatalogUrl(baseUrl)) {\n const fs = await import(\"node:fs\");\n const library = await openLibrary();\n try {\n const sources = await library.listSources();\n type LibraryRow = (typeof sources)[number];\n // Type-narrow: `path` is required for local libraries after the filter.\n const usable = sources\n .filter(\n (s): s is LibraryRow & { path: string } =>\n s.backend === \"local\" && typeof s.path === \"string\" && s.path.length > 0,\n )\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n if (usable.length === 0) {\n throw new Error(\n \"catalog.url is set to 'local' but no local library is registered. \" +\n \"Run `skaile source add <path>` first, then `skaile source sync`.\",\n );\n }\n\n // Prefer the most recently added library whose path still exists.\n const present = usable.find((s) => fs.existsSync(s.path));\n if (!present) {\n const head = usable[0];\n throw new Error(\n `catalog.url is set to 'local' but every registered local library has a missing path on disk. ` +\n `Most recent: ${head.path} (library ${head.id}). ` +\n `Re-register with \\`skaile source add <existing-path>\\` or run \\`skaile source list\\` to inspect.`,\n );\n }\n\n const source = new LocalCatalogSource(\n library,\n present.id,\n present.path,\n createFullRegistry(),\n );\n return { source, close: () => library.close() };\n } catch (err) {\n // Release the handle on any failure during dispatch — otherwise the\n // SQLite WAL state leaks for the lifetime of the process.\n library.close();\n throw err;\n }\n }\n\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n const source =\n cfg.catalog.framing === \"rest\"\n ? new RestCatalogSource({ baseUrl, cacheTtlMs })\n : new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n return { source, close: () => {} };\n}\n\n/**\n * Open the LibraryManager bound to the active LocalIndex.\n * Caller owns lifetime — must call `close()` (returned helper closes the\n * underlying LocalIndex).\n *\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibraryManager(): Promise<{\n manager: import(\"@skaile/workspaces/library\").LibraryManager;\n library: import(\"@skaile/workspaces/library\").LocalIndex;\n close: () => void;\n}> {\n const { LibraryManager } = await import(\"@skaile/workspaces/library\");\n const library = await openLibrary();\n const manager = new LibraryManager(library);\n return { manager, library, close: () => library.close() };\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/open-registry.ts","../cli/src/open-library.ts"],"names":["source"],"mappings":"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","file":"chunk-IY4X7PZN.js","sourcesContent":["/**\n * open-registry.ts — shared helper to create a full AssetKindRegistry.\n *\n * Bootstraps the registry with all built-in providers (9 core + preset)\n * from @skaile/discovery, plus the extension kind providers (flow from\n * @skaile/workspaces/base-assets/connectors/flow/engine, knowledge from @skaile/library).\n *\n * This is the single registration point for the CLI. All code paths\n * that need a registry (source sync, lib-status, etc.) should use this.\n */\n\nimport { flowKindProvider } from \"@skaile/workspaces/base-assets/connectors/flow/engine\";\nimport type { AssetKindRegistry } from \"@skaile/workspaces/discovery\";\nimport { createDefaultRegistry } from \"@skaile/workspaces/discovery\";\nimport { knowledgeKindProvider } from \"@skaile/workspaces/library\";\n\n/**\n * Create a fully-configured AssetKindRegistry with all known providers.\n *\n * Registers:\n * - 9 core kinds (skill, agent, connector, mount, mcp-server, contract, prompt, persona, ruleset)\n * - preset (composition entity)\n * - flow (extension, from @skaile/workspaces/base-assets/connectors/flow/engine)\n * - knowledge (extension, from @skaile/library)\n *\n * @returns An unfrozen registry (auto-freezes on first read)\n */\nexport function createFullRegistry(): AssetKindRegistry {\n const registry = createDefaultRegistry();\n registry.register(flowKindProvider);\n registry.register(knowledgeKindProvider);\n return registry;\n}\n","/**\n * open-library.ts — shared helpers to open the LocalIndex and the configured\n * Catalog source.\n *\n * Lazy-loads the `@skaile/workspaces/library` subpath and returns the\n * LocalIndex instance (backed by `@libsql/client`; runs on Node and Bun).\n * The catalog-source helper reads\n * `~/.skaile/config.yaml` (and project-level overlay if `projectDir` is given)\n * to decide between {@link RemoteCatalogSource} (default — points at\n * `https://skaile.store`) and a {@link LocalCatalogSource} bound to the most\n * recent local library registered via `skaile source add`.\n */\n\nimport { logErr } from \"./helpers.ts\";\nimport { createFullRegistry } from \"./open-registry.ts\";\n\n/**\n * Open the LocalIndex with the full kind registry. Exits with code 1\n * if the library directory cannot be created.\n *\n * @returns A `LocalIndex` instance ready for use.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibrary() {\n try {\n const { LocalIndex } = await import(\"@skaile/workspaces/library\");\n return new LocalIndex({ kindRegistry: createFullRegistry() });\n } catch (err) {\n logErr(`Could not open LocalIndex: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\n/**\n * Resolve the configured **remote** Catalog source for the CLI.\n *\n * Reads `~/.skaile/config.yaml` (plus the optional project-level overlay) and\n * returns a {@link RemoteCatalogSource} pointing at `catalog.url` (default:\n * `https://skaile.store`). The `cache_ttl: 0` config flag flips the source\n * into air-gapped mode: network reads are disabled, only `skaile update`\n * performs refreshes.\n *\n * **Local-mode rejection.** If the resolved config has `catalog.url: local`\n * this helper throws — callers wanting the dispatched local-or-remote source\n * must use {@link resolveCatalogSource}. Remote-only consumers like\n * `skaile update --catalog-only` rely on this strict behaviour.\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A configured {@link RemoteCatalogSource}.\n * @throws When `catalog.url` is the `local` sentinel.\n * @docLink cli/dev-guide#open-library\n */\nexport async function openCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<\n | import(\"@skaile/workspaces/library\").RemoteCatalogSource\n | import(\"@skaile/workspaces/library\").RestCatalogSource\n> {\n const { resolveConfig, RemoteCatalogSource, RestCatalogSource, isLocalCatalogUrl } = await import(\n \"@skaile/workspaces/library\"\n );\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n if (isLocalCatalogUrl(baseUrl)) {\n throw new Error(\n \"catalog.url is set to 'local' — remote catalog is disabled. \" +\n \"Use `skaile source add <path>` + `skaile source sync` for local sources, \" +\n \"or set `catalog.url: https://skaile.store` in ~/.skaile/config.yaml.\",\n );\n }\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n if (cfg.catalog.framing === \"rest\") {\n return new RestCatalogSource({ baseUrl, cacheTtlMs });\n }\n return new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n}\n\n/**\n * Resolved catalog source plus a close handle for releasing any underlying\n * resources (e.g. the `LocalIndex` SQLite connection in local mode).\n *\n * Callers MUST invoke `close()` when done — typically in a `finally` block.\n * For remote-mode sources `close()` is a no-op, but the contract is uniform\n * so consumers don't have to branch.\n *\n * @docLink cli/dev-guide#open-library\n */\nexport interface ResolvedCatalogSource {\n /** The {@link ICatalogSource} ready for use. */\n source: import(\"@skaile/workspaces/library\").ICatalogSource;\n /** Release any underlying resources (SQLite handle in local mode). */\n close(): void;\n}\n\n/**\n * Resolve the configured Catalog source — local or remote — based on\n * `~/.skaile/config.yaml`.\n *\n * Dispatch:\n * - `catalog.url: local` → opens {@link LocalIndex}, picks the most recently\n * registered local library whose `path` still exists on disk, and returns a\n * {@link LocalCatalogSource} bound to that library. Throws if no usable\n * local library is registered.\n * - any URL → returns {@link RemoteCatalogSource} (same as\n * {@link openCatalogSource}).\n *\n * The returned `close()` releases the underlying `LocalIndex` SQLite handle\n * in local mode (no-op in remote mode). Callers MUST invoke it — typically in\n * a `finally` block — to satisfy `library/CLAUDE.md` § \"Notes for Consumers\".\n *\n * @param opts - Project directory (overlays project config) and explicit overrides.\n * @returns A `ResolvedCatalogSource` carrying the source and a close handle.\n * @throws When `local` is configured but no usable local library is registered.\n * @docLink cli/dev-guide#open-library\n */\nexport async function resolveCatalogSource(opts?: {\n projectDir?: string;\n baseUrlOverride?: string;\n /** Override the user-config path for tests. */\n userConfigFile?: string;\n}): Promise<ResolvedCatalogSource> {\n const {\n resolveConfig,\n RemoteCatalogSource,\n RestCatalogSource,\n LocalCatalogSource,\n isLocalCatalogUrl,\n } = await import(\"@skaile/workspaces/library\");\n const cfg = resolveConfig({\n projectDir: opts?.projectDir,\n userConfigFile: opts?.userConfigFile,\n });\n const baseUrl = opts?.baseUrlOverride ?? cfg.catalog.url;\n\n if (isLocalCatalogUrl(baseUrl)) {\n const fs = await import(\"node:fs\");\n const library = await openLibrary();\n try {\n const sources = await library.listSources();\n type LibraryRow = (typeof sources)[number];\n // Type-narrow: `path` is required for local libraries after the filter.\n const usable = sources\n .filter(\n (s): s is LibraryRow & { path: string } =>\n s.backend === \"local\" && typeof s.path === \"string\" && s.path.length > 0,\n )\n .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());\n\n if (usable.length === 0) {\n throw new Error(\n \"catalog.url is set to 'local' but no local library is registered. \" +\n \"Run `skaile source add <path>` first, then `skaile source sync`.\",\n );\n }\n\n // Prefer the most recently added library whose path still exists.\n const present = usable.find((s) => fs.existsSync(s.path));\n if (!present) {\n const head = usable[0];\n throw new Error(\n `catalog.url is set to 'local' but every registered local library has a missing path on disk. ` +\n `Most recent: ${head.path} (library ${head.id}). ` +\n `Re-register with \\`skaile source add <existing-path>\\` or run \\`skaile source list\\` to inspect.`,\n );\n }\n\n const source = new LocalCatalogSource(\n library,\n present.id,\n present.path,\n createFullRegistry(),\n );\n return { source, close: () => library.close() };\n } catch (err) {\n // Release the handle on any failure during dispatch — otherwise the\n // SQLite WAL state leaks for the lifetime of the process.\n library.close();\n throw err;\n }\n }\n\n const cacheTtlMs = cfg.catalog.cache_ttl * 1000;\n const source =\n cfg.catalog.framing === \"rest\"\n ? new RestCatalogSource({ baseUrl, cacheTtlMs })\n : new RemoteCatalogSource({ baseUrl, cacheTtlMs });\n return { source, close: () => {} };\n}\n\n/**\n * Open the LibraryManager bound to the active LocalIndex.\n * Caller owns lifetime — must call `close()` (returned helper closes the\n * underlying LocalIndex).\n *\n * @docLink cli/dev-guide#open-library\n */\nexport async function openLibraryManager(): Promise<{\n manager: import(\"@skaile/workspaces/library\").LibraryManager;\n library: import(\"@skaile/workspaces/library\").LocalIndex;\n close: () => void;\n}> {\n const { LibraryManager } = await import(\"@skaile/workspaces/library\");\n const library = await openLibrary();\n const manager = new LibraryManager(library);\n return { manager, library, close: () => library.close() };\n}\n"]}
package/dist/cli/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { openCatalogSource, openLibrary, createFullRegistry, openLibraryManager } from '../chunk-6EN5IJ2Y.js';
2
+ import { openCatalogSource, openLibrary, createFullRegistry, openLibraryManager } from '../chunk-IY4X7PZN.js';
3
3
  import { logErr, S, logOk, colorRef, logInfo, logWarn, kindColorPad, kindColor, formatRelativeTime } from '../chunk-4NDWKA64.js';
4
4
  import { getStoreConfig, storeFetch, saveStoreTokens, clearStoreTokens, isStoreAuthenticated } from '../chunk-6DEGWPAR.js';
5
5
  import { AI_RESOURCES } from '../chunk-2M3XTMOL.js';
6
6
  import { LocalSecretsProvider } from '../chunk-JDX54X4Y.js';
7
- import { resolveLibraryDir, skaileHomeDir } from '../chunk-2NIOMFSQ.js';
7
+ import { resolveLibraryDir, skaileHomeDir } from '../chunk-FNCYNUGS.js';
8
8
  import '../chunk-R7FOF242.js';
9
9
  import '../chunk-GKIA2PU5.js';
10
10
  import '../chunk-OKRUTSG7.js';
11
- import { runFlow, resumeFlow } from '../chunk-SO43XRWF.js';
11
+ import { runFlow, resumeFlow } from '../chunk-67TJEQJE.js';
12
12
  import '../chunk-GCJXPUHG.js';
13
13
  import { validateFlowVersions, parseSkillFrontmatter } from '../chunk-IPUYL6TD.js';
14
- import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-Z24KPZKU.js';
14
+ import { runAgentChat, loadSessionById, loadSession, listSessions, setCurrentSession, deleteSession, clearSession, loadAgentManifest, compileComposition, MarkdownStreamer, resolveMixin } from '../chunk-HJV7MHG5.js';
15
15
  import { buildClaudePluginFiles } from '../chunk-G7O7WDXX.js';
16
16
  import '../chunk-X5YPJV4N.js';
17
17
  import '../chunk-O7SG5PC2.js';
@@ -32,8 +32,8 @@ import '../chunk-QAVZOJCV.js';
32
32
  import { loadAllFlows } from '../chunk-ICS76R4T.js';
33
33
  import '../chunk-GZWJGNNN.js';
34
34
  import '../chunk-FVTV7M76.js';
35
- import { AssetManager } from '../chunk-7R4WLTZW.js';
36
- import '../chunk-4GEVGRWB.js';
35
+ import { AssetManager } from '../chunk-DEZVZSBN.js';
36
+ import '../chunk-ERCOCLW5.js';
37
37
  import { readLock, resolveSettings, globalSettingsPath, projectSettingsPath, loadSettings, saveSettings, portableSpawn, portableSpawnSync } from '../chunk-4RUVG5GX.js';
38
38
  import '../chunk-JKNWJ64A.js';
39
39
  import { SUPPORTED_DRIVER_TARGETS } from '../chunk-O4JH3KUE.js';
@@ -470,7 +470,7 @@ function makeCatalogCommand() {
470
470
  const cfg = resolveConfig({ projectDir });
471
471
  const baseUrl = opts.url ?? cfg.catalog.url;
472
472
  if (isLocalCatalogUrl(baseUrl)) {
473
- const { resolveCatalogSource } = await import('../open-library-XD7QYLMW.js');
473
+ const { resolveCatalogSource } = await import('../open-library-T6RXQJTQ.js');
474
474
  let resolved;
475
475
  try {
476
476
  resolved = await resolveCatalogSource({ projectDir: opts.projectDir });
@@ -2022,42 +2022,43 @@ function makeLogsCommand() {
2022
2022
  }
2023
2023
  var am;
2024
2024
  var state = {
2025
- tab: "libraries",
2025
+ tab: "assets",
2026
2026
  cursor: 0,
2027
2027
  assetRows: [],
2028
+ sourceRows: [],
2028
2029
  libraryRows: [],
2029
2030
  visibleRows: [],
2030
2031
  pendingAdds: /* @__PURE__ */ new Set(),
2031
2032
  pendingRemoves: /* @__PURE__ */ new Set(),
2032
- collapsedRepos: /* @__PURE__ */ new Set(),
2033
+ collapsedSources: /* @__PURE__ */ new Set(),
2033
2034
  collapsedDomains: /* @__PURE__ */ new Set(),
2034
2035
  message: "",
2035
2036
  cols: 80,
2036
2037
  awaitingExitConfirm: false
2037
2038
  };
2038
- function buildVisibleRows(rows, collapsedRepos, collapsedDomains) {
2039
+ function buildVisibleRows(rows, collapsedSources, collapsedDomains) {
2039
2040
  return rows.filter((row) => {
2040
- if (row.type === "repo-header") return true;
2041
- if (row.type === "header") return !collapsedRepos.has(row.repo);
2042
- const repo = row.entry?.repository ?? "other";
2041
+ if (row.type === "source-header") return true;
2042
+ if (row.type === "header") return !collapsedSources.has(row.source);
2043
+ const source = row.entry?.repository ?? "other";
2043
2044
  const domain = row.entry?.domain ?? "other";
2044
- return !collapsedRepos.has(repo) && !collapsedDomains.has(`${repo}:${domain}`);
2045
+ return !collapsedSources.has(source) && !collapsedDomains.has(`${source}:${domain}`);
2045
2046
  });
2046
2047
  }
2047
- function domainAssetRefs(rows, repo, domain) {
2048
- return rows.filter((r) => isAsset(r) && inDomain(r, repo, domain)).map((r) => assetRefOf(r));
2048
+ function domainAssetRefs(rows, source, domain) {
2049
+ return rows.filter((r) => isAsset(r) && inDomain(r, source, domain)).map((r) => assetRefOf(r));
2049
2050
  }
2050
- function repoAssetRefs(rows, repo) {
2051
- return rows.filter((r) => isAsset(r) && inRepo(r, repo)).map((r) => assetRefOf(r));
2051
+ function sourceAssetRefs(rows, source) {
2052
+ return rows.filter((r) => isAsset(r) && inSource(r, source)).map((r) => assetRefOf(r));
2052
2053
  }
2053
2054
  function isAsset(r) {
2054
2055
  return r.type === "asset";
2055
2056
  }
2056
- function inRepo(r, repo) {
2057
- return (r.entry?.repository ?? "other") === repo;
2057
+ function inSource(r, source) {
2058
+ return (r.entry?.repository ?? "other") === source;
2058
2059
  }
2059
- function inDomain(r, repo, domain) {
2060
- return inRepo(r, repo) && (r.entry?.domain ?? "other") === domain;
2060
+ function inDomain(r, source, domain) {
2061
+ return inSource(r, source) && (r.entry?.domain ?? "other") === domain;
2061
2062
  }
2062
2063
  function assetRefOf(r) {
2063
2064
  if (!isAsset(r) || !r.entry) return null;
@@ -2081,17 +2082,17 @@ function setSelection(ref, action) {
2081
2082
  state.pendingRemoves.delete(ref);
2082
2083
  return;
2083
2084
  }
2084
- resolved = row.deployed ? "remove" : "add";
2085
+ resolved = row.installed ? "remove" : "add";
2085
2086
  } else {
2086
2087
  resolved = action;
2087
2088
  }
2088
2089
  if (resolved === "add") {
2089
2090
  state.pendingRemoves.delete(ref);
2090
- if (row.deployed) return;
2091
+ if (row.installed) return;
2091
2092
  state.pendingAdds.add(ref);
2092
2093
  } else {
2093
2094
  state.pendingAdds.delete(ref);
2094
- if (!row.deployed) return;
2095
+ if (!row.installed) return;
2095
2096
  state.pendingRemoves.add(ref);
2096
2097
  }
2097
2098
  }
@@ -2099,51 +2100,53 @@ function bulkSelection(refs, action) {
2099
2100
  for (const ref of refs) setSelection(ref, action);
2100
2101
  }
2101
2102
  function actOnHeader(row, action) {
2102
- if (row.type === "repo-header") {
2103
- bulkSelection(repoAssetRefs(state.assetRows, row.repo), action);
2103
+ if (row.type === "source-header") {
2104
+ bulkSelection(sourceAssetRefs(state.assetRows, row.source), action);
2104
2105
  return true;
2105
2106
  }
2106
2107
  if (row.type === "header") {
2107
- bulkSelection(domainAssetRefs(state.assetRows, row.repo, row.domain), action);
2108
+ bulkSelection(domainAssetRefs(state.assetRows, row.source, row.domain), action);
2108
2109
  return true;
2109
2110
  }
2110
2111
  return false;
2111
2112
  }
2112
2113
  function loadAssets() {
2113
2114
  const entries = am.search();
2114
- const deployed = new Set(am.listDeployed().map((e) => `${e.kind}:${e.name}`));
2115
- const byRepo = /* @__PURE__ */ new Map();
2115
+ const installed = new Set(am.listDeployed().map((e) => `${e.kind}:${e.name}`));
2116
+ const bySource = /* @__PURE__ */ new Map();
2116
2117
  for (const e of entries) {
2117
- const repo = e.repository ?? "other";
2118
+ const source = e.repository ?? "other";
2118
2119
  const domain = e.domain ?? "other";
2119
- if (!byRepo.has(repo)) byRepo.set(repo, /* @__PURE__ */ new Map());
2120
- const domainMap = byRepo.get(repo);
2120
+ if (!bySource.has(source)) bySource.set(source, /* @__PURE__ */ new Map());
2121
+ const domainMap = bySource.get(source);
2121
2122
  if (!domainMap.has(domain)) domainMap.set(domain, []);
2122
2123
  domainMap.get(domain).push(e);
2123
2124
  }
2124
2125
  const rows = [];
2125
- for (const [repo, domainMap] of [...byRepo.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
2126
- rows.push({ type: "repo-header", repo });
2126
+ for (const [source, domainMap] of [...bySource.entries()].sort(
2127
+ (a, b) => a[0].localeCompare(b[0])
2128
+ )) {
2129
+ rows.push({ type: "source-header", source });
2127
2130
  for (const [domain, items] of [...domainMap.entries()].sort(
2128
2131
  (a, b) => a[0].localeCompare(b[0])
2129
2132
  )) {
2130
- rows.push({ type: "header", repo, domain });
2133
+ rows.push({ type: "header", source, domain });
2131
2134
  items.sort(
2132
2135
  (a, b) => a.kind !== b.kind ? a.kind.localeCompare(b.kind) : a.name.localeCompare(b.name)
2133
2136
  );
2134
2137
  for (const entry of items) {
2135
2138
  const ref = `${entry.kind}:${entry.name}`;
2136
- rows.push({ type: "asset", entry, deployed: deployed.has(ref) });
2139
+ rows.push({ type: "asset", entry, installed: installed.has(ref) });
2137
2140
  }
2138
2141
  }
2139
2142
  }
2140
2143
  state.assetRows = rows;
2141
- const newRepos = new Set(rows.filter((r) => r.type === "repo-header").map((r) => r.repo));
2142
- for (const r of state.collapsedRepos) {
2143
- if (!newRepos.has(r)) state.collapsedRepos.delete(r);
2144
+ const newSources = new Set(rows.filter((r) => r.type === "source-header").map((r) => r.source));
2145
+ for (const s of state.collapsedSources) {
2146
+ if (!newSources.has(s)) state.collapsedSources.delete(s);
2144
2147
  }
2145
2148
  const newDomainKeys = new Set(
2146
- rows.filter((r) => r.type === "header").map((r) => `${r.repo}:${r.domain}`)
2149
+ rows.filter((r) => r.type === "header").map((r) => `${r.source}:${r.domain}`)
2147
2150
  );
2148
2151
  for (const d of state.collapsedDomains) {
2149
2152
  if (!newDomainKeys.has(d)) state.collapsedDomains.delete(d);
@@ -2151,11 +2154,16 @@ function loadAssets() {
2151
2154
  for (const d of newDomainKeys) state.collapsedDomains.add(d);
2152
2155
  rebuildVisible();
2153
2156
  }
2154
- async function loadLibraries() {
2157
+ async function loadSourcesAndLibraries() {
2155
2158
  try {
2156
- const { openLibraryManager: openLibraryManager2 } = await import('../open-library-XD7QYLMW.js');
2159
+ const [{ openLibraryManager: openLibraryManager2 }, { skaileHomeDir: skaileHomeDir2 }] = await Promise.all([
2160
+ import('../open-library-T6RXQJTQ.js'),
2161
+ import('../library/index.js')
2162
+ ]);
2157
2163
  const { manager, library, close } = await openLibraryManager2();
2158
2164
  try {
2165
+ const sourcesDir2 = path15__default.join(skaileHomeDir2(), "sources");
2166
+ const isSourceRow2 = (l) => l.path.startsWith(sourcesDir2);
2159
2167
  const libs = await manager.listLibraries();
2160
2168
  const defs = await library.listAssetDefs();
2161
2169
  const counts = /* @__PURE__ */ new Map();
@@ -2163,7 +2171,13 @@ async function loadLibraries() {
2163
2171
  const id = d.libraryId ?? "";
2164
2172
  counts.set(id, (counts.get(id) ?? 0) + 1);
2165
2173
  }
2166
- state.libraryRows = libs.map((l) => ({
2174
+ state.sourceRows = libs.filter(isSourceRow2).map((l) => ({
2175
+ name: l.name,
2176
+ path: l.path,
2177
+ ownership: l.ownership,
2178
+ assetCount: counts.get(l.id) ?? 0
2179
+ }));
2180
+ state.libraryRows = libs.filter((l) => !isSourceRow2(l)).map((l) => ({
2167
2181
  name: l.name,
2168
2182
  backend: l.backend,
2169
2183
  ownership: l.ownership,
@@ -2174,13 +2188,14 @@ async function loadLibraries() {
2174
2188
  close();
2175
2189
  }
2176
2190
  } catch {
2191
+ state.sourceRows = [];
2177
2192
  state.libraryRows = [];
2178
2193
  }
2179
2194
  }
2180
2195
  function rebuildVisible() {
2181
2196
  state.visibleRows = buildVisibleRows(
2182
2197
  state.assetRows,
2183
- state.collapsedRepos,
2198
+ state.collapsedSources,
2184
2199
  state.collapsedDomains
2185
2200
  );
2186
2201
  clampCursor();
@@ -2195,19 +2210,11 @@ function moveCursor(delta) {
2195
2210
  state.cursor = Math.max(0, Math.min(maxCursor(), state.cursor + delta));
2196
2211
  }
2197
2212
  function nextTab() {
2198
- const order = ["libraries", "assets", "pending", "sync"];
2213
+ const order = ["assets", "sources", "libraries", "pending", "sync"];
2199
2214
  state.tab = order[(order.indexOf(state.tab) + 1) % order.length];
2200
2215
  state.cursor = 0;
2201
2216
  }
2202
2217
  var TABS = {
2203
- libraries: {
2204
- label: "Libraries",
2205
- rowCount: () => state.libraryRows.length,
2206
- selectableCount: () => state.libraryRows.length,
2207
- emptyMsg: " No libraries registered. Run `skaile library init <name>` or `skaile library add <git-url>` from the shell.",
2208
- renderRow: (i, sel) => renderLibraryRow(state.libraryRows[i], sel),
2209
- footer: " \u2191\u2193 navigate Tab switch q quit (use `skaile library \u2026` from the shell for CRUD)"
2210
- },
2211
2218
  assets: {
2212
2219
  label: "Assets",
2213
2220
  rowCount: () => state.visibleRows.length,
@@ -2215,6 +2222,22 @@ var TABS = {
2215
2222
  renderRow: (i, sel) => renderAssetRow(state.visibleRows[i], sel),
2216
2223
  footer: " \u2191\u2193/jk navigate \u2190/\u2192 collapse/expand [space/+/-] select [a/\u21B5] apply [i] info Tab switch [q/esc] quit"
2217
2224
  },
2225
+ sources: {
2226
+ label: "Sources",
2227
+ rowCount: () => state.sourceRows.length,
2228
+ selectableCount: () => state.sourceRows.length,
2229
+ emptyMsg: " No sources registered. Run `skaile source add <git-url>` from the shell to track a github repo.",
2230
+ renderRow: (i, sel) => renderSourceRow(state.sourceRows[i], sel),
2231
+ footer: " \u2191\u2193 navigate Tab switch q quit (use `skaile source \u2026` from the shell for CRUD)"
2232
+ },
2233
+ libraries: {
2234
+ label: "Libraries",
2235
+ rowCount: () => state.libraryRows.length,
2236
+ selectableCount: () => state.libraryRows.length,
2237
+ emptyMsg: " No libraries registered. Run `skaile library init <name>` from the shell to author your own.",
2238
+ renderRow: (i, sel) => renderLibraryRow(state.libraryRows[i], sel),
2239
+ footer: " \u2191\u2193 navigate Tab switch q quit (use `skaile library \u2026` from the shell for CRUD)"
2240
+ },
2218
2241
  pending: {
2219
2242
  label: "Pending",
2220
2243
  rowCount: () => 0,
@@ -2227,7 +2250,7 @@ var TABS = {
2227
2250
  label: "Sync",
2228
2251
  rowCount: () => 0,
2229
2252
  selectableCount: () => 0,
2230
- emptyMsg: " Press S to sync all libraries (rich rendering deferred to AF-LIB-TUI-RICH).",
2253
+ emptyMsg: " Press S to sync all sources + libraries (rich rendering deferred to AF-LIB-TUI-RICH).",
2231
2254
  renderRow: () => "",
2232
2255
  footer: " s sync all Tab switch q quit"
2233
2256
  }
@@ -2264,13 +2287,13 @@ function groupStatus(refs) {
2264
2287
  if (refs.length === 0) return pc5.dim("\xB7 ");
2265
2288
  if (refs.some((r) => state.pendingAdds.has(r))) return pc5.blue("+ ");
2266
2289
  if (refs.some((r) => state.pendingRemoves.has(r))) return pc5.red("- ");
2267
- const allDeployed = refs.every((r) => findAssetRow(r)?.deployed);
2268
- return allDeployed ? pc5.green("\u2713 ") : pc5.dim("\xB7 ");
2290
+ const allInstalled = refs.every((r) => findAssetRow(r)?.installed);
2291
+ return allInstalled ? pc5.green("\u2713 ") : pc5.dim("\xB7 ");
2269
2292
  }
2270
2293
  function renderHeaderLine(opts) {
2271
2294
  const indicator = opts.collapsed ? "\u25B6" : "\u25BC";
2272
2295
  const total = state.assetRows.filter(opts.match).length;
2273
- const installed = state.assetRows.filter((r) => opts.match(r) && r.deployed).length;
2296
+ const installed = state.assetRows.filter((r) => opts.match(r) && r.installed).length;
2274
2297
  const [add, remove] = pendingCountsFor(opts.match);
2275
2298
  let count = String(installed);
2276
2299
  if (add > 0) count += pc5.green(`+${add}`);
@@ -2281,22 +2304,22 @@ function renderHeaderLine(opts) {
2281
2304
  return opts.selected ? pc5.bgWhite(pc5.black(`${line} `.padEnd(state.cols))) : line;
2282
2305
  }
2283
2306
  function renderAssetRow(row, selected) {
2284
- if (row.type === "repo-header") {
2307
+ if (row.type === "source-header") {
2285
2308
  return renderHeaderLine({
2286
2309
  indent: " ",
2287
- collapsed: state.collapsedRepos.has(row.repo),
2288
- match: (r) => isAsset(r) && inRepo(r, row.repo),
2289
- refs: repoAssetRefs(state.assetRows, row.repo),
2290
- label: pc5.bold(pc5.cyan(row.repo)),
2310
+ collapsed: state.collapsedSources.has(row.source),
2311
+ match: (r) => isAsset(r) && inSource(r, row.source),
2312
+ refs: sourceAssetRefs(state.assetRows, row.source),
2313
+ label: pc5.bold(pc5.cyan(row.source)),
2291
2314
  selected
2292
2315
  });
2293
2316
  }
2294
2317
  if (row.type === "header") {
2295
2318
  return renderHeaderLine({
2296
2319
  indent: " ",
2297
- collapsed: state.collapsedDomains.has(`${row.repo}:${row.domain}`),
2298
- match: (r) => isAsset(r) && inDomain(r, row.repo, row.domain),
2299
- refs: domainAssetRefs(state.assetRows, row.repo, row.domain),
2320
+ collapsed: state.collapsedDomains.has(`${row.source}:${row.domain}`),
2321
+ match: (r) => isAsset(r) && inDomain(r, row.source, row.domain),
2322
+ refs: domainAssetRefs(state.assetRows, row.source, row.domain),
2300
2323
  label: pc5.bold(row.domain),
2301
2324
  selected
2302
2325
  });
@@ -2306,7 +2329,7 @@ function renderAssetRow(row, selected) {
2306
2329
  let status4;
2307
2330
  if (state.pendingAdds.has(ref)) status4 = pc5.blue("+ ");
2308
2331
  else if (state.pendingRemoves.has(ref)) status4 = pc5.red("- ");
2309
- else if (row.deployed) status4 = pc5.green("\u2713 ");
2332
+ else if (row.installed) status4 = pc5.green("\u2713 ");
2310
2333
  else status4 = pc5.dim("\xB7 ");
2311
2334
  const kind = kindColorPad(e.kind, 8);
2312
2335
  const name = e.name.padEnd(30);
@@ -2314,6 +2337,10 @@ function renderAssetRow(row, selected) {
2314
2337
  const line = ` ${status4} ${kind} ${name} ${pc5.dim(desc)}`;
2315
2338
  return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
2316
2339
  }
2340
+ function renderSourceRow(row, selected) {
2341
+ const line = ` ${S.cmd(row.name.padEnd(20))} ${pc5.dim(row.ownership.padEnd(12))} ${pc5.dim(`${row.assetCount} assets`)} ${pc5.dim(row.path)}`;
2342
+ return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
2343
+ }
2317
2344
  function renderLibraryRow(row, selected) {
2318
2345
  const mark = row.isDefault ? pc5.green("\u25B8") : " ";
2319
2346
  const line = `${mark} ${S.cmd(row.name.padEnd(16))} ${pc5.dim(row.backend.padEnd(7))} ${pc5.dim(row.ownership.padEnd(12))} ${pc5.dim(`${row.assetCount} assets`)}`;
@@ -2396,14 +2423,19 @@ async function applyChanges() {
2396
2423
  if (removed > 0) parts.push(pc5.red(`-${removed} removed`));
2397
2424
  if (parts.length) state.message = parts.join(" ");
2398
2425
  }
2399
- async function syncLibraries() {
2426
+ async function syncAll() {
2427
+ state.message = pc5.yellow(
2428
+ "Sync is not yet driven from the manage TUI. Run `skaile source sync` (sources) or `skaile library sync <name>` (git-backed libraries) from the shell."
2429
+ );
2430
+ }
2431
+ function sourceShellHint(action) {
2400
2432
  state.message = pc5.yellow(
2401
- "Library sync is not yet driven from the manage TUI. Run `skaile library sync <name>` from the shell."
2433
+ `${action} is a shell command. Run \`skaile source \u2026\` from the shell.`
2402
2434
  );
2403
2435
  }
2404
- function shellHint(action) {
2436
+ function libraryShellHint(action) {
2405
2437
  state.message = pc5.yellow(
2406
- `${action} is a shell command in the Libraries redesign. Run \`skaile library \u2026\` from the shell.`
2438
+ `${action} is a shell command. Run \`skaile library \u2026\` from the shell.`
2407
2439
  );
2408
2440
  }
2409
2441
  async function showInfo() {
@@ -2417,9 +2449,9 @@ async function showInfo() {
2417
2449
  console.log(` ${S.rule(50)}`);
2418
2450
  if (e.version) console.log(` version: ${e.version}`);
2419
2451
  if (e.description) console.log(` description: ${e.description}`);
2420
- if (e.repository) console.log(` repository: ${pc5.dim(e.repository)}`);
2421
- console.log(` source: ${pc5.dim(e.source)}`);
2422
- console.log(` deployed: ${row.deployed ? pc5.green("yes") : pc5.red("no")}`);
2452
+ if (e.repository) console.log(` source: ${pc5.dim(e.repository)}`);
2453
+ console.log(` manifest: ${pc5.dim(e.source)}`);
2454
+ console.log(` installed: ${row.installed ? pc5.green("yes") : pc5.red("no")}`);
2423
2455
  if (e.requires.length) {
2424
2456
  console.log(` requires:`);
2425
2457
  for (const d of e.requires) console.log(` ${kindColor(d.kind)}:${d.name}`);
@@ -2441,11 +2473,11 @@ async function showInfo() {
2441
2473
  function expandUnderCursor() {
2442
2474
  const row = state.visibleRows[state.cursor];
2443
2475
  if (!row) return;
2444
- if (row.type === "repo-header" && state.collapsedRepos.has(row.repo)) {
2445
- state.collapsedRepos.delete(row.repo);
2476
+ if (row.type === "source-header" && state.collapsedSources.has(row.source)) {
2477
+ state.collapsedSources.delete(row.source);
2446
2478
  rebuildVisible();
2447
2479
  } else if (row.type === "header") {
2448
- const dk = `${row.repo}:${row.domain}`;
2480
+ const dk = `${row.source}:${row.domain}`;
2449
2481
  if (state.collapsedDomains.has(dk)) {
2450
2482
  state.collapsedDomains.delete(dk);
2451
2483
  rebuildVisible();
@@ -2455,15 +2487,15 @@ function expandUnderCursor() {
2455
2487
  function collapseOrJumpUnderCursor() {
2456
2488
  const row = state.visibleRows[state.cursor];
2457
2489
  if (!row) return;
2458
- if (row.type === "repo-header") {
2459
- if (!state.collapsedRepos.has(row.repo)) {
2460
- state.collapsedRepos.add(row.repo);
2490
+ if (row.type === "source-header") {
2491
+ if (!state.collapsedSources.has(row.source)) {
2492
+ state.collapsedSources.add(row.source);
2461
2493
  rebuildVisible();
2462
2494
  }
2463
2495
  return;
2464
2496
  }
2465
2497
  if (row.type === "header") {
2466
- const dk = `${row.repo}:${row.domain}`;
2498
+ const dk = `${row.source}:${row.domain}`;
2467
2499
  if (!state.collapsedDomains.has(dk)) {
2468
2500
  state.collapsedDomains.add(dk);
2469
2501
  rebuildVisible();
@@ -2471,7 +2503,7 @@ function collapseOrJumpUnderCursor() {
2471
2503
  const idx2 = findLastIndex(
2472
2504
  state.visibleRows,
2473
2505
  state.cursor,
2474
- (r) => r.type === "repo-header"
2506
+ (r) => r.type === "source-header"
2475
2507
  );
2476
2508
  if (idx2 >= 0) state.cursor = idx2;
2477
2509
  }
@@ -2480,7 +2512,7 @@ function collapseOrJumpUnderCursor() {
2480
2512
  const idx = findLastIndex(
2481
2513
  state.visibleRows,
2482
2514
  state.cursor,
2483
- (r) => r.type === "header" || r.type === "repo-header"
2515
+ (r) => r.type === "header" || r.type === "source-header"
2484
2516
  );
2485
2517
  if (idx >= 0) state.cursor = idx;
2486
2518
  }
@@ -2491,6 +2523,7 @@ function findLastIndex(arr, endExclusive, pred) {
2491
2523
  return -1;
2492
2524
  }
2493
2525
  var TAB_ASSETS = (t) => t === "assets";
2526
+ var TAB_SOURCES = (t) => t === "sources";
2494
2527
  var TAB_LIBRARIES = (t) => t === "libraries";
2495
2528
  var KEYMAP = [
2496
2529
  // Quit (with pending check) — handled here, not via a modal subroutine, so
@@ -2513,7 +2546,7 @@ var KEYMAP = [
2513
2546
  // Collapse / expand — assets tab only
2514
2547
  { keys: ["\x1B[C"], when: TAB_ASSETS, run: expandUnderCursor },
2515
2548
  { keys: ["\x1B[D"], when: TAB_ASSETS, run: collapseOrJumpUnderCursor },
2516
- // + : assets → bulk-add or single-add toggle; repos → add repo
2549
+ // + : assets → bulk-add or single-add toggle
2517
2550
  {
2518
2551
  keys: ["+"],
2519
2552
  when: TAB_ASSETS,
@@ -2526,9 +2559,28 @@ var KEYMAP = [
2526
2559
  }
2527
2560
  }
2528
2561
  },
2529
- // Libraries tab: +/-/r/d/n/enter all map to shell hints in the minimal scaffold.
2530
- { keys: ["+", "n"], when: TAB_LIBRARIES, run: () => shellHint("Adding a library") },
2531
- // - : assets bulk-remove or single-remove toggle; repos remove repo
2562
+ // Sources tab: +/-/n/r/x map to shell hints in the minimal scaffold.
2563
+ { keys: ["+", "n", "a"], when: TAB_SOURCES, run: () => sourceShellHint("Adding a source") },
2564
+ { keys: ["-", "r", "x"], when: TAB_SOURCES, run: () => sourceShellHint("Removing a source") },
2565
+ { keys: ["\r", "\n"], when: TAB_SOURCES, run: () => sourceShellHint("Source actions") },
2566
+ // Libraries tab: +/-/n/r/x/d/enter map to shell hints in the minimal scaffold.
2567
+ {
2568
+ keys: ["+", "n", "a"],
2569
+ when: TAB_LIBRARIES,
2570
+ run: () => libraryShellHint("Adding a library")
2571
+ },
2572
+ {
2573
+ keys: ["-", "r", "x"],
2574
+ when: TAB_LIBRARIES,
2575
+ run: () => libraryShellHint("Removing a library")
2576
+ },
2577
+ {
2578
+ keys: ["d"],
2579
+ when: TAB_LIBRARIES,
2580
+ run: () => libraryShellHint("Setting the default library")
2581
+ },
2582
+ { keys: ["\r", "\n"], when: TAB_LIBRARIES, run: () => libraryShellHint("Library actions") },
2583
+ // - : assets → bulk-remove or single-remove toggle
2532
2584
  {
2533
2585
  keys: ["-"],
2534
2586
  when: TAB_ASSETS,
@@ -2541,8 +2593,6 @@ var KEYMAP = [
2541
2593
  }
2542
2594
  }
2543
2595
  },
2544
- { keys: ["-", "r", "x"], when: TAB_LIBRARIES, run: () => shellHint("Removing a library") },
2545
- { keys: ["d"], when: TAB_LIBRARIES, run: () => shellHint("Setting the default library") },
2546
2596
  // Space — auto-toggle (single asset or bulk header)
2547
2597
  {
2548
2598
  keys: [" "],
@@ -2556,14 +2606,12 @@ var KEYMAP = [
2556
2606
  }
2557
2607
  }
2558
2608
  },
2559
- // s — sync (any tab) — minimal scaffold delegates to shell.
2560
- { keys: ["s"], run: syncLibraries },
2561
- // a : assets → apply; libraries → shell hint
2609
+ // s — sync all (any tab) — minimal scaffold delegates to shell.
2610
+ { keys: ["s"], run: syncAll },
2611
+ // a : assets → apply
2562
2612
  { keys: ["a"], when: TAB_ASSETS, run: applyChanges },
2563
- { keys: ["a"], when: TAB_LIBRARIES, run: () => shellHint("Adding a library") },
2564
- // Enter — apply on assets tab; libraries → shell hint
2613
+ // Enter apply on assets tab
2565
2614
  { keys: ["\r", "\n"], when: TAB_ASSETS, run: applyChanges },
2566
- { keys: ["\r", "\n"], when: TAB_LIBRARIES, run: () => shellHint("Library actions") },
2567
2615
  // Info — assets only
2568
2616
  { keys: ["i"], when: TAB_ASSETS, run: showInfo }
2569
2617
  ];
@@ -2592,7 +2640,7 @@ async function handleExitConfirm(key) {
2592
2640
  async function run(projectDir) {
2593
2641
  am = new AssetManager({ projectDir });
2594
2642
  loadAssets();
2595
- await loadLibraries();
2643
+ await loadSourcesAndLibraries();
2596
2644
  hideCursor();
2597
2645
  process.stdin.setRawMode(true);
2598
2646
  process.stdin.resume();
@@ -2610,7 +2658,7 @@ async function run(projectDir) {
2610
2658
  clearScreen();
2611
2659
  }
2612
2660
  function makeManageCommand() {
2613
- return new Command("manage").description("Interactive TUI for managing libraries and assets").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
2661
+ return new Command("manage").description("Interactive TUI for managing assets, sources, and libraries").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
2614
2662
  await run(path15__default.resolve(opts.projectDir));
2615
2663
  });
2616
2664
  }
@@ -3588,7 +3636,7 @@ function makeInstallCommand() {
3588
3636
  const spinner6 = p5.spinner();
3589
3637
  spinner6.start(`Installing ${ref}`);
3590
3638
  try {
3591
- const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-XD7QYLMW.js');
3639
+ const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-T6RXQJTQ.js');
3592
3640
  const catalog = await openCatalogSource2({ projectDir: path15__default.resolve(opts.projectDir) });
3593
3641
  if (!supportsInstallManifest(catalog)) {
3594
3642
  throw new Error(