@skaile/workspaces 0.14.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 (90) hide show
  1. package/CHANGELOG.md +111 -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-OIFGKFZY.js → chunk-67TJEQJE.js} +2 -2
  8. package/dist/{chunk-OIFGKFZY.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-42OQF7UU.js → chunk-FNCYNUGS.js} +304 -227
  14. package/dist/chunk-FNCYNUGS.js.map +1 -0
  15. package/dist/{chunk-DN5476SV.js → chunk-HJV7MHG5.js} +17 -10
  16. package/dist/chunk-HJV7MHG5.js.map +1 -0
  17. package/dist/{chunk-VAJB2UJ5.js → chunk-IY4X7PZN.js} +13 -13
  18. package/dist/chunk-IY4X7PZN.js.map +1 -0
  19. package/dist/cli/index.js +807 -601
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/cli/src/commands/asset-cmd.d.ts +4 -1
  22. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  23. package/dist/cli/src/commands/library-cmd.d.ts +6 -4
  24. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  25. package/dist/cli/src/commands/manage.d.ts +31 -20
  26. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  27. package/dist/cli/src/commands/npx.d.ts.map +1 -1
  28. package/dist/cli/src/commands/project.d.ts +2 -2
  29. package/dist/cli/src/commands/source-manifest.d.ts +19 -0
  30. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -0
  31. package/dist/cli/src/commands/source.d.ts +6 -2
  32. package/dist/cli/src/commands/source.d.ts.map +1 -1
  33. package/dist/cli/src/commands/store.d.ts.map +1 -1
  34. package/dist/cli/src/open-library.d.ts +18 -18
  35. package/dist/cli/src/open-library.d.ts.map +1 -1
  36. package/dist/library/index.js +1 -1
  37. package/dist/library/src/config.d.ts +12 -3
  38. package/dist/library/src/config.d.ts.map +1 -1
  39. package/dist/library/src/index.d.ts +7 -8
  40. package/dist/library/src/index.d.ts.map +1 -1
  41. package/dist/library/src/library.d.ts +24 -77
  42. package/dist/library/src/library.d.ts.map +1 -1
  43. package/dist/library/src/local/db.d.ts +3 -2
  44. package/dist/library/src/local/db.d.ts.map +1 -1
  45. package/dist/library/src/local/{user-library-manager.d.ts → library-manager.d.ts} +15 -16
  46. package/dist/library/src/local/library-manager.d.ts.map +1 -0
  47. package/dist/library/src/local/library.d.ts +27 -23
  48. package/dist/library/src/local/library.d.ts.map +1 -1
  49. package/dist/library/src/local/local-catalog-source.d.ts +5 -5
  50. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  51. package/dist/library/src/local/sidecar-paths.d.ts +3 -3
  52. package/dist/library/src/local/store-paths.d.ts +42 -0
  53. package/dist/library/src/local/store-paths.d.ts.map +1 -0
  54. package/dist/library/src/preset/apply.d.ts +2 -2
  55. package/dist/library/src/preset/apply.d.ts.map +1 -1
  56. package/dist/library/src/preset/placeholders.d.ts +3 -3
  57. package/dist/library/src/preset/placeholders.d.ts.map +1 -1
  58. package/dist/library/src/preset/resolve-item.d.ts +3 -3
  59. package/dist/library/src/preset/resolve-item.d.ts.map +1 -1
  60. package/dist/library/src/sync/driver.d.ts +6 -6
  61. package/dist/library/src/sync/driver.d.ts.map +1 -1
  62. package/dist/library/src/sync/git-driver.d.ts +6 -6
  63. package/dist/library/src/sync/git-driver.d.ts.map +1 -1
  64. package/dist/library/src/sync/local-driver.d.ts +6 -6
  65. package/dist/library/src/sync/local-driver.d.ts.map +1 -1
  66. package/dist/library/src/user-library.d.ts +12 -17
  67. package/dist/library/src/user-library.d.ts.map +1 -1
  68. package/dist/{open-library-S6FK4N4S.js → open-library-T6RXQJTQ.js} +4 -4
  69. package/dist/{open-library-S6FK4N4S.js.map → open-library-T6RXQJTQ.js.map} +1 -1
  70. package/dist/runner/index.js +1 -1
  71. package/dist/runner/src/composition/resolve.d.ts +3 -3
  72. package/dist/runner/src/composition/resolve.d.ts.map +1 -1
  73. package/dist/sdk/asset-manager.js +2 -2
  74. package/dist/sdk/index.js +1 -1
  75. package/dist/sdk/runner.js +1 -1
  76. package/dist/tui/index.js +1 -1
  77. package/dist/types/src/install-manifest.d.ts +1 -1
  78. package/package.json +1 -1
  79. package/dist/chunk-42OQF7UU.js.map +0 -1
  80. package/dist/chunk-4GEVGRWB.js.map +0 -1
  81. package/dist/chunk-7R4WLTZW.js.map +0 -1
  82. package/dist/chunk-DN5476SV.js.map +0 -1
  83. package/dist/chunk-VAJB2UJ5.js.map +0 -1
  84. package/dist/cli/src/commands/library-status.d.ts +0 -19
  85. package/dist/cli/src/commands/library-status.d.ts.map +0 -1
  86. package/dist/cli/src/commands/source-sidecar.d.ts +0 -6
  87. package/dist/cli/src/commands/source-sidecar.d.ts.map +0 -1
  88. package/dist/library/src/local/user-library-manager.d.ts.map +0 -1
  89. package/dist/library/src/sync/store-driver.d.ts +0 -21
  90. package/dist/library/src/sync/store-driver.d.ts.map +0 -1
package/dist/cli/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { openCatalogSource, openLibrary, createFullRegistry, openUserLibraryManager } from '../chunk-VAJB2UJ5.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 } from '../chunk-42OQF7UU.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-OIFGKFZY.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-DN5476SV.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';
@@ -53,15 +53,15 @@ import '../chunk-LV2HPH3C.js';
53
53
  import '../chunk-NSBPE2FW.js';
54
54
  import * as fs10 from 'fs';
55
55
  import fs10__default, { readFileSync, existsSync, writeFileSync, statSync } from 'fs';
56
- import * as path16 from 'path';
57
- import path16__default, { resolve, join } from 'path';
56
+ import * as path15 from 'path';
57
+ import path15__default, { resolve, join } from 'path';
58
58
  import { fileURLToPath } from 'url';
59
59
  import { Help, Command, Option } from 'commander';
60
60
  import * as p5 from '@clack/prompts';
61
- import pc6 from 'picocolors';
61
+ import pc5 from 'picocolors';
62
62
  import * as readline from 'readline';
63
63
  import { createInterface } from 'readline';
64
- import { execSync } from 'child_process';
64
+ import { execSync, spawnSync } from 'child_process';
65
65
  import { homedir } from 'os';
66
66
  import fs5 from 'fs/promises';
67
67
  import { parse as parse$1, stringify } from 'smol-toml';
@@ -80,7 +80,7 @@ function makeAssetCommand() {
80
80
  logErr(`Source path does not exist: ${srcPath}`);
81
81
  process.exit(1);
82
82
  }
83
- const { manager, close } = await openUserLibraryManager();
83
+ const { manager, close } = await openLibraryManager();
84
84
  try {
85
85
  let target;
86
86
  if (opts.to) {
@@ -103,10 +103,10 @@ function makeAssetCommand() {
103
103
  );
104
104
  process.exit(1);
105
105
  }
106
- const basename2 = path16.basename(srcPath);
107
- const destDir = target.structure === "domain" && opts.domain ? path16.join(target.path, opts.domain) : target.path;
106
+ const basename2 = path15.basename(srcPath);
107
+ const destDir = target.structure === "domain" && opts.domain ? path15.join(target.path, opts.domain) : target.path;
108
108
  fs10.mkdirSync(destDir, { recursive: true });
109
- const destPath = path16.join(destDir, basename2);
109
+ const destPath = path15.join(destDir, basename2);
110
110
  if (fs10.existsSync(destPath)) {
111
111
  logErr(`Destination already exists: ${destPath}`);
112
112
  process.exit(1);
@@ -119,13 +119,13 @@ function makeAssetCommand() {
119
119
  fs10.renameSync(srcPath, destPath);
120
120
  break;
121
121
  case "link":
122
- fs10.symlinkSync(path16.resolve(srcPath), destPath);
122
+ fs10.symlinkSync(path15.resolve(srcPath), destPath);
123
123
  break;
124
124
  }
125
125
  if (target.backend === "git" && opts.commit) {
126
- const { spawnSync } = await import('child_process');
127
- spawnSync("git", ["add", "-A"], { cwd: target.path, stdio: "ignore" });
128
- spawnSync("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
126
+ const { spawnSync: spawnSync2 } = await import('child_process');
127
+ spawnSync2("git", ["add", "-A"], { cwd: target.path, stdio: "ignore" });
128
+ spawnSync2("git", ["commit", "-m", `skaile: migrate ${basename2}`], {
129
129
  cwd: target.path,
130
130
  stdio: "ignore"
131
131
  });
@@ -149,7 +149,7 @@ function makeAssetCommand() {
149
149
  logErr(`Invalid --mode "${opts.mode}". Expected: copy | link.`);
150
150
  process.exit(1);
151
151
  }
152
- const { manager, library, close } = await openUserLibraryManager();
152
+ const { manager, library, close } = await openLibraryManager();
153
153
  try {
154
154
  const def = await library.getAssetDef(ref);
155
155
  if (!def) {
@@ -157,7 +157,7 @@ function makeAssetCommand() {
157
157
  process.exit(1);
158
158
  }
159
159
  const target = opts.target ?? process.cwd();
160
- const lib = def.sourceId ? (await manager.listLibraries()).find((l) => l.id === def.sourceId) : void 0;
160
+ const lib = def.libraryId ? (await manager.listLibraries()).find((l) => l.id === def.libraryId) : void 0;
161
161
  if (!lib) {
162
162
  logErr(`Asset has no associated library; install path unknown.`);
163
163
  process.exit(1);
@@ -167,17 +167,17 @@ function makeAssetCommand() {
167
167
  }
168
168
  const manifestPath = def.manifest.path;
169
169
  const candidateSubpath = typeof manifestPath === "string" && manifestPath.length > 0 ? manifestPath : def.name;
170
- const srcPath = path16.join(lib.path, candidateSubpath);
170
+ const srcPath = path15.join(lib.path, candidateSubpath);
171
171
  if (!fs10.existsSync(srcPath)) {
172
172
  logErr(`Asset path not found: ${srcPath}`);
173
173
  process.exit(1);
174
174
  }
175
- const destPath = path16.join(target, candidateSubpath);
176
- fs10.mkdirSync(path16.dirname(destPath), { recursive: true });
175
+ const destPath = path15.join(target, candidateSubpath);
176
+ fs10.mkdirSync(path15.dirname(destPath), { recursive: true });
177
177
  if (opts.mode === "copy") {
178
178
  fs10.cpSync(srcPath, destPath, { recursive: true });
179
179
  } else {
180
- fs10.symlinkSync(path16.resolve(srcPath), destPath);
180
+ fs10.symlinkSync(path15.resolve(srcPath), destPath);
181
181
  }
182
182
  logOk(`Installed ${ref} \u2192 ${destPath} (${opts.mode})`);
183
183
  } finally {
@@ -186,12 +186,12 @@ function makeAssetCommand() {
186
186
  }
187
187
  );
188
188
  cmd.command("list").description("List asset definitions across libraries").option("--library <name>", "Filter by library").option("--domain <name>", "Filter by domain").option("--kind <kind>", "Filter by kind").option("--json", "Output as JSON").action(async (opts) => {
189
- const { manager, library, close } = await openUserLibraryManager();
189
+ const { manager, library, close } = await openLibraryManager();
190
190
  try {
191
191
  let defs = await library.listAssetDefs(opts.kind ? { kind: opts.kind } : void 0);
192
192
  if (opts.library) {
193
193
  const lib = await manager.requireLibrary(opts.library);
194
- defs = defs.filter((d) => d.sourceId === lib.id);
194
+ defs = defs.filter((d) => d.libraryId === lib.id);
195
195
  }
196
196
  if (opts.json) return console.log(JSON.stringify(defs, null, 2));
197
197
  if (defs.length === 0) {
@@ -209,7 +209,7 @@ function makeAssetCommand() {
209
209
  }
210
210
  });
211
211
  cmd.command("show <ref>").description("Show details for an asset by canonical ref").action(async (ref) => {
212
- const { library, close } = await openUserLibraryManager();
212
+ const { library, close } = await openLibraryManager();
213
213
  try {
214
214
  const def = await library.getAssetDef(ref);
215
215
  if (!def) {
@@ -221,10 +221,6 @@ function makeAssetCommand() {
221
221
  close();
222
222
  }
223
223
  });
224
- cmd.command("publish <ref>").description("Publish to the store (STUB)").option("--scope <scope>", "team | public", "team").action(async (_ref, _opts) => {
225
- logErr("`skaile asset publish` is not yet wired (store write path stub).");
226
- process.exit(2);
227
- });
228
224
  return cmd;
229
225
  }
230
226
  var VALID_STRATEGIES = ["keychain", "passphrase", "machine"];
@@ -275,7 +271,7 @@ function makeSearchCommand() {
275
271
  const showLocal = !opts.store;
276
272
  const showStore = !opts.local;
277
273
  if (showLocal) {
278
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
274
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
279
275
  const entries = am2.search(query, kind);
280
276
  if (entries.length === 0) {
281
277
  if (!showStore) {
@@ -341,7 +337,7 @@ function makeSearchCommand() {
341
337
  function makeAddCommand() {
342
338
  return new Command("add").description("Add to skaile.yaml + deploy").argument("<ref>", "Asset reference (kind:name[@repo])").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Deploy to global dir (~/.claude)").option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
343
339
  const am2 = new AssetManager({
344
- projectDir: path16__default.resolve(opts.projectDir),
340
+ projectDir: path15__default.resolve(opts.projectDir),
345
341
  global: opts.global,
346
342
  driverTarget: opts.target
347
343
  });
@@ -362,7 +358,7 @@ function makeAddCommand() {
362
358
  function makeRemoveCommand() {
363
359
  return new Command("remove").description("Remove from skaile.yaml + undeploy").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).option("--global", "Remove from global dir").option("--target <agent>", "Driver target", "claude-code").action((ref, opts) => {
364
360
  const am2 = new AssetManager({
365
- projectDir: path16__default.resolve(opts.projectDir),
361
+ projectDir: path15__default.resolve(opts.projectDir),
366
362
  global: opts.global,
367
363
  driverTarget: opts.target
368
364
  });
@@ -376,7 +372,7 @@ function makeListCommand() {
376
372
  new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
377
373
  ).action((kind, opts) => {
378
374
  const am2 = new AssetManager({
379
- projectDir: path16__default.resolve(opts.projectDir),
375
+ projectDir: path15__default.resolve(opts.projectDir),
380
376
  global: opts.global,
381
377
  driverTarget: opts.target
382
378
  });
@@ -400,7 +396,7 @@ function makeListCommand() {
400
396
  }
401
397
  function makeInfoCommand() {
402
398
  return new Command("info").description("Show asset metadata, deps, deploy status").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
403
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
399
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
404
400
  const entry = am2.info(ref);
405
401
  if (!entry) {
406
402
  logErr(
@@ -433,9 +429,9 @@ function makeCreateCommand() {
433
429
  new Option("-k, --kind <kind>", "Asset kind").default("skill").choices([...ASSET_KINDS])
434
430
  ).option("-d, --dir <dir>", "Target directory (default: cwd)").action((name, opts) => {
435
431
  const am2 = new AssetManager({ projectDir: process.cwd() });
436
- const destDir = opts.dir ? path16__default.resolve(opts.dir) : process.cwd();
432
+ const destDir = opts.dir ? path15__default.resolve(opts.dir) : process.cwd();
437
433
  const result = am2.create(name, opts.kind, destDir);
438
- if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${pc6.dim(result.path)}`);
434
+ if (result.ok) logOk(`Created ${kindColor(opts.kind)}: ${pc5.dim(result.path)}`);
439
435
  else {
440
436
  logErr(result.path);
441
437
  process.exit(1);
@@ -444,7 +440,7 @@ function makeCreateCommand() {
444
440
  }
445
441
  function makeDoctorCommand() {
446
442
  return new Command("doctor").description("Scan for missing dependency chains").argument("[name]", "Check a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((name, opts) => {
447
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
443
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
448
444
  const issues = am2.doctor();
449
445
  if (issues.length === 0) {
450
446
  logOk("No missing dependencies.");
@@ -470,11 +466,11 @@ function makeCatalogCommand() {
470
466
  const catalog = new Command("catalog").description("Catalog source health and configuration");
471
467
  catalog.command("test").description("Probe the configured catalog source and report status").option("--project-dir <path>", "Project directory (for project-level config overlay)").option("--url <url>", "Override the catalog URL for this probe").option("--force", "Probe the network even in air-gapped mode (cache_ttl: 0)").action(async (opts) => {
472
468
  const { resolveConfig, isLocalCatalogUrl, trpcGetUrl } = await import('../library/index.js');
473
- const projectDir = opts.projectDir ? path16__default.resolve(opts.projectDir) : void 0;
469
+ const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : void 0;
474
470
  const cfg = resolveConfig({ projectDir });
475
471
  const baseUrl = opts.url ?? cfg.catalog.url;
476
472
  if (isLocalCatalogUrl(baseUrl)) {
477
- const { resolveCatalogSource } = await import('../open-library-S6FK4N4S.js');
473
+ const { resolveCatalogSource } = await import('../open-library-T6RXQJTQ.js');
478
474
  let resolved;
479
475
  try {
480
476
  resolved = await resolveCatalogSource({ projectDir: opts.projectDir });
@@ -563,7 +559,7 @@ function makeCatalogCommand() {
563
559
  });
564
560
  catalog.command("info").description("Print the resolved catalog configuration (url, framing, cacheTtlMs)").option("--project-dir <path>", "Project directory (for project-level config overlay)").action(async (opts) => {
565
561
  const { resolveConfig } = await import('../library/index.js');
566
- const projectDir = opts.projectDir ? path16__default.resolve(opts.projectDir) : void 0;
562
+ const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : void 0;
567
563
  const cfg = resolveConfig({ projectDir });
568
564
  console.log(`url: ${cfg.catalog.url}`);
569
565
  console.log(`framing: ${cfg.catalog.framing}`);
@@ -620,7 +616,7 @@ function findSkills(domain) {
620
616
  if (!fs10__default.existsSync(AI_RESOURCES)) return skills;
621
617
  const domains = fs10__default.readdirSync(AI_RESOURCES, { withFileTypes: true }).filter((d) => d.isDirectory()).filter((d) => true);
622
618
  for (const d of domains) {
623
- const skillsDir = path16__default.join(AI_RESOURCES, d.name, "skills");
619
+ const skillsDir = path15__default.join(AI_RESOURCES, d.name, "skills");
624
620
  if (!fs10__default.existsSync(skillsDir)) continue;
625
621
  walkSkills(skillsDir, d.name, skills);
626
622
  }
@@ -628,9 +624,9 @@ function findSkills(domain) {
628
624
  }
629
625
  function walkSkills(dir, domain, out) {
630
626
  for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
631
- const full = path16__default.join(dir, entry.name);
627
+ const full = path15__default.join(dir, entry.name);
632
628
  if (entry.isDirectory()) {
633
- const skillMd = path16__default.join(full, "SKILL.md");
629
+ const skillMd = path15__default.join(full, "SKILL.md");
634
630
  if (fs10__default.existsSync(skillMd)) {
635
631
  out.push({ name: entry.name, path: full, skillPath: skillMd, domain });
636
632
  } else {
@@ -656,7 +652,7 @@ function resolveFlowIds() {
656
652
  }
657
653
  }
658
654
  function resolveSessionIds(projectDir) {
659
- const sessionsDir = path16__default.join(projectDir, ".skaile", "sessions");
655
+ const sessionsDir = path15__default.join(projectDir, ".skaile", "sessions");
660
656
  if (!fs10__default.existsSync(sessionsDir)) return [];
661
657
  try {
662
658
  return fs10__default.readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -".json".length));
@@ -717,7 +713,7 @@ var API_KEY_PREFIX = "apiKey.";
717
713
  function makeConfigCommand() {
718
714
  const cmd = new Command("config").description("Manage personal config (.skaile/settings.json)");
719
715
  cmd.command("show").description("Show effective config with sources").option("--project-dir <path>", "Project directory").action(async (opts) => {
720
- const projectDir = opts.projectDir ? path16__default.resolve(opts.projectDir) : process.cwd();
716
+ const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
721
717
  const config = await resolveSettings(projectDir);
722
718
  const wsDefaults = {};
723
719
  try {
@@ -774,13 +770,13 @@ function makeConfigCommand() {
774
770
  console.log();
775
771
  });
776
772
  cmd.command("get <key>").description("Get an effective config value").option("--project-dir <path>", "Project directory").action(async (key, opts) => {
777
- const projectDir = opts.projectDir ? path16__default.resolve(opts.projectDir) : process.cwd();
773
+ const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
778
774
  const config = await resolveSettings(projectDir);
779
775
  const value = config[key];
780
776
  console.log(value ?? S.dim("(not set)"));
781
777
  });
782
778
  cmd.command("set <key> <value>").description("Set a personal config value (driver, model, provider, apiKey.<provider>)").option("--project-dir <path>", "Project directory").option("--global", "Write to ~/.skaile/settings.json instead of project-local").action(async (key, value, opts) => {
783
- const projectDir = opts.projectDir ? path16__default.resolve(opts.projectDir) : process.cwd();
779
+ const projectDir = opts.projectDir ? path15__default.resolve(opts.projectDir) : process.cwd();
784
780
  const isApiKey = key.startsWith(API_KEY_PREFIX);
785
781
  if (!PERSONAL_KEYS.has(key) && !isApiKey) {
786
782
  logErr(
@@ -796,11 +792,11 @@ function makeConfigCommand() {
796
792
  const provider = key.slice(API_KEY_PREFIX.length);
797
793
  existing.apiKeys = { ...existing.apiKeys, [provider]: value };
798
794
  await saveSettings(existing, filePath);
799
- logOk(`Set ${pc6.bold(`apiKeys.${provider}`)} = ****${value.slice(-4)}`);
795
+ logOk(`Set ${pc5.bold(`apiKeys.${provider}`)} = ****${value.slice(-4)}`);
800
796
  } else {
801
797
  existing[key] = value;
802
798
  await saveSettings(existing, filePath);
803
- logOk(`Set ${pc6.bold(key)} = ${value}`);
799
+ logOk(`Set ${pc5.bold(key)} = ${value}`);
804
800
  }
805
801
  console.log(S.dim(` \u2192 ${filePath}`));
806
802
  });
@@ -897,11 +893,11 @@ function makeConnectCommand() {
897
893
  process.exitCode = 1;
898
894
  return;
899
895
  }
900
- await new Promise((resolve3) => {
896
+ await new Promise((resolve4) => {
901
897
  client.onMessage((event) => {
902
898
  console.log(formatEvent(event));
903
899
  if (event.type === "finished" || event.type === "debug_result") {
904
- resolve3();
900
+ resolve4();
905
901
  }
906
902
  });
907
903
  client.send(parsed);
@@ -945,12 +941,12 @@ function makeConnectCommand() {
945
941
  client.send(cmd);
946
942
  rl.prompt();
947
943
  });
948
- await new Promise((resolve3) => {
949
- rl.on("close", resolve3);
944
+ await new Promise((resolve4) => {
945
+ rl.on("close", resolve4);
950
946
  client.onDisconnect(() => {
951
947
  logErr("Server disconnected");
952
948
  rl.close();
953
- resolve3();
949
+ resolve4();
954
950
  });
955
951
  });
956
952
  await client.disconnect();
@@ -1016,15 +1012,15 @@ function parseOpArgs(args) {
1016
1012
  async function promptText(label, defaultVal) {
1017
1013
  const rl = createInterface({ input: process.stdin, output: process.stdout });
1018
1014
  const hint = defaultVal ? ` [${defaultVal}]` : "";
1019
- return new Promise((resolve3) => {
1015
+ return new Promise((resolve4) => {
1020
1016
  rl.question(` ${label}${hint}: `, (answer) => {
1021
1017
  rl.close();
1022
- resolve3(answer.trim() || defaultVal || "");
1018
+ resolve4(answer.trim() || defaultVal || "");
1023
1019
  });
1024
1020
  });
1025
1021
  }
1026
1022
  async function promptSecret(label) {
1027
- return new Promise((resolve3) => {
1023
+ return new Promise((resolve4) => {
1028
1024
  process.stdout.write(` ${label} (hidden): `);
1029
1025
  const stdin = process.stdin;
1030
1026
  stdin.setRawMode?.(true);
@@ -1037,7 +1033,7 @@ async function promptSecret(label) {
1037
1033
  stdin.pause();
1038
1034
  stdin.removeListener("data", onData);
1039
1035
  process.stdout.write("\n");
1040
- resolve3(value);
1036
+ resolve4(value);
1041
1037
  } else if (char === "") {
1042
1038
  process.exit(1);
1043
1039
  } else if (char === "\x7F") {
@@ -1087,8 +1083,8 @@ function makeConnectorCommand() {
1087
1083
  async (driver, opts) => {
1088
1084
  const { installNpmPackages } = await import('../connectors/index.js');
1089
1085
  const { scanDirectory, resolveBaseAssetsRoot, WorkspaceYamlEditor } = await import('../core/index.js');
1090
- const projectDir = path16__default.resolve(opts.projectDir);
1091
- const yamlPath = path16__default.join(projectDir, "skaile.yaml");
1086
+ const projectDir = path15__default.resolve(opts.projectDir);
1087
+ const yamlPath = path15__default.join(projectDir, "skaile.yaml");
1092
1088
  if (!existsSync(yamlPath)) {
1093
1089
  logErr("No skaile.yaml found in current directory. Run 'skaile init' first.");
1094
1090
  process.exit(1);
@@ -1151,8 +1147,8 @@ ${installResult.output}`);
1151
1147
  );
1152
1148
  cmd.command("remove <id>").option("--project-dir <path>", "Workspace directory", process.cwd()).description("Remove a connector from skaile.yaml by its instance ID").action(async (id, opts) => {
1153
1149
  const { WorkspaceYamlEditor } = await import('../core/index.js');
1154
- const projectDir = path16__default.resolve(opts.projectDir);
1155
- const yamlPath = path16__default.join(projectDir, "skaile.yaml");
1150
+ const projectDir = path15__default.resolve(opts.projectDir);
1151
+ const yamlPath = path15__default.join(projectDir, "skaile.yaml");
1156
1152
  if (!existsSync(yamlPath)) {
1157
1153
  logErr("No skaile.yaml found in current directory.");
1158
1154
  process.exit(1);
@@ -1169,7 +1165,7 @@ ${installResult.output}`);
1169
1165
  cmd.command("status [id]").option("--project-dir <path>", "Workspace directory", process.cwd()).description("Connect and report health status for one or all connectors").action(async (id, opts) => {
1170
1166
  const res = await import('../connectors/index.js');
1171
1167
  res.registerBuiltinConnectors();
1172
- const projectDir = path16__default.resolve(opts.projectDir);
1168
+ const projectDir = path15__default.resolve(opts.projectDir);
1173
1169
  const declarations = res.loadConnectorDeclarations(projectDir);
1174
1170
  if (declarations.length === 0) {
1175
1171
  console.log("No connectors configured in skaile.yaml.");
@@ -1193,7 +1189,7 @@ ${installResult.output}`);
1193
1189
  await manager.disconnectAll();
1194
1190
  });
1195
1191
  cmd.command("list").description("List all configured connectors").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (opts) => {
1196
- const projectDir = path16__default.resolve(opts.projectDir);
1192
+ const projectDir = path15__default.resolve(opts.projectDir);
1197
1193
  const manager = await connectConnectors(projectDir);
1198
1194
  try {
1199
1195
  console.log(JSON.stringify(manager.listConnectors(), null, 2));
@@ -1202,7 +1198,7 @@ ${installResult.output}`);
1202
1198
  }
1203
1199
  });
1204
1200
  cmd.command("sync [id]").description("Re-sync a filesystem-face connector or all of them (git pull, S3 refresh, etc.)").option("--all", "Sync all connectors").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, opts) => {
1205
- const projectDir = path16__default.resolve(opts.projectDir);
1201
+ const projectDir = path15__default.resolve(opts.projectDir);
1206
1202
  const manager = await connectConnectors(projectDir);
1207
1203
  try {
1208
1204
  if (opts.all) {
@@ -1226,7 +1222,7 @@ ${installResult.output}`);
1226
1222
  }
1227
1223
  });
1228
1224
  cmd.command("ops <id>").description("List available operations for a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, opts) => {
1229
- const projectDir = path16__default.resolve(opts.projectDir);
1225
+ const projectDir = path15__default.resolve(opts.projectDir);
1230
1226
  const manager = await connectConnectors(projectDir);
1231
1227
  try {
1232
1228
  if (!manager.has(id)) {
@@ -1241,7 +1237,7 @@ ${installResult.output}`);
1241
1237
  }
1242
1238
  });
1243
1239
  cmd.command("read <id> <resource-path>").description("Read content from a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, opts) => {
1244
- const projectDir = path16__default.resolve(opts.projectDir);
1240
+ const projectDir = path15__default.resolve(opts.projectDir);
1245
1241
  const manager = await connectConnectors(projectDir);
1246
1242
  try {
1247
1243
  const content = await manager.read(id, resourcePath);
@@ -1251,7 +1247,7 @@ ${installResult.output}`);
1251
1247
  }
1252
1248
  });
1253
1249
  cmd.command("write <id> <resource-path> <content>").description("Write content to a connector at a path").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, content, opts) => {
1254
- const projectDir = path16__default.resolve(opts.projectDir);
1250
+ const projectDir = path15__default.resolve(opts.projectDir);
1255
1251
  const manager = await connectConnectors(projectDir);
1256
1252
  try {
1257
1253
  await manager.write(id, resourcePath, { data: content });
@@ -1261,7 +1257,7 @@ ${installResult.output}`);
1261
1257
  }
1262
1258
  });
1263
1259
  cmd.command("entries <id> [resource-path]").description("List entries in a connector (files, keys, rows, etc)").option("--project-dir <path>", "Workspace directory", process.cwd()).option("--recursive", "Include nested entries").option("--limit <n>", "Maximum entries to return", parseInt).action(async (id, resourcePath, opts) => {
1264
- const projectDir = path16__default.resolve(opts.projectDir);
1260
+ const projectDir = path15__default.resolve(opts.projectDir);
1265
1261
  const manager = await connectConnectors(projectDir);
1266
1262
  try {
1267
1263
  const entries = await manager.list(id, resourcePath, {
@@ -1274,7 +1270,7 @@ ${installResult.output}`);
1274
1270
  }
1275
1271
  });
1276
1272
  cmd.command("search <id> <query>").description("Search within a connector for matching content").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, query, opts) => {
1277
- const projectDir = path16__default.resolve(opts.projectDir);
1273
+ const projectDir = path15__default.resolve(opts.projectDir);
1278
1274
  const manager = await connectConnectors(projectDir);
1279
1275
  try {
1280
1276
  const results = await manager.search(id, query);
@@ -1284,7 +1280,7 @@ ${installResult.output}`);
1284
1280
  }
1285
1281
  });
1286
1282
  cmd.command("delete <id> <resource-path>").description("Delete an entry from a connector").option("--project-dir <path>", "Workspace directory", process.cwd()).action(async (id, resourcePath, opts) => {
1287
- const projectDir = path16__default.resolve(opts.projectDir);
1283
+ const projectDir = path15__default.resolve(opts.projectDir);
1288
1284
  const manager = await connectConnectors(projectDir);
1289
1285
  try {
1290
1286
  const ok = await manager.delete(id, resourcePath);
@@ -1294,7 +1290,7 @@ ${installResult.output}`);
1294
1290
  }
1295
1291
  });
1296
1292
  cmd.command("run <id> <op> [args...]").description("Run a custom adapter operation (e.g. git log, sqlite query)").option("--project-dir <path>", "Workspace directory", process.cwd()).allowUnknownOption().action(async (id, op, args, opts) => {
1297
- const projectDir = path16__default.resolve(opts.projectDir);
1293
+ const projectDir = path15__default.resolve(opts.projectDir);
1298
1294
  const manager = await connectConnectors(projectDir);
1299
1295
  try {
1300
1296
  if (!manager.has(id)) {
@@ -1329,17 +1325,17 @@ async function runDebugQuery(query, parentOpts, args) {
1329
1325
  process.exitCode = 1;
1330
1326
  return;
1331
1327
  }
1332
- await new Promise((resolve3) => {
1328
+ await new Promise((resolve4) => {
1333
1329
  const timeout = setTimeout(() => {
1334
1330
  logErr("Timeout: no debug_result received within 5s");
1335
1331
  process.exitCode = 1;
1336
- resolve3();
1332
+ resolve4();
1337
1333
  }, 5e3);
1338
1334
  client.onMessage((event) => {
1339
1335
  if (event.type !== "debug_result") return;
1340
1336
  clearTimeout(timeout);
1341
1337
  printDebugResult(query, event.data);
1342
- resolve3();
1338
+ resolve4();
1343
1339
  });
1344
1340
  client.send({ type: "debug", query, args });
1345
1341
  });
@@ -1385,7 +1381,7 @@ function makeDebugCommand() {
1385
1381
  }
1386
1382
  function makeDiffCommand() {
1387
1383
  return new Command("diff").description("Show changes between deployed and source versions").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
1388
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
1384
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
1389
1385
  const result = am2.diff(ref);
1390
1386
  if (result === null) {
1391
1387
  logInfo("No differences (or asset not found).");
@@ -1438,7 +1434,7 @@ function makeFlowCommand() {
1438
1434
  function makeHistoryCommand() {
1439
1435
  const cmd = new Command("history").description("Show recent add/remove/update actions");
1440
1436
  cmd.argument("[limit]", "Number of entries to show", "20").option("--project-dir <path>", "Project directory", process.cwd()).action((limitStr, opts) => {
1441
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
1437
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
1442
1438
  const limit = parseInt(limitStr, 10) || 20;
1443
1439
  const entries = am2.history(limit);
1444
1440
  if (entries.length === 0) {
@@ -1458,18 +1454,21 @@ function makeHistoryCommand() {
1458
1454
  console.log();
1459
1455
  });
1460
1456
  cmd.command("clear").description("Clear action history").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
1461
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
1457
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
1462
1458
  am2.clearHistory();
1463
1459
  logOk("History cleared.");
1464
1460
  });
1465
1461
  return cmd;
1466
1462
  }
1463
+ var NOT_WIRED_MSG_PUBLISH = "`skaile library publish` is scaffolded but not yet wired. Server endpoint `POST /sources/<id>/manifest` lands in a follow-up PR.";
1464
+ function notWired(verb, msg) {
1465
+ logErr(`${msg} (verb: library ${verb})`);
1466
+ process.exit(2);
1467
+ }
1467
1468
  function makeLibraryCommand() {
1468
- const cmd = new Command("library").description(
1469
- "Manage user-facing libraries (local / git / store)"
1470
- );
1469
+ const cmd = new Command("library").description("Manage user authoring libraries (local / git)");
1471
1470
  cmd.command("list").description("List all registered libraries").option("--json", "Output as JSON").action(async (opts) => {
1472
- const { manager, close } = await openUserLibraryManager();
1471
+ const { manager, close } = await openLibraryManager();
1473
1472
  try {
1474
1473
  const ls = await manager.listLibraries();
1475
1474
  if (opts.json) return console.log(JSON.stringify(ls, null, 2));
@@ -1481,9 +1480,9 @@ function makeLibraryCommand() {
1481
1480
  console.log(S.heading(" Libraries"));
1482
1481
  console.log(` ${S.rule(80)}`);
1483
1482
  for (const l of ls) {
1484
- const def = l.isDefault ? pc6.green("\u25B8 ") : " ";
1483
+ const def = l.isDefault ? pc5.green("\u25B8 ") : " ";
1485
1484
  console.log(
1486
- `${def}${S.cmd(l.name.padEnd(16))} ${pc6.dim(l.backend.padEnd(7))} ${pc6.dim(l.ownership.padEnd(12))} ${pc6.dim(l.path)}`
1485
+ `${def}${S.cmd(l.name.padEnd(16))} ${pc5.dim(l.backend.padEnd(7))} ${pc5.dim(l.ownership.padEnd(12))} ${pc5.dim(l.path)}`
1487
1486
  );
1488
1487
  }
1489
1488
  console.log(`
@@ -1493,41 +1492,15 @@ function makeLibraryCommand() {
1493
1492
  close();
1494
1493
  }
1495
1494
  });
1496
- cmd.command("status [name]").description("Show sync status for one or all libraries").option("--json", "Output as JSON").action(async (name, opts) => {
1497
- const { manager, close } = await openUserLibraryManager();
1498
- try {
1499
- const targets = name ? [await manager.requireLibrary(name)] : await manager.listLibraries();
1500
- const results = await Promise.all(
1501
- targets.map(async (l) => ({
1502
- library: l.name,
1503
- status: await manager.driverFor(l.backend).status(l)
1504
- }))
1505
- );
1506
- if (opts.json) return console.log(JSON.stringify(results, null, 2));
1507
- for (const { library, status: status4 } of results) {
1508
- console.log(`
1509
- ${S.heading(library)}`);
1510
- console.log(` reachable: ${status4.reachable ? S.ok("yes") : S.err("no")}`);
1511
- if (status4.remoteChanges) {
1512
- console.log(
1513
- ` behind/ahead: ${status4.remoteChanges.behind}/${status4.remoteChanges.ahead}`
1514
- );
1515
- }
1516
- const lc = status4.localChanges;
1517
- if (lc.added.length + lc.modified.length + lc.deleted.length > 0) {
1518
- console.log(
1519
- ` local changes: +${lc.added.length} ~${lc.modified.length} -${lc.deleted.length}`
1520
- );
1521
- }
1522
- for (const note of status4.notes) console.log(` ${pc6.dim("note:")} ${note}`);
1523
- }
1524
- console.log();
1525
- } finally {
1526
- close();
1495
+ cmd.command("status [name]").description("Show overall Library health or per-library sync status").option("--project-dir <path>", "Project directory", process.cwd()).option("--json", "Output as JSON").action(async (name, opts) => {
1496
+ if (name) {
1497
+ await printPerLibraryStatus(name, opts.json ?? false);
1498
+ return;
1527
1499
  }
1500
+ await printOverallStatus(opts.projectDir, opts.json ?? false);
1528
1501
  });
1529
1502
  cmd.command("show <name>").description("Detailed info about a library").action(async (name) => {
1530
- const { manager, close } = await openUserLibraryManager();
1503
+ const { manager, close } = await openLibraryManager();
1531
1504
  try {
1532
1505
  const l = await manager.requireLibrary(name);
1533
1506
  console.log();
@@ -1546,12 +1519,12 @@ function makeLibraryCommand() {
1546
1519
  close();
1547
1520
  }
1548
1521
  });
1549
- cmd.command("init <name>").description("Create a new local library at ~/.skaile/libraries/<name>").option("--git <url>", "Initialize as a git library tracking <url>").option("--store <url>", "Initialize as a store library at <url>").option("--owner", "Mark as owner (default for local; probe-overrides for git)").option("--contributor", "Mark as contributor").option("--reader", "Mark as reader").action(
1522
+ cmd.command("init <name>").description("Create a new local library at ~/.skaile/libraries/<name>").option("--git <url>", "Initialize as a git library tracking <url>").option("--owner", "Mark as owner (default for local)").option("--contributor", "Mark as contributor").option("--reader", "Mark as reader").action(
1550
1523
  async (name, opts) => {
1551
1524
  const libDir = resolveLibraryDir();
1552
- const libPath = path16.join(libDir, name);
1525
+ const libPath = path15.join(libDir, name);
1553
1526
  const ownership = opts.contributor ? "contributor" : opts.reader ? "reader" : "owner";
1554
- const { manager, close } = await openUserLibraryManager();
1527
+ const { manager, close } = await openLibraryManager();
1555
1528
  try {
1556
1529
  if (opts.git) {
1557
1530
  fs10.mkdirSync(libPath, { recursive: true });
@@ -1562,14 +1535,6 @@ function makeLibraryCommand() {
1562
1535
  backendConfig: { url: opts.git, branch: "main", authHint: "ssh" },
1563
1536
  ownership
1564
1537
  });
1565
- } else if (opts.store) {
1566
- await manager.addLibrary({
1567
- name,
1568
- path: libPath,
1569
- backend: "store",
1570
- backendConfig: { url: opts.store, publisher: "", tokenRef: "" },
1571
- ownership
1572
- });
1573
1538
  } else {
1574
1539
  fs10.mkdirSync(libPath, { recursive: true });
1575
1540
  await manager.addLibrary({
@@ -1586,45 +1551,65 @@ function makeLibraryCommand() {
1586
1551
  }
1587
1552
  }
1588
1553
  );
1589
- cmd.command("add <git-url>").description("Clone a git library into ~/.skaile/libraries/<name>").option("--name <name>", "Override the derived library name").option("--owner", "Mark as owner (skip probe)").option("--contributor", "Mark as contributor (skip probe)").option("--reader", "Mark as reader (skip probe)").action(
1590
- async (url, opts) => {
1591
- const derived = opts.name ?? url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "library";
1592
- const libDir = resolveLibraryDir();
1593
- const libPath = path16.join(libDir, derived);
1594
- const { spawnSync } = await import('child_process');
1595
- const clone = spawnSync("git", ["clone", url, libPath], { stdio: "inherit" });
1596
- if (clone.status !== 0) {
1597
- logErr(`git clone failed for ${url}`);
1554
+ cmd.command("link <name> <git-url>").description("Attach a github remote to a local library (makes it store-publishable)").option("--branch <name>", "Default branch", "main").action(async (name, url, opts) => {
1555
+ const { manager, close } = await openLibraryManager();
1556
+ try {
1557
+ const lib = await manager.requireLibrary(name);
1558
+ if (lib.backend === "git") {
1559
+ logErr(
1560
+ `Library "${name}" is already git-backed. Use \`skaile library set ${name} backendConfig.url=${url}\` to change its remote.`
1561
+ );
1598
1562
  process.exit(1);
1599
1563
  }
1600
- const ownership = opts.owner ? "owner" : opts.contributor ? "contributor" : opts.reader ? "reader" : "reader";
1601
- const { manager, close } = await openUserLibraryManager();
1564
+ await manager.updateLibrary(name, {
1565
+ backend: "git",
1566
+ backendConfig: { url, branch: opts.branch, authHint: "ssh" }
1567
+ });
1568
+ logOk(`Library "${name}" linked to ${url}.`);
1569
+ } finally {
1570
+ close();
1571
+ }
1572
+ });
1573
+ cmd.command("create <kind> <name>").description("Scaffold a new asset inside the default (or named) library").addOption(
1574
+ new Option("--kind <kind>", "Asset kind override").choices([...ASSET_KINDS])
1575
+ ).option("--library <name>", "Target library (default: the default-marked one)").option("--dir <dir>", "Target directory inside the library (default: library root)").action(
1576
+ async (kind, name, opts) => {
1577
+ if (!ASSET_KINDS.includes(kind)) {
1578
+ logErr(`Unknown asset kind "${kind}". Expected: ${ASSET_KINDS.join(", ")}.`);
1579
+ process.exit(1);
1580
+ }
1581
+ const { manager, close } = await openLibraryManager();
1602
1582
  try {
1603
- await manager.addLibrary({
1604
- name: derived,
1605
- path: libPath,
1606
- backend: "git",
1607
- backendConfig: { url, branch: "main", authHint: "ssh" },
1608
- ownership
1609
- });
1610
- const { writeManifestIfMissing } = await import('../library/index.js');
1611
- const res = await writeManifestIfMissing({
1612
- libraryPath: libPath,
1613
- ownership,
1614
- structure: "flat"
1615
- });
1616
- if (res.wrote) {
1617
- await manager.updateLibrary(derived, { manifestGenerated: true });
1618
- logInfo(`Generated .skaile-source.yaml \u2014 edit by hand to inline assets.`);
1583
+ let target;
1584
+ if (opts.library) {
1585
+ target = await manager.requireLibrary(opts.library);
1586
+ } else {
1587
+ const all = await manager.listLibraries();
1588
+ const def = all.find((l) => l.isDefault);
1589
+ if (!def) {
1590
+ logErr(
1591
+ "No default library set. Either run `skaile library default <name>` first or pass --library."
1592
+ );
1593
+ process.exit(1);
1594
+ }
1595
+ target = def;
1596
+ }
1597
+ const am2 = new AssetManager({ projectDir: process.cwd() });
1598
+ const destDir = opts.dir ? path15.join(target.path, opts.dir) : target.path;
1599
+ const res = am2.create(name, opts.kind ?? kind, destDir);
1600
+ if (res.ok) {
1601
+ logOk(`Created ${opts.kind ?? kind}: ${pc5.dim(res.path)}`);
1602
+ } else {
1603
+ logErr(res.path);
1604
+ process.exit(1);
1619
1605
  }
1620
- logOk(`Library "${derived}" added (${ownership}).`);
1621
1606
  } finally {
1622
1607
  close();
1623
1608
  }
1624
1609
  }
1625
1610
  );
1626
1611
  cmd.command("default <name>").description("Set <name> as the default library").action(async (name) => {
1627
- const { manager, close } = await openUserLibraryManager();
1612
+ const { manager, close } = await openLibraryManager();
1628
1613
  try {
1629
1614
  const updated = await manager.setDefault(name);
1630
1615
  logOk(`Default \u2192 ${updated.name}`);
@@ -1633,11 +1618,11 @@ function makeLibraryCommand() {
1633
1618
  }
1634
1619
  });
1635
1620
  cmd.command("rename <old> <new>").description("Rename a library (also moves the directory)").action(async (oldName, newName) => {
1636
- const { manager, close } = await openUserLibraryManager();
1621
+ const { manager, close } = await openLibraryManager();
1637
1622
  try {
1638
1623
  const lib = await manager.requireLibrary(oldName);
1639
- const parent = path16.dirname(lib.path);
1640
- const newPath = path16.join(parent, newName);
1624
+ const parent = path15.dirname(lib.path);
1625
+ const newPath = path15.join(parent, newName);
1641
1626
  if (fs10.existsSync(newPath)) {
1642
1627
  logErr(`Target directory already exists: ${newPath}`);
1643
1628
  process.exit(1);
@@ -1652,7 +1637,7 @@ function makeLibraryCommand() {
1652
1637
  cmd.command("set <name> <field=value>").description("Update a single library field (e.g. ownership=contributor)").action(async (name, expr) => {
1653
1638
  const [field, ...rest] = expr.split("=");
1654
1639
  const value = rest.join("=");
1655
- const { manager, close } = await openUserLibraryManager();
1640
+ const { manager, close } = await openLibraryManager();
1656
1641
  try {
1657
1642
  const lib = await manager.requireLibrary(name);
1658
1643
  const patch = {};
@@ -1673,7 +1658,7 @@ function makeLibraryCommand() {
1673
1658
  }
1674
1659
  });
1675
1660
  cmd.command("remove <name>").description("Unregister a library (use --purge to also delete files)").option("--purge", "Also delete the library directory from disk", false).option("-y, --yes", "Skip confirmation", false).action(async (name, opts) => {
1676
- const { manager, close } = await openUserLibraryManager();
1661
+ const { manager, close } = await openLibraryManager();
1677
1662
  try {
1678
1663
  if (!opts.yes) {
1679
1664
  const confirmed = await p5.confirm({
@@ -1692,7 +1677,7 @@ function makeLibraryCommand() {
1692
1677
  }
1693
1678
  });
1694
1679
  cmd.command("sync <name>").description("Pull then push (as backend permits)").action(async (name) => {
1695
- const { manager, close } = await openUserLibraryManager();
1680
+ const { manager, close } = await openLibraryManager();
1696
1681
  try {
1697
1682
  const lib = await manager.requireLibrary(name);
1698
1683
  const drv = manager.driverFor(lib.backend);
@@ -1709,7 +1694,7 @@ function makeLibraryCommand() {
1709
1694
  }
1710
1695
  });
1711
1696
  cmd.command("pull <name>").description("Pull from remote").action(async (name) => {
1712
- const { manager, close } = await openUserLibraryManager();
1697
+ const { manager, close } = await openLibraryManager();
1713
1698
  try {
1714
1699
  const lib = await manager.requireLibrary(name);
1715
1700
  const res = await manager.driverFor(lib.backend).pull(lib);
@@ -1723,7 +1708,7 @@ function makeLibraryCommand() {
1723
1708
  }
1724
1709
  });
1725
1710
  cmd.command("push <name>").description("Push local commits (owner only)").option("--force", "Force-with-lease push", false).action(async (name, opts) => {
1726
- const { manager, close } = await openUserLibraryManager();
1711
+ const { manager, close } = await openLibraryManager();
1727
1712
  try {
1728
1713
  const lib = await manager.requireLibrary(name);
1729
1714
  const res = await manager.driverFor(lib.backend).push(lib, { force: opts.force });
@@ -1736,7 +1721,7 @@ function makeLibraryCommand() {
1736
1721
  }
1737
1722
  });
1738
1723
  cmd.command("propose <name>").description("Open a pull request on the upstream repo (contributor only)").option("--title <title>", "PR title").option("--body <body>", "PR body").option("--branch <name>", "Branch name (default: skaile/<timestamp>)").action(async (name, opts) => {
1739
- const { manager, close } = await openUserLibraryManager();
1724
+ const { manager, close } = await openLibraryManager();
1740
1725
  try {
1741
1726
  const lib = await manager.requireLibrary(name);
1742
1727
  const res = await manager.driverFor(lib.backend).propose(lib, opts);
@@ -1749,16 +1734,16 @@ function makeLibraryCommand() {
1749
1734
  }
1750
1735
  });
1751
1736
  cmd.command("commit <name>").description("Git-commit local changes inside the library (git only)").option("-m, --message <msg>", "Commit message", "skaile: update assets").action(async (name, opts) => {
1752
- const { manager, close } = await openUserLibraryManager();
1737
+ const { manager, close } = await openLibraryManager();
1753
1738
  try {
1754
1739
  const lib = await manager.requireLibrary(name);
1755
1740
  if (lib.backend !== "git") {
1756
1741
  logErr("`library commit` only applies to git-backed libraries.");
1757
1742
  process.exit(1);
1758
1743
  }
1759
- const { spawnSync } = await import('child_process');
1760
- spawnSync("git", ["add", "-A"], { cwd: lib.path, stdio: "inherit" });
1761
- const r = spawnSync("git", ["commit", "-m", opts.message], {
1744
+ const { spawnSync: spawnSync2 } = await import('child_process');
1745
+ spawnSync2("git", ["add", "-A"], { cwd: lib.path, stdio: "inherit" });
1746
+ const r = spawnSync2("git", ["commit", "-m", opts.message], {
1762
1747
  cwd: lib.path,
1763
1748
  stdio: "inherit"
1764
1749
  });
@@ -1773,126 +1758,151 @@ function makeLibraryCommand() {
1773
1758
  });
1774
1759
  cmd.command("git <name>").description("Pass-through: run arbitrary git commands inside the library").allowUnknownOption().action(async (name, _, command) => {
1775
1760
  const args = command.args.slice(1);
1776
- const { manager, close } = await openUserLibraryManager();
1761
+ const { manager, close } = await openLibraryManager();
1777
1762
  try {
1778
1763
  const lib = await manager.requireLibrary(name);
1779
- const { spawnSync } = await import('child_process');
1780
- const r = spawnSync("git", args, { cwd: lib.path, stdio: "inherit" });
1764
+ const { spawnSync: spawnSync2 } = await import('child_process');
1765
+ const r = spawnSync2("git", args, { cwd: lib.path, stdio: "inherit" });
1781
1766
  process.exit(r.status ?? 0);
1782
1767
  } finally {
1783
1768
  close();
1784
1769
  }
1785
1770
  });
1771
+ cmd.command("publish <ref>").description("Push + register manifest atomically (needs git backend)").action((_ref) => notWired("publish", NOT_WIRED_MSG_PUBLISH));
1772
+ cmd.command("register <ref>").description("Register manifest in store without pushing (bytes already on github)").action((_ref) => notWired("register", NOT_WIRED_MSG_PUBLISH));
1773
+ cmd.command("yank <ref>").description("Retract a catalog entry").option("--version <v>", "Version to yank").action((_ref) => notWired("yank", NOT_WIRED_MSG_PUBLISH));
1786
1774
  return cmd;
1787
1775
  }
1788
- function makeLibraryStatusCommand() {
1789
- return new Command("lib-status").description("Show Library status (sources, cached assets, instances, secrets)").option("--project-dir <path>", "Project directory", process.cwd()).option("--json", "Output as JSON").action(async (opts) => {
1790
- const library = await openLibrary();
1791
- try {
1792
- const sources = await library.listSources();
1793
- const defs = await library.listAssetDefs();
1794
- const instances = await library.listInstances();
1795
- let secretsStrategy = "unknown";
1796
- try {
1797
- const { LocalSecretsProvider: LocalSecretsProvider2 } = await import('../secrets/index.js');
1798
- const provider = new LocalSecretsProvider2();
1799
- secretsStrategy = provider.getKeyStrategy();
1800
- } catch {
1801
- secretsStrategy = "unavailable";
1802
- }
1803
- const projectDir = path16__default.resolve(opts.projectDir);
1804
- const hasWorkspaceConfig = existsSync(path16__default.join(projectDir, "skaile.yaml"));
1805
- const hasLockFile = existsSync(path16__default.join(projectDir, "skaile.lock.yaml"));
1806
- let subscriptions = [];
1807
- if (hasWorkspaceConfig) {
1808
- try {
1809
- subscriptions = await library.listSubscriptions(projectDir);
1810
- } catch {
1811
- }
1812
- }
1813
- const registry = createFullRegistry();
1814
- const registeredKinds = registry.getAllKinds();
1815
- if (opts.json) {
1816
- console.log(
1817
- JSON.stringify(
1818
- {
1819
- sources: sources.length,
1820
- assetDefinitions: defs.length,
1821
- instances: instances.length,
1822
- subscriptions: subscriptions.length,
1823
- secretsStrategy,
1824
- registeredKinds,
1825
- workspace: {
1826
- dir: projectDir,
1827
- hasConfig: hasWorkspaceConfig,
1828
- hasLock: hasLockFile
1829
- }
1830
- },
1831
- null,
1832
- 2
1833
- )
1834
- );
1835
- return;
1836
- }
1837
- console.log();
1838
- console.log(S.heading(" Library Status"));
1839
- console.log(` ${S.rule(50)}`);
1776
+ async function printPerLibraryStatus(name, asJson) {
1777
+ const { manager, close } = await openLibraryManager();
1778
+ try {
1779
+ const lib = await manager.requireLibrary(name);
1780
+ const status4 = await manager.driverFor(lib.backend).status(lib);
1781
+ if (asJson) return console.log(JSON.stringify({ library: lib.name, status: status4 }, null, 2));
1782
+ console.log(`
1783
+ ${S.heading(lib.name)}`);
1784
+ console.log(` reachable: ${status4.reachable ? S.ok("yes") : S.err("no")}`);
1785
+ if (status4.remoteChanges) {
1840
1786
  console.log(
1841
- ` ${S.label("Libraries")} ${sources.length === 0 ? S.dim("none") : pc6.green(String(sources.length))}`
1787
+ ` behind/ahead: ${status4.remoteChanges.behind}/${status4.remoteChanges.ahead}`
1842
1788
  );
1843
- for (const s of sources.slice(0, 3)) {
1844
- const synced = s.lastSyncedAt ? `synced ${formatRelativeTime(s.lastSyncedAt)}` : "never synced";
1845
- const defaultMark = s.isDefault ? pc6.green(" *") : "";
1846
- console.log(
1847
- ` ${S.dim(s.id.slice(0, 8))} ${s.name} ${S.dim(`(${s.type})`)} ${S.dim(s.ownership)} ${S.dim(synced)}${defaultMark}`
1848
- );
1849
- }
1850
- if (sources.length > 3) {
1851
- console.log(` ${S.dim(`...and ${sources.length - 3} more`)}`);
1852
- }
1853
- const byKind = /* @__PURE__ */ new Map();
1854
- for (const d of defs) {
1855
- byKind.set(d.kind, (byKind.get(d.kind) ?? 0) + 1);
1856
- }
1789
+ }
1790
+ const lc = status4.localChanges;
1791
+ if (lc.added.length + lc.modified.length + lc.deleted.length > 0) {
1857
1792
  console.log(
1858
- ` ${S.label("Cached assets")} ${defs.length === 0 ? S.dim("none") : pc6.green(String(defs.length))}`
1793
+ ` local changes: +${lc.added.length} ~${lc.modified.length} -${lc.deleted.length}`
1859
1794
  );
1860
- if (byKind.size > 0) {
1861
- const parts = [...byKind.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => `${v} ${k}${v > 1 ? "s" : ""}`);
1862
- console.log(` ${S.dim(parts.join(", "))}`);
1795
+ }
1796
+ for (const note of status4.notes) console.log(` ${pc5.dim("note:")} ${note}`);
1797
+ console.log();
1798
+ } finally {
1799
+ close();
1800
+ }
1801
+ }
1802
+ async function printOverallStatus(projectDir, asJson) {
1803
+ const library = await openLibrary();
1804
+ try {
1805
+ const libs = await library.listSources();
1806
+ const defs = await library.listAssetDefs();
1807
+ const instances = await library.listInstances();
1808
+ let secretsStrategy = "unknown";
1809
+ try {
1810
+ const { LocalSecretsProvider: LocalSecretsProvider2 } = await import('../secrets/index.js');
1811
+ const provider = new LocalSecretsProvider2();
1812
+ secretsStrategy = provider.getKeyStrategy();
1813
+ } catch {
1814
+ secretsStrategy = "unavailable";
1815
+ }
1816
+ const resolvedProjectDir = path15.resolve(projectDir);
1817
+ const hasWorkspaceConfig = existsSync(path15.join(resolvedProjectDir, "skaile.yaml"));
1818
+ const hasLockFile = existsSync(path15.join(resolvedProjectDir, "skaile.lock.yaml"));
1819
+ let subscriptions = [];
1820
+ if (hasWorkspaceConfig) {
1821
+ try {
1822
+ subscriptions = await library.listSubscriptions(resolvedProjectDir);
1823
+ } catch {
1863
1824
  }
1825
+ }
1826
+ const registry = createFullRegistry();
1827
+ const registeredKinds = registry.getAllKinds();
1828
+ if (asJson) {
1864
1829
  console.log(
1865
- ` ${S.label("Registered kinds")} ${pc6.green(String(registeredKinds.length))}`
1866
- );
1867
- console.log(` ${S.dim(registeredKinds.join(", "))}`);
1868
- console.log(
1869
- ` ${S.label("Instances")} ${instances.length === 0 ? S.dim("none") : pc6.green(String(instances.length))}`
1870
- );
1871
- console.log(
1872
- ` ${S.label("Subscriptions")} ${subscriptions.length === 0 ? S.dim("none (this workspace)") : pc6.green(String(subscriptions.length))}`
1873
- );
1874
- const strategyColor = secretsStrategy === "unavailable" ? S.dim : pc6.green;
1875
- console.log(` ${S.label("Secrets strategy")} ${strategyColor(secretsStrategy)}`);
1876
- console.log(` ${S.rule(50)}`);
1877
- console.log(` ${S.label("Workspace")} ${projectDir}`);
1878
- console.log(
1879
- ` ${S.label("skaile.yaml")} ${hasWorkspaceConfig ? pc6.green("present") : S.dim("not found")}`
1830
+ JSON.stringify(
1831
+ {
1832
+ libraries: libs.length,
1833
+ assetDefinitions: defs.length,
1834
+ instances: instances.length,
1835
+ subscriptions: subscriptions.length,
1836
+ secretsStrategy,
1837
+ registeredKinds,
1838
+ workspace: {
1839
+ dir: resolvedProjectDir,
1840
+ hasConfig: hasWorkspaceConfig,
1841
+ hasLock: hasLockFile
1842
+ }
1843
+ },
1844
+ null,
1845
+ 2
1846
+ )
1880
1847
  );
1848
+ return;
1849
+ }
1850
+ console.log();
1851
+ console.log(S.heading(" Library Status"));
1852
+ console.log(` ${S.rule(50)}`);
1853
+ console.log(
1854
+ ` ${S.label("Libraries")} ${libs.length === 0 ? S.dim("none") : pc5.green(String(libs.length))}`
1855
+ );
1856
+ for (const l of libs.slice(0, 3)) {
1857
+ const synced = l.lastSyncAt ? `synced ${formatRelativeTime(l.lastSyncAt)}` : "never synced";
1858
+ const defaultMark = l.isDefault ? pc5.green(" *") : "";
1881
1859
  console.log(
1882
- ` ${S.label("skaile.lock.yaml")} ${hasLockFile ? pc6.green("present") : S.dim("not found")}`
1860
+ ` ${S.dim(l.id.slice(0, 8))} ${l.name} ${S.dim(`(${l.backend})`)} ${S.dim(l.ownership)} ${S.dim(synced)}${defaultMark}`
1883
1861
  );
1884
- console.log();
1885
- if (sources.length === 0) {
1886
- logInfo("Get started: `skaile library init personal` or `skaile library add <git-url>`");
1887
- } else if (defs.length === 0) {
1888
- logInfo("Run `skaile library sync <name>` to discover assets.");
1889
- } else if (instances.length === 0) {
1890
- logInfo("Run `skaile asset install <ref>` to install an asset into a workspace.");
1891
- }
1892
- } finally {
1893
- library.close();
1894
1862
  }
1895
- });
1863
+ if (libs.length > 3) {
1864
+ console.log(` ${S.dim(`...and ${libs.length - 3} more`)}`);
1865
+ }
1866
+ const byKind = /* @__PURE__ */ new Map();
1867
+ for (const d of defs) byKind.set(d.kind, (byKind.get(d.kind) ?? 0) + 1);
1868
+ console.log(
1869
+ ` ${S.label("Cached assets")} ${defs.length === 0 ? S.dim("none") : pc5.green(String(defs.length))}`
1870
+ );
1871
+ if (byKind.size > 0) {
1872
+ const parts = [...byKind.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => `${v} ${k}${v > 1 ? "s" : ""}`);
1873
+ console.log(` ${S.dim(parts.join(", "))}`);
1874
+ }
1875
+ console.log(
1876
+ ` ${S.label("Registered kinds")} ${pc5.green(String(registeredKinds.length))}`
1877
+ );
1878
+ console.log(` ${S.dim(registeredKinds.join(", "))}`);
1879
+ console.log(
1880
+ ` ${S.label("Instances")} ${instances.length === 0 ? S.dim("none") : pc5.green(String(instances.length))}`
1881
+ );
1882
+ console.log(
1883
+ ` ${S.label("Subscriptions")} ${subscriptions.length === 0 ? S.dim("none (this workspace)") : pc5.green(String(subscriptions.length))}`
1884
+ );
1885
+ const strategyColor = secretsStrategy === "unavailable" ? S.dim : pc5.green;
1886
+ console.log(` ${S.label("Secrets strategy")} ${strategyColor(secretsStrategy)}`);
1887
+ console.log(` ${S.rule(50)}`);
1888
+ console.log(` ${S.label("Workspace")} ${resolvedProjectDir}`);
1889
+ console.log(
1890
+ ` ${S.label("skaile.yaml")} ${hasWorkspaceConfig ? pc5.green("present") : S.dim("not found")}`
1891
+ );
1892
+ console.log(
1893
+ ` ${S.label("skaile.lock.yaml")} ${hasLockFile ? pc5.green("present") : S.dim("not found")}`
1894
+ );
1895
+ console.log();
1896
+ if (libs.length === 0) {
1897
+ logInfo("Get started: `skaile library init personal` or `skaile source add <git-url>`");
1898
+ } else if (defs.length === 0) {
1899
+ logInfo("Run `skaile library sync <name>` to discover assets.");
1900
+ } else if (instances.length === 0) {
1901
+ logInfo("Run `skaile asset install <ref>` to install an asset into a workspace.");
1902
+ }
1903
+ } finally {
1904
+ library.close();
1905
+ }
1896
1906
  }
1897
1907
  function parseContainers(raw) {
1898
1908
  return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
@@ -1901,11 +1911,11 @@ function parseContainers(raw) {
1901
1911
  });
1902
1912
  }
1903
1913
  function colorLine(line) {
1904
- if (/error|Error|ERROR|failed|Failed/.test(line)) return pc6.red(line);
1905
- if (/connector|MCP|tool/.test(line)) return pc6.yellow(line);
1906
- if (/rebuilt|registered|ready/.test(line)) return pc6.green(line);
1907
- if (/\[driver\]/.test(line)) return pc6.cyan(line);
1908
- if (/\[serve\]/.test(line)) return pc6.dim(line);
1914
+ if (/error|Error|ERROR|failed|Failed/.test(line)) return pc5.red(line);
1915
+ if (/connector|MCP|tool/.test(line)) return pc5.yellow(line);
1916
+ if (/rebuilt|registered|ready/.test(line)) return pc5.green(line);
1917
+ if (/\[driver\]/.test(line)) return pc5.cyan(line);
1918
+ if (/\[serve\]/.test(line)) return pc5.dim(line);
1909
1919
  return line;
1910
1920
  }
1911
1921
  function dockerAvailable() {
@@ -2012,42 +2022,43 @@ function makeLogsCommand() {
2012
2022
  }
2013
2023
  var am;
2014
2024
  var state = {
2015
- tab: "libraries",
2025
+ tab: "assets",
2016
2026
  cursor: 0,
2017
2027
  assetRows: [],
2028
+ sourceRows: [],
2018
2029
  libraryRows: [],
2019
2030
  visibleRows: [],
2020
2031
  pendingAdds: /* @__PURE__ */ new Set(),
2021
2032
  pendingRemoves: /* @__PURE__ */ new Set(),
2022
- collapsedRepos: /* @__PURE__ */ new Set(),
2033
+ collapsedSources: /* @__PURE__ */ new Set(),
2023
2034
  collapsedDomains: /* @__PURE__ */ new Set(),
2024
2035
  message: "",
2025
2036
  cols: 80,
2026
2037
  awaitingExitConfirm: false
2027
2038
  };
2028
- function buildVisibleRows(rows, collapsedRepos, collapsedDomains) {
2039
+ function buildVisibleRows(rows, collapsedSources, collapsedDomains) {
2029
2040
  return rows.filter((row) => {
2030
- if (row.type === "repo-header") return true;
2031
- if (row.type === "header") return !collapsedRepos.has(row.repo);
2032
- 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";
2033
2044
  const domain = row.entry?.domain ?? "other";
2034
- return !collapsedRepos.has(repo) && !collapsedDomains.has(`${repo}:${domain}`);
2045
+ return !collapsedSources.has(source) && !collapsedDomains.has(`${source}:${domain}`);
2035
2046
  });
2036
2047
  }
2037
- function domainAssetRefs(rows, repo, domain) {
2038
- 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));
2039
2050
  }
2040
- function repoAssetRefs(rows, repo) {
2041
- 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));
2042
2053
  }
2043
2054
  function isAsset(r) {
2044
2055
  return r.type === "asset";
2045
2056
  }
2046
- function inRepo(r, repo) {
2047
- return (r.entry?.repository ?? "other") === repo;
2057
+ function inSource(r, source) {
2058
+ return (r.entry?.repository ?? "other") === source;
2048
2059
  }
2049
- function inDomain(r, repo, domain) {
2050
- 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;
2051
2062
  }
2052
2063
  function assetRefOf(r) {
2053
2064
  if (!isAsset(r) || !r.entry) return null;
@@ -2071,17 +2082,17 @@ function setSelection(ref, action) {
2071
2082
  state.pendingRemoves.delete(ref);
2072
2083
  return;
2073
2084
  }
2074
- resolved = row.deployed ? "remove" : "add";
2085
+ resolved = row.installed ? "remove" : "add";
2075
2086
  } else {
2076
2087
  resolved = action;
2077
2088
  }
2078
2089
  if (resolved === "add") {
2079
2090
  state.pendingRemoves.delete(ref);
2080
- if (row.deployed) return;
2091
+ if (row.installed) return;
2081
2092
  state.pendingAdds.add(ref);
2082
2093
  } else {
2083
2094
  state.pendingAdds.delete(ref);
2084
- if (!row.deployed) return;
2095
+ if (!row.installed) return;
2085
2096
  state.pendingRemoves.add(ref);
2086
2097
  }
2087
2098
  }
@@ -2089,51 +2100,53 @@ function bulkSelection(refs, action) {
2089
2100
  for (const ref of refs) setSelection(ref, action);
2090
2101
  }
2091
2102
  function actOnHeader(row, action) {
2092
- if (row.type === "repo-header") {
2093
- bulkSelection(repoAssetRefs(state.assetRows, row.repo), action);
2103
+ if (row.type === "source-header") {
2104
+ bulkSelection(sourceAssetRefs(state.assetRows, row.source), action);
2094
2105
  return true;
2095
2106
  }
2096
2107
  if (row.type === "header") {
2097
- bulkSelection(domainAssetRefs(state.assetRows, row.repo, row.domain), action);
2108
+ bulkSelection(domainAssetRefs(state.assetRows, row.source, row.domain), action);
2098
2109
  return true;
2099
2110
  }
2100
2111
  return false;
2101
2112
  }
2102
2113
  function loadAssets() {
2103
2114
  const entries = am.search();
2104
- const deployed = new Set(am.listDeployed().map((e) => `${e.kind}:${e.name}`));
2105
- const byRepo = /* @__PURE__ */ new Map();
2115
+ const installed = new Set(am.listDeployed().map((e) => `${e.kind}:${e.name}`));
2116
+ const bySource = /* @__PURE__ */ new Map();
2106
2117
  for (const e of entries) {
2107
- const repo = e.repository ?? "other";
2118
+ const source = e.repository ?? "other";
2108
2119
  const domain = e.domain ?? "other";
2109
- if (!byRepo.has(repo)) byRepo.set(repo, /* @__PURE__ */ new Map());
2110
- const domainMap = byRepo.get(repo);
2120
+ if (!bySource.has(source)) bySource.set(source, /* @__PURE__ */ new Map());
2121
+ const domainMap = bySource.get(source);
2111
2122
  if (!domainMap.has(domain)) domainMap.set(domain, []);
2112
2123
  domainMap.get(domain).push(e);
2113
2124
  }
2114
2125
  const rows = [];
2115
- for (const [repo, domainMap] of [...byRepo.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
2116
- 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 });
2117
2130
  for (const [domain, items] of [...domainMap.entries()].sort(
2118
2131
  (a, b) => a[0].localeCompare(b[0])
2119
2132
  )) {
2120
- rows.push({ type: "header", repo, domain });
2133
+ rows.push({ type: "header", source, domain });
2121
2134
  items.sort(
2122
2135
  (a, b) => a.kind !== b.kind ? a.kind.localeCompare(b.kind) : a.name.localeCompare(b.name)
2123
2136
  );
2124
2137
  for (const entry of items) {
2125
2138
  const ref = `${entry.kind}:${entry.name}`;
2126
- rows.push({ type: "asset", entry, deployed: deployed.has(ref) });
2139
+ rows.push({ type: "asset", entry, installed: installed.has(ref) });
2127
2140
  }
2128
2141
  }
2129
2142
  }
2130
2143
  state.assetRows = rows;
2131
- const newRepos = new Set(rows.filter((r) => r.type === "repo-header").map((r) => r.repo));
2132
- for (const r of state.collapsedRepos) {
2133
- 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);
2134
2147
  }
2135
2148
  const newDomainKeys = new Set(
2136
- 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}`)
2137
2150
  );
2138
2151
  for (const d of state.collapsedDomains) {
2139
2152
  if (!newDomainKeys.has(d)) state.collapsedDomains.delete(d);
@@ -2141,19 +2154,30 @@ function loadAssets() {
2141
2154
  for (const d of newDomainKeys) state.collapsedDomains.add(d);
2142
2155
  rebuildVisible();
2143
2156
  }
2144
- async function loadLibraries() {
2157
+ async function loadSourcesAndLibraries() {
2145
2158
  try {
2146
- const { openUserLibraryManager: openUserLibraryManager2 } = await import('../open-library-S6FK4N4S.js');
2147
- const { manager, library, close } = await openUserLibraryManager2();
2159
+ const [{ openLibraryManager: openLibraryManager2 }, { skaileHomeDir: skaileHomeDir2 }] = await Promise.all([
2160
+ import('../open-library-T6RXQJTQ.js'),
2161
+ import('../library/index.js')
2162
+ ]);
2163
+ const { manager, library, close } = await openLibraryManager2();
2148
2164
  try {
2165
+ const sourcesDir2 = path15__default.join(skaileHomeDir2(), "sources");
2166
+ const isSourceRow2 = (l) => l.path.startsWith(sourcesDir2);
2149
2167
  const libs = await manager.listLibraries();
2150
2168
  const defs = await library.listAssetDefs();
2151
2169
  const counts = /* @__PURE__ */ new Map();
2152
2170
  for (const d of defs) {
2153
- const id = d.sourceId ?? "";
2171
+ const id = d.libraryId ?? "";
2154
2172
  counts.set(id, (counts.get(id) ?? 0) + 1);
2155
2173
  }
2156
- 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) => ({
2157
2181
  name: l.name,
2158
2182
  backend: l.backend,
2159
2183
  ownership: l.ownership,
@@ -2164,13 +2188,14 @@ async function loadLibraries() {
2164
2188
  close();
2165
2189
  }
2166
2190
  } catch {
2191
+ state.sourceRows = [];
2167
2192
  state.libraryRows = [];
2168
2193
  }
2169
2194
  }
2170
2195
  function rebuildVisible() {
2171
2196
  state.visibleRows = buildVisibleRows(
2172
2197
  state.assetRows,
2173
- state.collapsedRepos,
2198
+ state.collapsedSources,
2174
2199
  state.collapsedDomains
2175
2200
  );
2176
2201
  clampCursor();
@@ -2185,19 +2210,11 @@ function moveCursor(delta) {
2185
2210
  state.cursor = Math.max(0, Math.min(maxCursor(), state.cursor + delta));
2186
2211
  }
2187
2212
  function nextTab() {
2188
- const order = ["libraries", "assets", "pending", "sync"];
2213
+ const order = ["assets", "sources", "libraries", "pending", "sync"];
2189
2214
  state.tab = order[(order.indexOf(state.tab) + 1) % order.length];
2190
2215
  state.cursor = 0;
2191
2216
  }
2192
2217
  var TABS = {
2193
- libraries: {
2194
- label: "Libraries",
2195
- rowCount: () => state.libraryRows.length,
2196
- selectableCount: () => state.libraryRows.length,
2197
- emptyMsg: " No libraries registered. Run `skaile library init <name>` or `skaile library add <git-url>` from the shell.",
2198
- renderRow: (i, sel) => renderLibraryRow(state.libraryRows[i], sel),
2199
- footer: " \u2191\u2193 navigate Tab switch q quit (use `skaile library \u2026` from the shell for CRUD)"
2200
- },
2201
2218
  assets: {
2202
2219
  label: "Assets",
2203
2220
  rowCount: () => state.visibleRows.length,
@@ -2205,6 +2222,22 @@ var TABS = {
2205
2222
  renderRow: (i, sel) => renderAssetRow(state.visibleRows[i], sel),
2206
2223
  footer: " \u2191\u2193/jk navigate \u2190/\u2192 collapse/expand [space/+/-] select [a/\u21B5] apply [i] info Tab switch [q/esc] quit"
2207
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
+ },
2208
2241
  pending: {
2209
2242
  label: "Pending",
2210
2243
  rowCount: () => 0,
@@ -2217,7 +2250,7 @@ var TABS = {
2217
2250
  label: "Sync",
2218
2251
  rowCount: () => 0,
2219
2252
  selectableCount: () => 0,
2220
- 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).",
2221
2254
  renderRow: () => "",
2222
2255
  footer: " s sync all Tab switch q quit"
2223
2256
  }
@@ -2234,8 +2267,8 @@ function showCursor() {
2234
2267
  function renderTabs() {
2235
2268
  return Object.entries(TABS).map(([id, spec]) => {
2236
2269
  const text = `${spec.label} (${spec.selectableCount()})`;
2237
- return id === state.tab ? pc6.bgCyan(pc6.black(` ${text} `)) : pc6.dim(` ${text} `);
2238
- }).join(pc6.dim("\u2502"));
2270
+ return id === state.tab ? pc5.bgCyan(pc5.black(` ${text} `)) : pc5.dim(` ${text} `);
2271
+ }).join(pc5.dim("\u2502"));
2239
2272
  }
2240
2273
  function pendingCountsFor(match) {
2241
2274
  let add = 0;
@@ -2251,63 +2284,67 @@ function pendingCountsFor(match) {
2251
2284
  return [add, remove];
2252
2285
  }
2253
2286
  function groupStatus(refs) {
2254
- if (refs.length === 0) return pc6.dim("\xB7 ");
2255
- if (refs.some((r) => state.pendingAdds.has(r))) return pc6.blue("+ ");
2256
- if (refs.some((r) => state.pendingRemoves.has(r))) return pc6.red("- ");
2257
- const allDeployed = refs.every((r) => findAssetRow(r)?.deployed);
2258
- return allDeployed ? pc6.green("\u2713 ") : pc6.dim("\xB7 ");
2287
+ if (refs.length === 0) return pc5.dim("\xB7 ");
2288
+ if (refs.some((r) => state.pendingAdds.has(r))) return pc5.blue("+ ");
2289
+ if (refs.some((r) => state.pendingRemoves.has(r))) return pc5.red("- ");
2290
+ const allInstalled = refs.every((r) => findAssetRow(r)?.installed);
2291
+ return allInstalled ? pc5.green("\u2713 ") : pc5.dim("\xB7 ");
2259
2292
  }
2260
2293
  function renderHeaderLine(opts) {
2261
2294
  const indicator = opts.collapsed ? "\u25B6" : "\u25BC";
2262
2295
  const total = state.assetRows.filter(opts.match).length;
2263
- 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;
2264
2297
  const [add, remove] = pendingCountsFor(opts.match);
2265
2298
  let count = String(installed);
2266
- if (add > 0) count += pc6.green(`+${add}`);
2267
- if (remove > 0) count += pc6.red(`-${remove}`);
2299
+ if (add > 0) count += pc5.green(`+${add}`);
2300
+ if (remove > 0) count += pc5.red(`-${remove}`);
2268
2301
  count += `/${total}`;
2269
2302
  const status4 = groupStatus(opts.refs);
2270
2303
  const line = `${opts.indent}${status4}${indicator} ${opts.label} (${count} assets)`;
2271
- return opts.selected ? pc6.bgWhite(pc6.black(`${line} `.padEnd(state.cols))) : line;
2304
+ return opts.selected ? pc5.bgWhite(pc5.black(`${line} `.padEnd(state.cols))) : line;
2272
2305
  }
2273
2306
  function renderAssetRow(row, selected) {
2274
- if (row.type === "repo-header") {
2307
+ if (row.type === "source-header") {
2275
2308
  return renderHeaderLine({
2276
2309
  indent: " ",
2277
- collapsed: state.collapsedRepos.has(row.repo),
2278
- match: (r) => isAsset(r) && inRepo(r, row.repo),
2279
- refs: repoAssetRefs(state.assetRows, row.repo),
2280
- label: pc6.bold(pc6.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)),
2281
2314
  selected
2282
2315
  });
2283
2316
  }
2284
2317
  if (row.type === "header") {
2285
2318
  return renderHeaderLine({
2286
2319
  indent: " ",
2287
- collapsed: state.collapsedDomains.has(`${row.repo}:${row.domain}`),
2288
- match: (r) => isAsset(r) && inDomain(r, row.repo, row.domain),
2289
- refs: domainAssetRefs(state.assetRows, row.repo, row.domain),
2290
- label: pc6.bold(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),
2323
+ label: pc5.bold(row.domain),
2291
2324
  selected
2292
2325
  });
2293
2326
  }
2294
2327
  const e = row.entry;
2295
2328
  const ref = assetRefOf(row);
2296
2329
  let status4;
2297
- if (state.pendingAdds.has(ref)) status4 = pc6.blue("+ ");
2298
- else if (state.pendingRemoves.has(ref)) status4 = pc6.red("- ");
2299
- else if (row.deployed) status4 = pc6.green("\u2713 ");
2300
- else status4 = pc6.dim("\xB7 ");
2330
+ if (state.pendingAdds.has(ref)) status4 = pc5.blue("+ ");
2331
+ else if (state.pendingRemoves.has(ref)) status4 = pc5.red("- ");
2332
+ else if (row.installed) status4 = pc5.green("\u2713 ");
2333
+ else status4 = pc5.dim("\xB7 ");
2301
2334
  const kind = kindColorPad(e.kind, 8);
2302
2335
  const name = e.name.padEnd(30);
2303
2336
  const desc = e.description?.slice(0, state.cols - 52) ?? "";
2304
- const line = ` ${status4} ${kind} ${name} ${pc6.dim(desc)}`;
2305
- return selected ? pc6.inverse(line.padEnd(state.cols)) : line;
2337
+ const line = ` ${status4} ${kind} ${name} ${pc5.dim(desc)}`;
2338
+ return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
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;
2306
2343
  }
2307
2344
  function renderLibraryRow(row, selected) {
2308
- const mark = row.isDefault ? pc6.green("\u25B8") : " ";
2309
- const line = `${mark} ${S.cmd(row.name.padEnd(16))} ${pc6.dim(row.backend.padEnd(7))} ${pc6.dim(row.ownership.padEnd(12))} ${pc6.dim(`${row.assetCount} assets`)}`;
2310
- return selected ? pc6.inverse(line.padEnd(state.cols)) : line;
2345
+ const mark = row.isDefault ? pc5.green("\u25B8") : " ";
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`)}`;
2347
+ return selected ? pc5.inverse(line.padEnd(state.cols)) : line;
2311
2348
  }
2312
2349
  function render() {
2313
2350
  clearScreen();
@@ -2317,12 +2354,12 @@ function render() {
2317
2354
  const overhead = 5 + pendingLines + msgLines;
2318
2355
  const maxRows = Math.max(5, (process.stdout.rows || 30) - overhead);
2319
2356
  console.log();
2320
- console.log(` ${pc6.bold("skaile manage")} ${renderTabs()}`);
2357
+ console.log(` ${pc5.bold("skaile manage")} ${renderTabs()}`);
2321
2358
  console.log(` ${S.rule(state.cols - 4)}`);
2322
2359
  const spec = TABS[state.tab];
2323
2360
  const total = spec.rowCount();
2324
2361
  if (total === 0 && spec.emptyMsg) {
2325
- console.log(pc6.dim(spec.emptyMsg));
2362
+ console.log(pc5.dim(spec.emptyMsg));
2326
2363
  } else {
2327
2364
  const start = Math.max(0, state.cursor - maxRows + 3);
2328
2365
  const end = Math.min(total, start + maxRows);
@@ -2333,9 +2370,9 @@ function render() {
2333
2370
  if (state.pendingAdds.size > 0 || state.pendingRemoves.size > 0) {
2334
2371
  console.log();
2335
2372
  if (state.pendingAdds.size > 0)
2336
- console.log(` ${pc6.blue(`+ ${state.pendingAdds.size} to add`)}`);
2373
+ console.log(` ${pc5.blue(`+ ${state.pendingAdds.size} to add`)}`);
2337
2374
  if (state.pendingRemoves.size > 0)
2338
- console.log(` ${pc6.red(`- ${state.pendingRemoves.size} to remove`)}`);
2375
+ console.log(` ${pc5.red(`- ${state.pendingRemoves.size} to remove`)}`);
2339
2376
  }
2340
2377
  if (state.message) {
2341
2378
  console.log();
@@ -2343,27 +2380,27 @@ function render() {
2343
2380
  state.message = "";
2344
2381
  }
2345
2382
  console.log();
2346
- console.log(pc6.dim(spec.footer));
2383
+ console.log(pc5.dim(spec.footer));
2347
2384
  }
2348
2385
  function renderExitPrompt() {
2349
2386
  clearScreen();
2350
2387
  console.log();
2351
- console.log(` ${pc6.yellow("!")} ${pc6.bold("You have unapplied changes:")}`);
2388
+ console.log(` ${pc5.yellow("!")} ${pc5.bold("You have unapplied changes:")}`);
2352
2389
  if (state.pendingAdds.size > 0)
2353
- console.log(` ${pc6.blue(`+ ${state.pendingAdds.size} to add`)}`);
2390
+ console.log(` ${pc5.blue(`+ ${state.pendingAdds.size} to add`)}`);
2354
2391
  if (state.pendingRemoves.size > 0)
2355
- console.log(` ${pc6.red(`- ${state.pendingRemoves.size} to remove`)}`);
2392
+ console.log(` ${pc5.red(`- ${state.pendingRemoves.size} to remove`)}`);
2356
2393
  console.log();
2357
2394
  console.log(
2358
- ` Apply before exiting? ${pc6.bold("[y]")} apply ${pc6.bold("[n]")} discard ${pc6.bold("[c/Esc]")} cancel`
2395
+ ` Apply before exiting? ${pc5.bold("[y]")} apply ${pc5.bold("[n]")} discard ${pc5.bold("[c/Esc]")} cancel`
2359
2396
  );
2360
2397
  }
2361
2398
  async function applyChanges() {
2362
2399
  if (state.pendingAdds.size === 0 && state.pendingRemoves.size === 0) {
2363
- state.message = pc6.dim("Nothing to apply.");
2400
+ state.message = pc5.dim("Nothing to apply.");
2364
2401
  return;
2365
2402
  }
2366
- state.message = pc6.yellow("Applying changes...");
2403
+ state.message = pc5.yellow("Applying changes...");
2367
2404
  render();
2368
2405
  let added = 0;
2369
2406
  let removed = 0;
@@ -2375,25 +2412,30 @@ async function applyChanges() {
2375
2412
  am.add(ref);
2376
2413
  added++;
2377
2414
  } catch (err) {
2378
- state.message = pc6.red(`Failed to add ${ref}: ${err}`);
2415
+ state.message = pc5.red(`Failed to add ${ref}: ${err}`);
2379
2416
  }
2380
2417
  }
2381
2418
  state.pendingAdds.clear();
2382
2419
  state.pendingRemoves.clear();
2383
2420
  loadAssets();
2384
2421
  const parts = [];
2385
- if (added > 0) parts.push(pc6.green(`+${added} added`));
2386
- if (removed > 0) parts.push(pc6.red(`-${removed} removed`));
2422
+ if (added > 0) parts.push(pc5.green(`+${added} added`));
2423
+ if (removed > 0) parts.push(pc5.red(`-${removed} removed`));
2387
2424
  if (parts.length) state.message = parts.join(" ");
2388
2425
  }
2389
- async function syncLibraries() {
2390
- state.message = pc6.yellow(
2391
- "Library sync is not yet driven from the manage TUI. Run `skaile library sync <name>` from the shell."
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) {
2432
+ state.message = pc5.yellow(
2433
+ `${action} is a shell command. Run \`skaile source \u2026\` from the shell.`
2392
2434
  );
2393
2435
  }
2394
- function shellHint(action) {
2395
- state.message = pc6.yellow(
2396
- `${action} is a shell command in the Libraries redesign. Run \`skaile library \u2026\` from the shell.`
2436
+ function libraryShellHint(action) {
2437
+ state.message = pc5.yellow(
2438
+ `${action} is a shell command. Run \`skaile library \u2026\` from the shell.`
2397
2439
  );
2398
2440
  }
2399
2441
  async function showInfo() {
@@ -2403,13 +2445,13 @@ async function showInfo() {
2403
2445
  const e = row.entry;
2404
2446
  clearScreen();
2405
2447
  console.log();
2406
- console.log(` ${kindColor(e.kind)} ${pc6.bold(e.name)}`);
2448
+ console.log(` ${kindColor(e.kind)} ${pc5.bold(e.name)}`);
2407
2449
  console.log(` ${S.rule(50)}`);
2408
2450
  if (e.version) console.log(` version: ${e.version}`);
2409
2451
  if (e.description) console.log(` description: ${e.description}`);
2410
- if (e.repository) console.log(` repository: ${pc6.dim(e.repository)}`);
2411
- console.log(` source: ${pc6.dim(e.source)}`);
2412
- console.log(` deployed: ${row.deployed ? pc6.green("yes") : pc6.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")}`);
2413
2455
  if (e.requires.length) {
2414
2456
  console.log(` requires:`);
2415
2457
  for (const d of e.requires) console.log(` ${kindColor(d.kind)}:${d.name}`);
@@ -2419,11 +2461,11 @@ async function showInfo() {
2419
2461
  for (const d of e.dependencies) console.log(` ${d}`);
2420
2462
  }
2421
2463
  console.log();
2422
- console.log(pc6.dim(" Press any key to return..."));
2423
- await new Promise((resolve3) => {
2464
+ console.log(pc5.dim(" Press any key to return..."));
2465
+ await new Promise((resolve4) => {
2424
2466
  const onData = () => {
2425
2467
  process.stdin.removeListener("data", onData);
2426
- resolve3();
2468
+ resolve4();
2427
2469
  };
2428
2470
  process.stdin.once("data", onData);
2429
2471
  });
@@ -2431,11 +2473,11 @@ async function showInfo() {
2431
2473
  function expandUnderCursor() {
2432
2474
  const row = state.visibleRows[state.cursor];
2433
2475
  if (!row) return;
2434
- if (row.type === "repo-header" && state.collapsedRepos.has(row.repo)) {
2435
- state.collapsedRepos.delete(row.repo);
2476
+ if (row.type === "source-header" && state.collapsedSources.has(row.source)) {
2477
+ state.collapsedSources.delete(row.source);
2436
2478
  rebuildVisible();
2437
2479
  } else if (row.type === "header") {
2438
- const dk = `${row.repo}:${row.domain}`;
2480
+ const dk = `${row.source}:${row.domain}`;
2439
2481
  if (state.collapsedDomains.has(dk)) {
2440
2482
  state.collapsedDomains.delete(dk);
2441
2483
  rebuildVisible();
@@ -2445,15 +2487,15 @@ function expandUnderCursor() {
2445
2487
  function collapseOrJumpUnderCursor() {
2446
2488
  const row = state.visibleRows[state.cursor];
2447
2489
  if (!row) return;
2448
- if (row.type === "repo-header") {
2449
- if (!state.collapsedRepos.has(row.repo)) {
2450
- state.collapsedRepos.add(row.repo);
2490
+ if (row.type === "source-header") {
2491
+ if (!state.collapsedSources.has(row.source)) {
2492
+ state.collapsedSources.add(row.source);
2451
2493
  rebuildVisible();
2452
2494
  }
2453
2495
  return;
2454
2496
  }
2455
2497
  if (row.type === "header") {
2456
- const dk = `${row.repo}:${row.domain}`;
2498
+ const dk = `${row.source}:${row.domain}`;
2457
2499
  if (!state.collapsedDomains.has(dk)) {
2458
2500
  state.collapsedDomains.add(dk);
2459
2501
  rebuildVisible();
@@ -2461,7 +2503,7 @@ function collapseOrJumpUnderCursor() {
2461
2503
  const idx2 = findLastIndex(
2462
2504
  state.visibleRows,
2463
2505
  state.cursor,
2464
- (r) => r.type === "repo-header"
2506
+ (r) => r.type === "source-header"
2465
2507
  );
2466
2508
  if (idx2 >= 0) state.cursor = idx2;
2467
2509
  }
@@ -2470,7 +2512,7 @@ function collapseOrJumpUnderCursor() {
2470
2512
  const idx = findLastIndex(
2471
2513
  state.visibleRows,
2472
2514
  state.cursor,
2473
- (r) => r.type === "header" || r.type === "repo-header"
2515
+ (r) => r.type === "header" || r.type === "source-header"
2474
2516
  );
2475
2517
  if (idx >= 0) state.cursor = idx;
2476
2518
  }
@@ -2481,6 +2523,7 @@ function findLastIndex(arr, endExclusive, pred) {
2481
2523
  return -1;
2482
2524
  }
2483
2525
  var TAB_ASSETS = (t) => t === "assets";
2526
+ var TAB_SOURCES = (t) => t === "sources";
2484
2527
  var TAB_LIBRARIES = (t) => t === "libraries";
2485
2528
  var KEYMAP = [
2486
2529
  // Quit (with pending check) — handled here, not via a modal subroutine, so
@@ -2503,7 +2546,7 @@ var KEYMAP = [
2503
2546
  // Collapse / expand — assets tab only
2504
2547
  { keys: ["\x1B[C"], when: TAB_ASSETS, run: expandUnderCursor },
2505
2548
  { keys: ["\x1B[D"], when: TAB_ASSETS, run: collapseOrJumpUnderCursor },
2506
- // + : assets → bulk-add or single-add toggle; repos → add repo
2549
+ // + : assets → bulk-add or single-add toggle
2507
2550
  {
2508
2551
  keys: ["+"],
2509
2552
  when: TAB_ASSETS,
@@ -2516,9 +2559,28 @@ var KEYMAP = [
2516
2559
  }
2517
2560
  }
2518
2561
  },
2519
- // Libraries tab: +/-/r/d/n/enter all map to shell hints in the minimal scaffold.
2520
- { keys: ["+", "n"], when: TAB_LIBRARIES, run: () => shellHint("Adding a library") },
2521
- // - : 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
2522
2584
  {
2523
2585
  keys: ["-"],
2524
2586
  when: TAB_ASSETS,
@@ -2531,8 +2593,6 @@ var KEYMAP = [
2531
2593
  }
2532
2594
  }
2533
2595
  },
2534
- { keys: ["-", "r", "x"], when: TAB_LIBRARIES, run: () => shellHint("Removing a library") },
2535
- { keys: ["d"], when: TAB_LIBRARIES, run: () => shellHint("Setting the default library") },
2536
2596
  // Space — auto-toggle (single asset or bulk header)
2537
2597
  {
2538
2598
  keys: [" "],
@@ -2546,14 +2606,12 @@ var KEYMAP = [
2546
2606
  }
2547
2607
  }
2548
2608
  },
2549
- // s — sync (any tab) — minimal scaffold delegates to shell.
2550
- { keys: ["s"], run: syncLibraries },
2551
- // 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
2552
2612
  { keys: ["a"], when: TAB_ASSETS, run: applyChanges },
2553
- { keys: ["a"], when: TAB_LIBRARIES, run: () => shellHint("Adding a library") },
2554
- // Enter — apply on assets tab; libraries → shell hint
2613
+ // Enter apply on assets tab
2555
2614
  { keys: ["\r", "\n"], when: TAB_ASSETS, run: applyChanges },
2556
- { keys: ["\r", "\n"], when: TAB_LIBRARIES, run: () => shellHint("Library actions") },
2557
2615
  // Info — assets only
2558
2616
  { keys: ["i"], when: TAB_ASSETS, run: showInfo }
2559
2617
  ];
@@ -2582,7 +2640,7 @@ async function handleExitConfirm(key) {
2582
2640
  async function run(projectDir) {
2583
2641
  am = new AssetManager({ projectDir });
2584
2642
  loadAssets();
2585
- await loadLibraries();
2643
+ await loadSourcesAndLibraries();
2586
2644
  hideCursor();
2587
2645
  process.stdin.setRawMode(true);
2588
2646
  process.stdin.resume();
@@ -2600,8 +2658,8 @@ async function run(projectDir) {
2600
2658
  clearScreen();
2601
2659
  }
2602
2660
  function makeManageCommand() {
2603
- return new Command("manage").description("Interactive TUI for managing libraries and assets").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
2604
- await run(path16__default.resolve(opts.projectDir));
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) => {
2662
+ await run(path15__default.resolve(opts.projectDir));
2605
2663
  });
2606
2664
  }
2607
2665
  function makeMcpServerCommand() {
@@ -2642,7 +2700,7 @@ function makeNpxCommand() {
2642
2700
  const npx = new Command("npx").description("Compatibility shim for npx skills syntax");
2643
2701
  const skills = npx.command("skills").description("Skill installation from external repos");
2644
2702
  skills.command("add <url>").description("Register a repo as a Library Source and install a skill from it").requiredOption("--skill <name>", "Skill name to install from the repo").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").option("--global", "Deploy globally").action(async (url, opts) => {
2645
- const projectDir = path16__default.resolve(opts.projectDir);
2703
+ const projectDir = path15__default.resolve(opts.projectDir);
2646
2704
  const spinner5 = p5.spinner();
2647
2705
  let sourcePath;
2648
2706
  const isUrl = /^(https?:|git@|git:)/.test(url);
@@ -2653,14 +2711,14 @@ function makeNpxCommand() {
2653
2711
  if (!existsSync(sourcePath)) {
2654
2712
  execSync(`git clone ${url} ${sourcePath}`, { stdio: "ignore" });
2655
2713
  }
2656
- spinner5.stop(`Cloned to ${path16__default.basename(sourcePath)}`);
2714
+ spinner5.stop(`Cloned to ${path15__default.basename(sourcePath)}`);
2657
2715
  } catch (err) {
2658
2716
  spinner5.stop("Clone failed");
2659
2717
  logErr(err instanceof Error ? err.message : String(err));
2660
2718
  process.exit(1);
2661
2719
  }
2662
2720
  } else {
2663
- sourcePath = path16__default.resolve(url);
2721
+ sourcePath = path15__default.resolve(url);
2664
2722
  if (!existsSync(sourcePath)) {
2665
2723
  logErr(`Path does not exist: ${sourcePath}`);
2666
2724
  process.exit(1);
@@ -2672,9 +2730,10 @@ function makeNpxCommand() {
2672
2730
  let source = existing.find((s) => s.path === sourcePath);
2673
2731
  if (!source) {
2674
2732
  source = await library.addSource({
2675
- type: "local",
2676
- name: path16__default.basename(sourcePath),
2677
- path: sourcePath
2733
+ backend: "local",
2734
+ name: path15__default.basename(sourcePath),
2735
+ path: sourcePath,
2736
+ ownership: "owner"
2678
2737
  });
2679
2738
  }
2680
2739
  spinner5.start("Syncing source");
@@ -2713,7 +2772,7 @@ function makeNpxCommand() {
2713
2772
  }
2714
2773
  function cloneDestination(url) {
2715
2774
  const cleaned = url.replace(/\.git$/, "");
2716
- const root = path16__default.join(homedir(), ".skaile", "clones");
2775
+ const root = path15__default.join(homedir(), ".skaile", "clones");
2717
2776
  let host = "unknown";
2718
2777
  let pathPart = cleaned;
2719
2778
  const httpMatch = cleaned.match(/^https?:\/\/([^/]+)\/(.+)$/);
@@ -2729,14 +2788,14 @@ function cloneDestination(url) {
2729
2788
  host = gitProtoMatch[1];
2730
2789
  pathPart = gitProtoMatch[2];
2731
2790
  }
2732
- return path16__default.join(root, host, pathPart);
2791
+ return path15__default.join(root, host, pathPart);
2733
2792
  }
2734
2793
  function makeOutdatedCommand() {
2735
2794
  return new Command("outdated").description("Check for assets behind their repo").argument("[name]", "Check a specific asset (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).addOption(
2736
2795
  new Option("--target <agent>", "Driver target").default("claude-code").choices(SUPPORTED_DRIVER_TARGETS)
2737
2796
  ).action((name, opts) => {
2738
2797
  const am2 = new AssetManager({
2739
- projectDir: path16__default.resolve(opts.projectDir),
2798
+ projectDir: path15__default.resolve(opts.projectDir),
2740
2799
  driverTarget: opts.target
2741
2800
  });
2742
2801
  const entries = am2.outdated();
@@ -2755,7 +2814,7 @@ function makeOutdatedCommand() {
2755
2814
  console.log(` ${S.rule(nameW + 40)}`);
2756
2815
  for (const e of filtered) {
2757
2816
  console.log(
2758
- ` ${kindColorPad(e.kind)} ${e.name.padEnd(nameW)} ${S.dim(e.repository)} ${pc6.yellow(`${e.behind} commit(s) behind`)}`
2817
+ ` ${kindColorPad(e.kind)} ${e.name.padEnd(nameW)} ${S.dim(e.repository)} ${pc5.yellow(`${e.behind} commit(s) behind`)}`
2759
2818
  );
2760
2819
  }
2761
2820
  console.log();
@@ -2765,7 +2824,7 @@ function makeOutdatedCommand() {
2765
2824
  function makePatchCommand() {
2766
2825
  const cmd = new Command("patch").description("Patch workflow for skill improvement");
2767
2826
  cmd.command("extract <ref>").alias("start").description("Extract asset for local editing").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
2768
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
2827
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
2769
2828
  try {
2770
2829
  const dest = am2.patch(ref);
2771
2830
  logOk(`Extracted to ${S.dim(dest)}`);
@@ -2776,7 +2835,7 @@ function makePatchCommand() {
2776
2835
  }
2777
2836
  });
2778
2837
  cmd.command("commit <ref>").description("Generate .patch file from edits").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
2779
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
2838
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
2780
2839
  try {
2781
2840
  const patchFile = am2.patchCommit(ref);
2782
2841
  logOk(`Patch saved to ${S.dim(patchFile)}`);
@@ -2787,7 +2846,7 @@ function makePatchCommand() {
2787
2846
  }
2788
2847
  });
2789
2848
  cmd.command("submit <ref>").description("Apply patch to repo clone and prepare for PR").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
2790
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
2849
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
2791
2850
  try {
2792
2851
  am2.patchSubmit(ref);
2793
2852
  logOk("Patch applied to repo clone and committed.");
@@ -2800,7 +2859,7 @@ function makePatchCommand() {
2800
2859
  }
2801
2860
  });
2802
2861
  cmd.command("remove <ref>").description("Remove local patch after upstream merge").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
2803
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
2862
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
2804
2863
  am2.patchRemove(ref);
2805
2864
  logOk(`Patch removed for ${ref}`);
2806
2865
  });
@@ -2814,7 +2873,7 @@ var MCP_SERVER_ENTRY = {
2814
2873
  env: {}
2815
2874
  };
2816
2875
  function pluginDir(projectDir) {
2817
- return path16__default.join(projectDir, ".claude", "plugins", "skaile");
2876
+ return path15__default.join(projectDir, ".claude", "plugins", "skaile");
2818
2877
  }
2819
2878
  async function readJsonStrict(p7) {
2820
2879
  let raw;
@@ -2832,7 +2891,7 @@ async function readJsonStrict(p7) {
2832
2891
  }
2833
2892
  }
2834
2893
  async function writeJson(p7, value) {
2835
- await fs5.mkdir(path16__default.dirname(p7), { recursive: true });
2894
+ await fs5.mkdir(path15__default.dirname(p7), { recursive: true });
2836
2895
  await fs5.writeFile(p7, `${JSON.stringify(value, null, 2)}
2837
2896
  `);
2838
2897
  }
@@ -2840,8 +2899,8 @@ async function copyDir(src, dest) {
2840
2899
  await fs5.mkdir(dest, { recursive: true });
2841
2900
  const entries = await fs5.readdir(src, { withFileTypes: true });
2842
2901
  for (const entry of entries) {
2843
- const srcPath = path16__default.join(src, entry.name);
2844
- const destPath = path16__default.join(dest, entry.name);
2902
+ const srcPath = path15__default.join(src, entry.name);
2903
+ const destPath = path15__default.join(dest, entry.name);
2845
2904
  if (entry.isDirectory()) await copyDir(srcPath, destPath);
2846
2905
  else await fs5.copyFile(srcPath, destPath);
2847
2906
  }
@@ -2850,14 +2909,14 @@ async function install(projectDir, opts) {
2850
2909
  return opts?.full ? installFullPlugin(projectDir) : installMcp(projectDir);
2851
2910
  }
2852
2911
  async function installMcp(projectDir) {
2853
- const mcpPath = path16__default.join(projectDir, ".claude", "mcp.json");
2912
+ const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
2854
2913
  const existing = await readJsonStrict(mcpPath) ?? {};
2855
2914
  const mcpServers = { ...existing.mcpServers ?? {} };
2856
2915
  const previous = mcpServers[SKAILE_MCP_NAME];
2857
2916
  const matches = previous && JSON.stringify(previous) === JSON.stringify(MCP_SERVER_ENTRY);
2858
2917
  let warning;
2859
2918
  if (previous && !matches) {
2860
- warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${path16__default.relative(projectDir, mcpPath)}`;
2919
+ warning = `overwrote existing ${SKAILE_MCP_NAME} entry in ${path15__default.relative(projectDir, mcpPath)}`;
2861
2920
  }
2862
2921
  mcpServers[SKAILE_MCP_NAME] = MCP_SERVER_ENTRY;
2863
2922
  await writeJson(mcpPath, { ...existing, mcpServers });
@@ -2866,15 +2925,15 @@ async function installMcp(projectDir) {
2866
2925
  async function installFullPlugin(projectDir) {
2867
2926
  const dir = pluginDir(projectDir);
2868
2927
  for (const [rel, content] of Object.entries(buildClaudePluginFiles())) {
2869
- const dest = path16__default.join(dir, rel);
2870
- await fs5.mkdir(path16__default.dirname(dest), { recursive: true });
2928
+ const dest = path15__default.join(dir, rel);
2929
+ await fs5.mkdir(path15__default.dirname(dest), { recursive: true });
2871
2930
  await fs5.writeFile(dest, content);
2872
2931
  }
2873
- const projectSkillsDir = path16__default.join(projectDir, ".skaile", "skills");
2932
+ const projectSkillsDir = path15__default.join(projectDir, ".skaile", "skills");
2874
2933
  if (existsSync(projectSkillsDir)) {
2875
- await copyDir(projectSkillsDir, path16__default.join(dir, "skills"));
2934
+ await copyDir(projectSkillsDir, path15__default.join(dir, "skills"));
2876
2935
  }
2877
- const settingsPath = path16__default.join(projectDir, ".claude", "settings.json");
2936
+ const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
2878
2937
  const settings = await readJsonStrict(settingsPath) ?? {};
2879
2938
  const plugins = settings.plugins ?? [];
2880
2939
  if (!plugins.includes(dir)) plugins.push(dir);
@@ -2882,8 +2941,8 @@ async function installFullPlugin(projectDir) {
2882
2941
  return { changed: true, method: "plugin" };
2883
2942
  }
2884
2943
  async function uninstall(projectDir) {
2885
- const settingsPath = path16__default.join(projectDir, ".claude", "settings.json");
2886
- const mcpPath = path16__default.join(projectDir, ".claude", "mcp.json");
2944
+ const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
2945
+ const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
2887
2946
  const dir = pluginDir(projectDir);
2888
2947
  let changed = false;
2889
2948
  const settings = await readJsonStrict(settingsPath);
@@ -2917,12 +2976,12 @@ async function uninstall(projectDir) {
2917
2976
  async function detectInstall(projectDir) {
2918
2977
  const dir = pluginDir(projectDir);
2919
2978
  const settings = await readJsonStrict(
2920
- path16__default.join(projectDir, ".claude", "settings.json")
2979
+ path15__default.join(projectDir, ".claude", "settings.json")
2921
2980
  );
2922
- if (existsSync(path16__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir)) {
2981
+ if (existsSync(path15__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir)) {
2923
2982
  return { method: "plugin", pluginPath: dir };
2924
2983
  }
2925
- const mcp = await readJsonStrict(path16__default.join(projectDir, ".claude", "mcp.json"));
2984
+ const mcp = await readJsonStrict(path15__default.join(projectDir, ".claude", "mcp.json"));
2926
2985
  if (mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers) {
2927
2986
  return { method: "mcp" };
2928
2987
  }
@@ -2931,7 +2990,7 @@ async function detectInstall(projectDir) {
2931
2990
  async function enable(projectDir) {
2932
2991
  const detected = await detectInstall(projectDir);
2933
2992
  if (!detected) throw new Error("plugin not installed for claude-code");
2934
- const settingsPath = path16__default.join(projectDir, ".claude", "settings.json");
2993
+ const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
2935
2994
  const settings = await readJsonStrict(settingsPath) ?? {};
2936
2995
  if (detected.method === "plugin") {
2937
2996
  const disabled2 = settings.disabledPlugins ?? [];
@@ -2953,7 +3012,7 @@ async function enable(projectDir) {
2953
3012
  async function disable(projectDir) {
2954
3013
  const detected = await detectInstall(projectDir);
2955
3014
  if (!detected) throw new Error("plugin not installed for claude-code");
2956
- const settingsPath = path16__default.join(projectDir, ".claude", "settings.json");
3015
+ const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
2957
3016
  const settings = await readJsonStrict(settingsPath) ?? {};
2958
3017
  if (detected.method === "plugin") {
2959
3018
  const list2 = settings.disabledPlugins ?? [];
@@ -2973,12 +3032,12 @@ async function disable(projectDir) {
2973
3032
  return { changed: true };
2974
3033
  }
2975
3034
  async function status(projectDir) {
2976
- const settingsPath = path16__default.join(projectDir, ".claude", "settings.json");
2977
- const mcpPath = path16__default.join(projectDir, ".claude", "mcp.json");
3035
+ const settingsPath = path15__default.join(projectDir, ".claude", "settings.json");
3036
+ const mcpPath = path15__default.join(projectDir, ".claude", "mcp.json");
2978
3037
  const dir = pluginDir(projectDir);
2979
3038
  const settings = await readJsonStrict(settingsPath);
2980
3039
  const mcp = await readJsonStrict(mcpPath);
2981
- const pluginInstalled = !!(existsSync(path16__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir));
3040
+ const pluginInstalled = !!(existsSync(path15__default.join(dir, ".claude-plugin", "plugin.json")) && settings?.plugins?.includes(dir));
2982
3041
  const mcpInstalled = !!(mcp?.mcpServers && SKAILE_MCP_NAME in mcp.mcpServers);
2983
3042
  if (!pluginInstalled && !mcpInstalled) {
2984
3043
  return {
@@ -2996,7 +3055,7 @@ async function status(projectDir) {
2996
3055
  installed: "yes",
2997
3056
  enabled: disabled2 ? "no" : "yes",
2998
3057
  method: "plugin",
2999
- location: path16__default.relative(projectDir, dir)
3058
+ location: path15__default.relative(projectDir, dir)
3000
3059
  };
3001
3060
  }
3002
3061
  const disabled = settings?.disabledMcpjsonServers?.includes(SKAILE_MCP_NAME) ?? false;
@@ -3005,7 +3064,7 @@ async function status(projectDir) {
3005
3064
  installed: "yes",
3006
3065
  enabled: disabled ? "no" : "yes",
3007
3066
  method: "mcp",
3008
- location: path16__default.relative(projectDir, mcpPath)
3067
+ location: path15__default.relative(projectDir, mcpPath)
3009
3068
  };
3010
3069
  }
3011
3070
  var SKAILE_MCP_NAME2 = "skaile-workspace";
@@ -3032,7 +3091,7 @@ async function readConfig(p7) {
3032
3091
  }
3033
3092
  }
3034
3093
  async function writeConfig(p7, value) {
3035
- await fs5.mkdir(path16__default.dirname(p7), { recursive: true });
3094
+ await fs5.mkdir(path15__default.dirname(p7), { recursive: true });
3036
3095
  const cleaned = {};
3037
3096
  for (const [k, v] of Object.entries(value)) {
3038
3097
  if (v === void 0) continue;
@@ -3041,7 +3100,7 @@ async function writeConfig(p7, value) {
3041
3100
  await fs5.writeFile(p7, stringify(cleaned));
3042
3101
  }
3043
3102
  function configPath(projectDir) {
3044
- return path16__default.join(projectDir, ".codex", "config.toml");
3103
+ return path15__default.join(projectDir, ".codex", "config.toml");
3045
3104
  }
3046
3105
  async function install2(projectDir) {
3047
3106
  const p7 = configPath(projectDir);
@@ -3052,7 +3111,7 @@ async function install2(projectDir) {
3052
3111
  const matches = previous && JSON.stringify(previous) === JSON.stringify(next);
3053
3112
  let warning;
3054
3113
  if (previous && !matches) {
3055
- warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path16__default.relative(projectDir, p7)}`;
3114
+ warning = `overwrote existing ${SKAILE_MCP_NAME2} entry in ${path15__default.relative(projectDir, p7)}`;
3056
3115
  }
3057
3116
  if (matches) return { changed: false, method: "toml" };
3058
3117
  servers[SKAILE_MCP_NAME2] = next;
@@ -3093,12 +3152,12 @@ async function status2(projectDir) {
3093
3152
  installed: "yes",
3094
3153
  enabled: "n/a",
3095
3154
  method: "mcp",
3096
- location: path16__default.relative(projectDir, p7)
3155
+ location: path15__default.relative(projectDir, p7)
3097
3156
  };
3098
3157
  }
3099
3158
  async function install3(projectDir) {
3100
- const extDir = path16__default.join(projectDir, ".omp", "extensions");
3101
- const extPath = path16__default.join(extDir, "skaile.ts");
3159
+ const extDir = path15__default.join(projectDir, ".omp", "extensions");
3160
+ const extPath = path15__default.join(extDir, "skaile.ts");
3102
3161
  await fs5.mkdir(extDir, { recursive: true });
3103
3162
  const { WorkspacePlugin } = await import('../workspace-plugin/index.js');
3104
3163
  const plugin = new WorkspacePlugin({ projectDir });
@@ -3113,7 +3172,7 @@ async function install3(projectDir) {
3113
3172
  return { changed: true, method: "generated" };
3114
3173
  }
3115
3174
  async function uninstall3(projectDir) {
3116
- const extPath = path16__default.join(projectDir, ".omp", "extensions", "skaile.ts");
3175
+ const extPath = path15__default.join(projectDir, ".omp", "extensions", "skaile.ts");
3117
3176
  try {
3118
3177
  await fs5.unlink(extPath);
3119
3178
  return { changed: true };
@@ -3122,14 +3181,14 @@ async function uninstall3(projectDir) {
3122
3181
  }
3123
3182
  }
3124
3183
  async function status3(projectDir) {
3125
- const extPath = path16__default.join(projectDir, ".omp", "extensions", "skaile.ts");
3184
+ const extPath = path15__default.join(projectDir, ".omp", "extensions", "skaile.ts");
3126
3185
  if (existsSync(extPath)) {
3127
3186
  return {
3128
3187
  backend: "omp",
3129
3188
  installed: "yes",
3130
3189
  enabled: "n/a",
3131
3190
  method: "extension",
3132
- location: path16__default.relative(projectDir, extPath)
3191
+ location: path15__default.relative(projectDir, extPath)
3133
3192
  };
3134
3193
  }
3135
3194
  return {
@@ -3150,7 +3209,7 @@ function resolveDriver(driver) {
3150
3209
  throw new Error(`unknown driver: ${driver} (expected: claude-code | omp | codex | all)`);
3151
3210
  }
3152
3211
  async function runInstall(opts) {
3153
- const projectDir = path16__default.resolve(opts.projectDir);
3212
+ const projectDir = path15__default.resolve(opts.projectDir);
3154
3213
  const targets = resolveDriver(opts.driver);
3155
3214
  let exitCode = 0;
3156
3215
  if (targets.includes("claude-code")) {
@@ -3205,7 +3264,7 @@ async function runInstall(opts) {
3205
3264
  return exitCode;
3206
3265
  }
3207
3266
  async function runUninstall(opts) {
3208
- const projectDir = path16__default.resolve(opts.projectDir);
3267
+ const projectDir = path15__default.resolve(opts.projectDir);
3209
3268
  const targets = resolveDriver(opts.driver);
3210
3269
  let exitCode = 0;
3211
3270
  if (targets.includes("claude-code")) {
@@ -3242,7 +3301,7 @@ async function runUninstall(opts) {
3242
3301
  return exitCode;
3243
3302
  }
3244
3303
  async function runToggle(opts, action) {
3245
- const projectDir = path16__default.resolve(opts.projectDir);
3304
+ const projectDir = path15__default.resolve(opts.projectDir);
3246
3305
  const requestedAll = opts.driver === "all";
3247
3306
  const targets = resolveDriver(opts.driver);
3248
3307
  if (!requestedAll) {
@@ -3277,7 +3336,7 @@ async function runToggle(opts, action) {
3277
3336
  return exitCode;
3278
3337
  }
3279
3338
  async function runStatus(opts) {
3280
- const projectDir = path16__default.resolve(opts.projectDir);
3339
+ const projectDir = path15__default.resolve(opts.projectDir);
3281
3340
  const targets = resolveDriver(opts.driver);
3282
3341
  const rows = [];
3283
3342
  let exitCode = 0;
@@ -3348,7 +3407,7 @@ async function runHook(event) {
3348
3407
  await plugin.shutdown();
3349
3408
  return;
3350
3409
  }
3351
- const store = new PluginStore(path16__default.join(projectDir, ".skaile", "plugin-state.json"));
3410
+ const store = new PluginStore(path15__default.join(projectDir, ".skaile", "plugin-state.json"));
3352
3411
  await store.load();
3353
3412
  const status4 = store.get("connector:status");
3354
3413
  if (status4 && typeof status4 === "object" && Object.keys(status4).length > 0) {
@@ -3413,7 +3472,7 @@ function makePresetCommand() {
3413
3472
  cmd.command("init [name]").description("Scaffold a new .preset.yaml file").option("--dir <path>", "Output directory", process.cwd()).action(async (name, opts) => {
3414
3473
  const presetName = name ?? "my-preset";
3415
3474
  const filename = `${presetName}.preset.yaml`;
3416
- const outPath = path16__default.join(path16__default.resolve(opts.dir), filename);
3475
+ const outPath = path15__default.join(path15__default.resolve(opts.dir), filename);
3417
3476
  if (existsSync(outPath)) {
3418
3477
  logErr(`File already exists: ${outPath}`);
3419
3478
  logInfo("Choose a different name or remove the existing file.");
@@ -3427,7 +3486,7 @@ function makePresetCommand() {
3427
3486
  logInfo(` skaile preset validate ${filename}`);
3428
3487
  });
3429
3488
  cmd.command("validate <path>").description("Validate a preset YAML file (schema + cycles + nesting depth)").action(async (filePath) => {
3430
- const resolved = path16__default.resolve(filePath);
3489
+ const resolved = path15__default.resolve(filePath);
3431
3490
  if (!existsSync(resolved)) {
3432
3491
  logErr(`File not found: ${resolved}`);
3433
3492
  process.exit(1);
@@ -3453,7 +3512,7 @@ function makePresetCommand() {
3453
3512
  logInfo(`Nested preset refs: ${nestedRefs.length} (depth validated at apply-time)`);
3454
3513
  }
3455
3514
  const { detectCycles } = await import('../discovery/index.js');
3456
- const presetRef = path16__default.basename(resolved, ".preset.yaml");
3515
+ const presetRef = path15__default.basename(resolved, ".preset.yaml");
3457
3516
  const edges = [];
3458
3517
  for (const item of preset.items) {
3459
3518
  if (item.ref) {
@@ -3577,8 +3636,8 @@ function makeInstallCommand() {
3577
3636
  const spinner6 = p5.spinner();
3578
3637
  spinner6.start(`Installing ${ref}`);
3579
3638
  try {
3580
- const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-S6FK4N4S.js');
3581
- const catalog = await openCatalogSource2({ projectDir: path16__default.resolve(opts.projectDir) });
3639
+ const { openCatalogSource: openCatalogSource2, openLibrary: openLibrary2 } = await import('../open-library-T6RXQJTQ.js');
3640
+ const catalog = await openCatalogSource2({ projectDir: path15__default.resolve(opts.projectDir) });
3582
3641
  if (!supportsInstallManifest(catalog)) {
3583
3642
  throw new Error(
3584
3643
  "pointer-only install (skaile install <ref>) requires a tRPC-framed Catalog. The configured catalog uses REST framing, which does not serve install manifests. Set catalog.url to https://skaile.store, or catalog.framing: trpc, in ~/.skaile/config.yaml."
@@ -3608,7 +3667,7 @@ function makeInstallCommand() {
3608
3667
  return;
3609
3668
  }
3610
3669
  const am2 = new AssetManager({
3611
- projectDir: path16__default.resolve(opts.projectDir),
3670
+ projectDir: path15__default.resolve(opts.projectDir),
3612
3671
  driverTarget: opts.target
3613
3672
  });
3614
3673
  const spinner5 = p5.spinner();
@@ -3647,7 +3706,7 @@ function makeInstallCommand() {
3647
3706
  }
3648
3707
  function makeCheckCommand() {
3649
3708
  return new Command("check").description("Check for unmet requirements").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
3650
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
3709
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
3651
3710
  const issues = am2.doctor();
3652
3711
  if (issues.length === 0) {
3653
3712
  logOk("All dependencies satisfied.");
@@ -3664,10 +3723,10 @@ function makeCheckCommand() {
3664
3723
  function makeCleanCommand() {
3665
3724
  return new Command("clean").description("Remove all skaile-managed assets from the workspace").option("--all", "Full reset: also remove history, patches, repos, and lock file").option("--dry-run", "Show what would be removed without doing it").option("-y, --yes", "Skip confirmation prompt").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").action(async (opts) => {
3666
3725
  const am2 = new AssetManager({
3667
- projectDir: path16__default.resolve(opts.projectDir),
3726
+ projectDir: path15__default.resolve(opts.projectDir),
3668
3727
  driverTarget: opts.target
3669
3728
  });
3670
- const lock = readLock(path16__default.resolve(opts.projectDir, "skaile.lock.yaml"));
3729
+ const lock = readLock(path15__default.resolve(opts.projectDir, "skaile.lock.yaml"));
3671
3730
  if (!lock || Object.keys(lock.assets).length === 0) {
3672
3731
  logInfo("Nothing to clean (no skaile-managed assets found).");
3673
3732
  return;
@@ -3720,14 +3779,14 @@ function makeCleanCommand() {
3720
3779
  }
3721
3780
  function makeRebuildCommand() {
3722
3781
  return new Command("rebuild").description("Re-snapshot inline-snapshot composition items and bump prompt version").argument("[agent]", "Agent name or path (defaults to current project agent)").option("--project-dir <dir>", "Project directory", process.cwd()).action(async (agentArg, opts) => {
3723
- const projectDir = path16__default.resolve(opts.projectDir);
3782
+ const projectDir = path15__default.resolve(opts.projectDir);
3724
3783
  let agentDir;
3725
3784
  if (agentArg) {
3726
3785
  if (agentArg.includes("/") || agentArg.includes("\\")) {
3727
- agentDir = path16__default.resolve(projectDir, agentArg);
3786
+ agentDir = path15__default.resolve(projectDir, agentArg);
3728
3787
  } else {
3729
3788
  const resolved = resolveAgentDir(projectDir);
3730
- agentDir = resolved ?? path16__default.resolve(projectDir, agentArg);
3789
+ agentDir = resolved ?? path15__default.resolve(projectDir, agentArg);
3731
3790
  }
3732
3791
  } else {
3733
3792
  const resolved = resolveAgentDir(projectDir);
@@ -3788,7 +3847,7 @@ function makeFlowEventHandler() {
3788
3847
  if (n.status === "running") {
3789
3848
  process.stdout.write(` ${S.dim("\u2192")} ${id}`);
3790
3849
  } else if (n.status === "complete") {
3791
- process.stdout.write(` ${pc6.green("\u2713")}
3850
+ process.stdout.write(` ${pc5.green("\u2713")}
3792
3851
  `);
3793
3852
  } else if (n.status === "skipped") {
3794
3853
  process.stdout.write(` ${S.dim("\u21B7 skipped")}
@@ -3805,7 +3864,7 @@ function makeFlowEventHandler() {
3805
3864
  }
3806
3865
  function makeRunCommand() {
3807
3866
  const cmd = new Command("run").description("Start a flow or run a single-shot text prompt").argument("[flow-id-or-text...]", "Flow ID or text prompt").option("--project-dir <path>", "Project directory", process.cwd()).option("--driver <name>", "Driver backend (claude-sdk, codex, omp)").option("--provider <name>", "LLM provider").option("--model <name>", "Model override").option("--label <label>", "Human-readable session label").option("--dry-run", "Print plan without executing").option("--skill <name>", "Skill name (for single-shot mode)").action(async (positional, opts) => {
3808
- const projectDir = path16__default.resolve(opts.projectDir);
3867
+ const projectDir = path15__default.resolve(opts.projectDir);
3809
3868
  const cliDriver = opts.driver;
3810
3869
  const dryRun = opts.dryRun ?? false;
3811
3870
  let flowId = positional[0];
@@ -3859,15 +3918,15 @@ function makeRunCommand() {
3859
3918
  let flowPath;
3860
3919
  let dir = projectDir;
3861
3920
  for (let i = 0; i < 6; i++) {
3862
- const candidate = path16__default.join(dir, "ai-assets");
3921
+ const candidate = path15__default.join(dir, "ai-assets");
3863
3922
  if (fs10__default.existsSync(candidate)) {
3864
3923
  for (const domain of fs10__default.readdirSync(candidate)) {
3865
- const p_ = path16__default.join(candidate, domain, "flows", `${flowId}.flow.yaml`);
3924
+ const p_ = path15__default.join(candidate, domain, "flows", `${flowId}.flow.yaml`);
3866
3925
  if (fs10__default.existsSync(p_)) {
3867
3926
  flowPath = p_;
3868
3927
  break;
3869
3928
  }
3870
- const legacy = path16__default.join(candidate, domain, "flows", `${flowId}.json`);
3929
+ const legacy = path15__default.join(candidate, domain, "flows", `${flowId}.json`);
3871
3930
  if (fs10__default.existsSync(legacy)) {
3872
3931
  flowPath = legacy;
3873
3932
  break;
@@ -3875,16 +3934,16 @@ function makeRunCommand() {
3875
3934
  }
3876
3935
  break;
3877
3936
  }
3878
- dir = path16__default.dirname(dir);
3937
+ dir = path15__default.dirname(dir);
3879
3938
  }
3880
3939
  if (!flowPath) {
3881
3940
  for (const domain of fs10__default.readdirSync(AI_RESOURCES)) {
3882
- const p_ = path16__default.join(AI_RESOURCES, domain, "flows", `${flowId}.flow.yaml`);
3941
+ const p_ = path15__default.join(AI_RESOURCES, domain, "flows", `${flowId}.flow.yaml`);
3883
3942
  if (fs10__default.existsSync(p_)) {
3884
3943
  flowPath = p_;
3885
3944
  break;
3886
3945
  }
3887
- const legacy = path16__default.join(AI_RESOURCES, domain, "flows", `${flowId}.json`);
3946
+ const legacy = path15__default.join(AI_RESOURCES, domain, "flows", `${flowId}.json`);
3888
3947
  if (fs10__default.existsSync(legacy)) {
3889
3948
  flowPath = legacy;
3890
3949
  break;
@@ -3918,7 +3977,7 @@ function makeRunCommand() {
3918
3977
  }
3919
3978
  function makeResumeCommand() {
3920
3979
  const cmd = new Command("resume").description("Resume current session").option("--project-dir <path>", "Project directory", process.cwd()).option("--session <run-id>", "Target session by runId").option("--dry-run", "Print plan without executing").action(async (opts) => {
3921
- const projectDir = path16__default.resolve(opts.projectDir);
3980
+ const projectDir = path15__default.resolve(opts.projectDir);
3922
3981
  const sessionId = opts.session;
3923
3982
  const dryRun = opts.dryRun ?? false;
3924
3983
  const session = sessionId ? await loadSessionById(projectDir, sessionId) : await loadSession(projectDir);
@@ -3945,14 +4004,14 @@ function makeResumeCommand() {
3945
4004
  }
3946
4005
  function makeStatusCommand() {
3947
4006
  return new Command("status").description("Show current session state").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
3948
- const projectDir = path16__default.resolve(opts.projectDir);
4007
+ const projectDir = path15__default.resolve(opts.projectDir);
3949
4008
  const session = await loadSession(projectDir);
3950
4009
  if (!session) {
3951
4010
  logInfo("No active session.");
3952
4011
  return;
3953
4012
  }
3954
4013
  const age = Math.round((Date.now() - new Date(session.updatedAt).getTime()) / 1e3);
3955
- const statusColor = session.status === "complete" ? pc6.green : session.status === "failed" ? pc6.red : session.status === "running" ? pc6.cyan : pc6.yellow;
4014
+ const statusColor = session.status === "complete" ? pc5.green : session.status === "failed" ? pc5.red : session.status === "running" ? pc5.cyan : pc5.yellow;
3956
4015
  console.log();
3957
4016
  console.log(` ${S.label("Flow:")} ${S.heading(session.flowId)}`);
3958
4017
  console.log(` ${S.label("Run ID:")} ${session.runId.slice(0, 8)}`);
@@ -3970,7 +4029,7 @@ function makeStatusCommand() {
3970
4029
  }
3971
4030
  function makeClearCommand() {
3972
4031
  return new Command("clear").description("Unset current session pointer").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
3973
- const projectDir = path16__default.resolve(opts.projectDir);
4032
+ const projectDir = path15__default.resolve(opts.projectDir);
3974
4033
  await clearSession(projectDir);
3975
4034
  logOk("Session cleared.");
3976
4035
  });
@@ -3980,7 +4039,7 @@ function makeReplCommand() {
3980
4039
  const { findWorkspaceRoot } = await import('../core/index.js');
3981
4040
  const { startRepl } = await import('../tui/index.js');
3982
4041
  const os = await import('os');
3983
- const userCwd = path16__default.resolve(opts.projectDir ?? process.cwd());
4042
+ const userCwd = path15__default.resolve(opts.projectDir ?? process.cwd());
3984
4043
  const workspaceRoot = findWorkspaceRoot(userCwd);
3985
4044
  let projectDir;
3986
4045
  let agentCwd;
@@ -4002,12 +4061,12 @@ function makeReplCommand() {
4002
4061
  p5.cancel("Cancelled.");
4003
4062
  process.exit(0);
4004
4063
  }
4005
- const tmpDir = fs10__default.mkdtempSync(path16__default.join(os.tmpdir(), "skaile-repl-"));
4064
+ const tmpDir = fs10__default.mkdtempSync(path15__default.join(os.tmpdir(), "skaile-repl-"));
4006
4065
  projectDir = tmpDir;
4007
4066
  agentCwd = userCwd;
4008
4067
  logOk(`Temporary workspace: ${S.cmd(tmpDir)}`);
4009
4068
  if (!driverOverride) {
4010
- const claudeDir = path16__default.join(os.homedir(), ".claude");
4069
+ const claudeDir = path15__default.join(os.homedir(), ".claude");
4011
4070
  if (fs10__default.existsSync(claudeDir)) {
4012
4071
  driverOverride = "claude-sdk";
4013
4072
  logInfo(`Detected ${S.cmd("~/.claude")} \u2192 using ${S.cmd("claude-sdk")} backend`);
@@ -4055,7 +4114,7 @@ function makeServeCommand() {
4055
4114
  async function runCompileTest(opts) {
4056
4115
  const { logOk: logOk2, logErr: logErr2, logInfo: logInfo2, S: S2 } = await import('../helpers-I3SREIC3.js');
4057
4116
  const { tmpdir } = await import('os');
4058
- const { dirname: dirname3, join: join4, resolve: resolve3 } = await import('path');
4117
+ const { dirname: dirname3, join: join5, resolve: resolve4 } = await import('path');
4059
4118
  const { fileURLToPath: fileURLToPath2 } = await import('url');
4060
4119
  const { unlinkSync, existsSync: existsSync11 } = await import('fs');
4061
4120
  const { spawn } = await import('child_process');
@@ -4067,9 +4126,9 @@ async function runCompileTest(opts) {
4067
4126
  process.exitCode = 2;
4068
4127
  return;
4069
4128
  }
4070
- const outfile = join4(tmpdir(), `skaile-compile-test-${Date.now()}`);
4129
+ const outfile = join5(tmpdir(), `skaile-compile-test-${Date.now()}`);
4071
4130
  const __thisFile = fileURLToPath2(import.meta.url);
4072
- const entryPoint = resolve3(dirname3(__thisFile), "..", "index.ts");
4131
+ const entryPoint = resolve4(dirname3(__thisFile), "..", "index.ts");
4073
4132
  logInfo2(`Building compiled binary...`);
4074
4133
  logInfo2(`Entry: ${S2.dim(entryPoint)}`);
4075
4134
  logInfo2(`Output: ${S2.dim(outfile)}`);
@@ -4145,7 +4204,7 @@ function formatEntries(entries, opts = {}) {
4145
4204
  lines.push(...renderEntryLines(e));
4146
4205
  }
4147
4206
  if (opts.nextCursor) {
4148
- lines.push(pc6.dim(`... more available. Use --cursor ${opts.nextCursor} to page back.`));
4207
+ lines.push(pc5.dim(`... more available. Use --cursor ${opts.nextCursor} to page back.`));
4149
4208
  }
4150
4209
  return lines.join("\n");
4151
4210
  }
@@ -4166,9 +4225,9 @@ function renderEntryLines(e) {
4166
4225
  return lines;
4167
4226
  }
4168
4227
  function formatLine(e) {
4169
- const ts = pc6.dim(`[${formatTime(e.timestamp)}]`);
4228
+ const ts = pc5.dim(`[${formatTime(e.timestamp)}]`);
4170
4229
  const lvl = colorLevel(e.level);
4171
- const src = pc6.cyan(`[${formatSource(e.source)}]`);
4230
+ const src = pc5.cyan(`[${formatSource(e.source)}]`);
4172
4231
  return `${ts} ${lvl} ${src} ${e.message}`;
4173
4232
  }
4174
4233
  function formatTime(iso) {
@@ -4187,13 +4246,13 @@ function formatSource(src) {
4187
4246
  function colorLevel(level) {
4188
4247
  switch (level) {
4189
4248
  case "error":
4190
- return pc6.red("ERROR");
4249
+ return pc5.red("ERROR");
4191
4250
  case "warn":
4192
- return pc6.yellow("WARN ");
4251
+ return pc5.yellow("WARN ");
4193
4252
  case "info":
4194
- return pc6.green("INFO ");
4253
+ return pc5.green("INFO ");
4195
4254
  case "debug":
4196
- return pc6.dim("DEBUG");
4255
+ return pc5.dim("DEBUG");
4197
4256
  default:
4198
4257
  return String(level).toUpperCase();
4199
4258
  }
@@ -4201,15 +4260,15 @@ function colorLevel(level) {
4201
4260
  function formatData(data) {
4202
4261
  const oneLine = JSON.stringify(data);
4203
4262
  if (oneLine.length <= 120) {
4204
- return [` ${pc6.dim("> data:")} ${oneLine}`];
4263
+ return [` ${pc5.dim("> data:")} ${oneLine}`];
4205
4264
  }
4206
4265
  const pretty = JSON.stringify(data, null, 2);
4207
- return [` ${pc6.dim("> data:")}`, ...pretty.split("\n").map((l) => ` ${l}`)];
4266
+ return [` ${pc5.dim("> data:")}`, ...pretty.split("\n").map((l) => ` ${l}`)];
4208
4267
  }
4209
4268
  function formatError(err) {
4210
- const head = ` ${pc6.dim("> error:")} ${pc6.red(err.name)}: ${err.message}`;
4269
+ const head = ` ${pc5.dim("> error:")} ${pc5.red(err.name)}: ${err.message}`;
4211
4270
  if (!err.stack) return [head];
4212
- const stackLines = err.stack.split("\n").filter((l) => l.trim().length > 0).map((l) => ` ${pc6.dim(l)}`);
4271
+ const stackLines = err.stack.split("\n").filter((l) => l.trim().length > 0).map((l) => ` ${pc5.dim(l)}`);
4213
4272
  return [head, ...stackLines];
4214
4273
  }
4215
4274
 
@@ -4372,19 +4431,19 @@ function buildTailSelect(q) {
4372
4431
  return { sql, params };
4373
4432
  }
4374
4433
  function sleepUnlessAborted(ms, signal) {
4375
- return new Promise((resolve3) => {
4434
+ return new Promise((resolve4) => {
4376
4435
  if (signal?.aborted) {
4377
- resolve3();
4436
+ resolve4();
4378
4437
  return;
4379
4438
  }
4380
4439
  const timer = setTimeout(() => {
4381
4440
  signal?.removeEventListener("abort", onAbort);
4382
- resolve3();
4441
+ resolve4();
4383
4442
  }, ms);
4384
4443
  const onAbort = () => {
4385
4444
  clearTimeout(timer);
4386
4445
  signal?.removeEventListener("abort", onAbort);
4387
- resolve3();
4446
+ resolve4();
4388
4447
  };
4389
4448
  signal?.addEventListener("abort", onAbort, { once: true });
4390
4449
  });
@@ -4461,7 +4520,7 @@ async function remoteTail(opts) {
4461
4520
  ]
4462
4521
  });
4463
4522
  const filter = makeFilter(opts.query);
4464
- return new Promise((resolve3, reject) => {
4523
+ return new Promise((resolve4, reject) => {
4465
4524
  let settled = false;
4466
4525
  const finish = (err) => {
4467
4526
  if (settled) return;
@@ -4472,11 +4531,11 @@ async function remoteTail(opts) {
4472
4531
  }
4473
4532
  opts.signal?.removeEventListener("abort", onAbort);
4474
4533
  if (err) reject(err);
4475
- else resolve3();
4534
+ else resolve4();
4476
4535
  };
4477
4536
  const onAbort = () => finish();
4478
4537
  if (opts.signal?.aborted) {
4479
- resolve3();
4538
+ resolve4();
4480
4539
  return;
4481
4540
  }
4482
4541
  opts.signal?.addEventListener("abort", onAbort, { once: true });
@@ -4530,7 +4589,7 @@ function resolveMode(opts) {
4530
4589
  if (opts.forceLocal && opts.forceRemote) {
4531
4590
  throw new Error("Cannot use both --local and --remote");
4532
4591
  }
4533
- const startDir = path16__default.resolve(opts.projectDir ?? process.cwd());
4592
+ const startDir = path15__default.resolve(opts.projectDir ?? process.cwd());
4534
4593
  const localDb = findLogsDb(startDir);
4535
4594
  if (opts.forceLocal) {
4536
4595
  if (!localDb) {
@@ -4563,14 +4622,14 @@ function resolveMode(opts) {
4563
4622
  function findLogsDb(startDir) {
4564
4623
  let dir = startDir;
4565
4624
  for (let i = 0; i < MAX_WALK_LEVELS; i++) {
4566
- const candidate = path16__default.join(dir, ".skaile", "logs.db");
4625
+ const candidate = path15__default.join(dir, ".skaile", "logs.db");
4567
4626
  if (existsSync(candidate)) {
4568
4627
  try {
4569
4628
  if (statSync(candidate).isFile()) return candidate;
4570
4629
  } catch {
4571
4630
  }
4572
4631
  }
4573
- const parent = path16__default.dirname(dir);
4632
+ const parent = path15__default.dirname(dir);
4574
4633
  if (parent === dir) return void 0;
4575
4634
  dir = parent;
4576
4635
  }
@@ -4596,7 +4655,7 @@ function readApiToken() {
4596
4655
  }
4597
4656
  function readGlobalSettings() {
4598
4657
  try {
4599
- const settingsPath = path16__default.join(homedir(), ".skaile", "settings.json");
4658
+ const settingsPath = path15__default.join(homedir(), ".skaile", "settings.json");
4600
4659
  if (!existsSync(settingsPath)) return {};
4601
4660
  return JSON.parse(readFileSync(settingsPath, "utf8"));
4602
4661
  } catch {
@@ -4744,7 +4803,7 @@ function parsePositiveInt(value, flag) {
4744
4803
  function makeSessionCommand() {
4745
4804
  const cmd = new Command("session").description("Manage sessions");
4746
4805
  cmd.command("list").description("List all sessions for a project").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
4747
- const projectDir = path16__default.resolve(opts.projectDir);
4806
+ const projectDir = path15__default.resolve(opts.projectDir);
4748
4807
  const sessions = await listSessions(projectDir);
4749
4808
  const current = await loadSession(projectDir);
4750
4809
  if (sessions.length === 0) {
@@ -4760,10 +4819,10 @@ function makeSessionCommand() {
4760
4819
  console.log(` ${S.dim(" ")} ${S.rule(75)}`);
4761
4820
  for (const s of sessions) {
4762
4821
  const isCurrent = current?.runId === s.runId;
4763
- const marker = isCurrent ? pc6.cyan(" \u25B6 ") : " ";
4822
+ const marker = isCurrent ? pc5.cyan(" \u25B6 ") : " ";
4764
4823
  const age = Math.round((Date.now() - new Date(s.updatedAt).getTime()) / 6e4);
4765
4824
  const label = (s.label ?? "").padEnd(20);
4766
- const statusColor = s.status === "complete" ? pc6.green : s.status === "failed" ? pc6.red : s.status === "running" ? pc6.cyan : pc6.dim;
4825
+ const statusColor = s.status === "complete" ? pc5.green : s.status === "failed" ? pc5.red : s.status === "running" ? pc5.cyan : pc5.dim;
4767
4826
  const status4 = statusColor((s.status ?? "").padEnd(12));
4768
4827
  console.log(
4769
4828
  `${marker} ${S.dim(s.runId.slice(0, 8))} ${s.flowId.padEnd(20)} ${label} ${status4} ${S.dim(`${age}m ago`)}`
@@ -4772,7 +4831,7 @@ function makeSessionCommand() {
4772
4831
  console.log();
4773
4832
  });
4774
4833
  cmd.command("show <run-id>").description("Show a specific session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
4775
- const projectDir = path16__default.resolve(opts.projectDir);
4834
+ const projectDir = path15__default.resolve(opts.projectDir);
4776
4835
  const session = await loadSessionById(projectDir, runId);
4777
4836
  if (!session) {
4778
4837
  logErr(`Session not found: ${runId}`);
@@ -4781,12 +4840,12 @@ function makeSessionCommand() {
4781
4840
  console.log(JSON.stringify(session, null, 2));
4782
4841
  });
4783
4842
  cmd.command("switch <run-id>").description("Switch the current session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
4784
- const projectDir = path16__default.resolve(opts.projectDir);
4843
+ const projectDir = path15__default.resolve(opts.projectDir);
4785
4844
  await setCurrentSession(projectDir, runId);
4786
4845
  logOk(`Switched to session: ${S.dim(runId.slice(0, 8))}`);
4787
4846
  });
4788
4847
  cmd.command("delete <run-id>").description("Delete a session").option("--project-dir <path>", "Project directory", process.cwd()).action(async (runId, opts) => {
4789
- const projectDir = path16__default.resolve(opts.projectDir);
4848
+ const projectDir = path15__default.resolve(opts.projectDir);
4790
4849
  await deleteSession(projectDir, runId);
4791
4850
  logOk(`Deleted session: ${S.dim(runId.slice(0, 8))}`);
4792
4851
  });
@@ -4795,11 +4854,11 @@ function makeSessionCommand() {
4795
4854
  return cmd;
4796
4855
  }
4797
4856
  var SYNC_ICONS = {
4798
- synced: pc6.green("synced"),
4799
- outdated: pc6.yellow("outdated"),
4800
- local: pc6.cyan("local"),
4801
- error: pc6.red("error"),
4802
- unknown: pc6.dim("\u2014")
4857
+ synced: pc5.green("synced"),
4858
+ outdated: pc5.yellow("outdated"),
4859
+ local: pc5.cyan("local"),
4860
+ error: pc5.red("error"),
4861
+ unknown: pc5.dim("\u2014")
4803
4862
  };
4804
4863
  function showOverview(am2) {
4805
4864
  const result = am2.overview();
@@ -4812,25 +4871,25 @@ function showOverview(am2) {
4812
4871
  if (result.repos.length > 0) {
4813
4872
  console.log();
4814
4873
  for (const r of result.repos) {
4815
- const icon = r.error ? pc6.red("!") : r.upToDate ? pc6.green("\u2713") : pc6.yellow("\u2193");
4816
- const status4 = r.error ? pc6.red(r.error) : r.upToDate ? pc6.green("up to date") : pc6.yellow(`${r.behind} behind`);
4817
- console.log(` ${icon} ${S.cmd(r.name)} ${pc6.dim(`[${r.kind}]`)} ${status4}`);
4874
+ const icon = r.error ? pc5.red("!") : r.upToDate ? pc5.green("\u2713") : pc5.yellow("\u2193");
4875
+ const status4 = r.error ? pc5.red(r.error) : r.upToDate ? pc5.green("up to date") : pc5.yellow(`${r.behind} behind`);
4876
+ console.log(` ${icon} ${S.cmd(r.name)} ${pc5.dim(`[${r.kind}]`)} ${status4}`);
4818
4877
  }
4819
4878
  }
4820
4879
  const nameW = Math.max(4, ...[...result.byDomain.values()].flat().map((e) => e.name.length));
4821
4880
  const kindW = 8;
4822
4881
  for (const [domain, entries] of result.byDomain) {
4823
4882
  console.log();
4824
- console.log(` ${S.heading(domain)} ${pc6.dim(`(${entries.length})`)}`);
4883
+ console.log(` ${S.heading(domain)} ${pc5.dim(`(${entries.length})`)}`);
4825
4884
  console.log(` ${S.rule(nameW + kindW + 20)}`);
4826
4885
  for (const e of entries) {
4827
4886
  const sync = SYNC_ICONS[e.syncStatus] ?? SYNC_ICONS.unknown;
4828
- const ver = e.version ? pc6.dim(` v${e.version}`) : "";
4887
+ const ver = e.version ? pc5.dim(` v${e.version}`) : "";
4829
4888
  console.log(` ${kindColorPad(e.kind, kindW)} ${S.cmd(e.name.padEnd(nameW))} ${sync}${ver}`);
4830
4889
  }
4831
4890
  }
4832
4891
  console.log();
4833
- console.log(` ${pc6.dim(`${result.total} assets deployed`)}`);
4892
+ console.log(` ${pc5.dim(`${result.total} assets deployed`)}`);
4834
4893
  console.log();
4835
4894
  }
4836
4895
  function showAsset(am2, kind, name) {
@@ -4849,7 +4908,7 @@ function showAsset(am2, kind, name) {
4849
4908
  function makeShowCommand() {
4850
4909
  return new Command("show").description("Show deployed assets overview, or print asset content").argument("[kind]", "Asset kind (skill, agent, prompt, flow, bundle, contract)").argument("[name]", "Asset name").option("--project-dir <path>", "Project directory", process.cwd()).option("--target <agent>", "Agent framework", "claude-code").action((kind, name, opts) => {
4851
4910
  const am2 = new AssetManager({
4852
- projectDir: path16__default.resolve(opts.projectDir),
4911
+ projectDir: path15__default.resolve(opts.projectDir),
4853
4912
  driverTarget: opts.target
4854
4913
  });
4855
4914
  if (!kind) {
@@ -4867,16 +4926,139 @@ function makeShowCommand() {
4867
4926
  }
4868
4927
  });
4869
4928
  }
4870
- var DEPRECATION_MSG = "`skaile source` has been removed. Use `skaile library` instead. (Underlying data was migrated; columns renamed.)";
4929
+
4930
+ // cli/src/commands/source-manifest.ts
4931
+ var NOT_WIRED_MSG = "`skaile source manifest *` is scaffolded but not yet wired. Server-side endpoint (`POST /sources/<id>/manifest`) lands in a follow-up PR.";
4932
+ function notWired2(verb) {
4933
+ logErr(`${NOT_WIRED_MSG} (verb: source manifest ${verb})`);
4934
+ process.exit(2);
4935
+ }
4936
+ function addSourceManifestCommands(src) {
4937
+ const manifest = src.command("manifest").description("Sidecar manifest lifecycle for a source");
4938
+ manifest.command("init <src>").description("Start a sidecar manifest for a source").action(() => notWired2("init"));
4939
+ manifest.command("edit <src>").description("Open the sidecar manifest in $EDITOR").action(() => notWired2("edit"));
4940
+ manifest.command("rebuild <src>").description("Re-derive the manifest after an upstream change").option("--merge", "Merge with existing entries instead of overwriting", false).action(() => notWired2("rebuild"));
4941
+ manifest.command("verify <src>").description("Verify hashes, deps, and schema").option("--strict", "Fail on advisory checks", false).action(() => notWired2("verify"));
4942
+ manifest.command("publish <src>").description("Register the manifest in the store (provenance=curator)").action(() => notWired2("publish"));
4943
+ manifest.command("propose <src>").description("Open a PR to upstream with the sidecar manifest").action(() => notWired2("propose"));
4944
+ manifest.command("yank <src>").description("Retract a published manifest from the remote store").option("--version <v>", "Version to yank").action(() => notWired2("yank"));
4945
+ }
4946
+
4947
+ // cli/src/commands/source.ts
4948
+ function sourcesDir() {
4949
+ return path15.join(skaileHomeDir(), "sources");
4950
+ }
4951
+ function deriveSlug(url) {
4952
+ return url.replace(/\.git$/, "").split(/[/:]/).pop() ?? "source";
4953
+ }
4954
+ function isSourceRow(lib) {
4955
+ return lib.path.startsWith(sourcesDir());
4956
+ }
4871
4957
  function makeSourceCommand() {
4872
- const cmd = new Command("source").description("[REMOVED] use `skaile library` instead").action(() => {
4873
- logErr(DEPRECATION_MSG);
4958
+ const cmd = new Command("source").description(
4959
+ "Manage github sources (third-party repos of AI assets)"
4960
+ );
4961
+ cmd.command("add <git-url>").description("Clone a github repo into ~/.skaile/sources/<slug> and register it").option("--name <slug>", "Override the derived slug").action(async (url, opts) => {
4962
+ const slug = opts.name ?? deriveSlug(url);
4963
+ const dest = path15.join(sourcesDir(), slug);
4964
+ const clone = spawnSync("git", ["clone", url, dest], { stdio: "inherit" });
4965
+ if (clone.status !== 0) {
4966
+ logErr(`git clone failed for ${url}`);
4967
+ process.exit(1);
4968
+ }
4969
+ const { manager, close } = await openLibraryManager();
4970
+ try {
4971
+ await manager.addLibrary({
4972
+ name: slug,
4973
+ path: dest,
4974
+ backend: "git",
4975
+ backendConfig: { url, branch: "main", authHint: "ssh" },
4976
+ ownership: "reader"
4977
+ });
4978
+ logOk(`Source "${slug}" added at ${dest}.`);
4979
+ } finally {
4980
+ close();
4981
+ }
4982
+ });
4983
+ cmd.command("list").description("List registered sources").option("--json", "Output as JSON").action(async (opts) => {
4984
+ const { manager, close } = await openLibraryManager();
4985
+ try {
4986
+ const all = await manager.listLibraries();
4987
+ const sources = all.filter(isSourceRow);
4988
+ if (opts.json) return console.log(JSON.stringify(sources, null, 2));
4989
+ if (sources.length === 0) {
4990
+ logInfo("No sources registered. Run `skaile source add <git-url>` to start.");
4991
+ return;
4992
+ }
4993
+ console.log();
4994
+ console.log(S.heading(" Sources"));
4995
+ for (const s of sources) {
4996
+ console.log(` ${S.cmd(s.name.padEnd(20))} ${S.dim(s.path)}`);
4997
+ }
4998
+ console.log(`
4999
+ ${S.dim(`${sources.length} source(s)`)}
5000
+ `);
5001
+ } finally {
5002
+ close();
5003
+ }
5004
+ });
5005
+ cmd.command("show <name>").description("Show details for a source").action(async (name) => {
5006
+ const { manager, close } = await openLibraryManager();
5007
+ try {
5008
+ const s = await manager.requireLibrary(name);
5009
+ if (!isSourceRow(s)) {
5010
+ logErr(`"${name}" is a library, not a source \u2014 use \`skaile library show ${name}\`.`);
5011
+ process.exit(1);
5012
+ }
5013
+ console.log(JSON.stringify(s, null, 2));
5014
+ } finally {
5015
+ close();
5016
+ }
5017
+ });
5018
+ cmd.command("remove <name>").description("Unregister a source").option("--purge", "Also delete the clone directory from disk", false).action(async (name, opts) => {
5019
+ const { manager, close } = await openLibraryManager();
5020
+ try {
5021
+ const s = await manager.requireLibrary(name);
5022
+ if (!isSourceRow(s)) {
5023
+ logErr(`"${name}" is a library, not a source \u2014 use \`skaile library remove ${name}\`.`);
5024
+ process.exit(1);
5025
+ }
5026
+ await manager.removeLibrary(name, { purge: opts.purge });
5027
+ logOk(`Removed source "${name}".`);
5028
+ } finally {
5029
+ close();
5030
+ }
5031
+ });
5032
+ cmd.command("sync [name]").description("Re-fetch upstream changes for one or all sources").action(async (name) => {
5033
+ const { manager, close } = await openLibraryManager();
5034
+ try {
5035
+ const all = await manager.listLibraries();
5036
+ const targets = name ? all.filter((l) => l.name === name && isSourceRow(l)) : all.filter(isSourceRow);
5037
+ if (targets.length === 0) {
5038
+ logInfo(name ? `No source named "${name}".` : "No sources registered.");
5039
+ return;
5040
+ }
5041
+ for (const s of targets) {
5042
+ const res = await manager.driverFor(s.backend).pull(s);
5043
+ logOk(`${s.name}: pulled ${res.applied} change(s).`);
5044
+ }
5045
+ } finally {
5046
+ close();
5047
+ }
5048
+ });
5049
+ cmd.command("patch <ref>").description("Extract an asset for editing against the source").action((_ref) => {
5050
+ logErr(
5051
+ "`skaile source patch` is scaffolded but not yet wired. The patch flow lands in a follow-up PR."
5052
+ );
4874
5053
  process.exit(2);
4875
5054
  });
4876
- cmd.command("*", { hidden: true }).allowUnknownOption().action(() => {
4877
- logErr(DEPRECATION_MSG);
5055
+ cmd.command("propose <ref>").description("Open a PR with the patch against the source upstream").action((_ref) => {
5056
+ logErr(
5057
+ "`skaile source propose` is scaffolded but not yet wired. The propose flow lands in a follow-up PR."
5058
+ );
4878
5059
  process.exit(2);
4879
5060
  });
5061
+ addSourceManifestCommands(cmd);
4880
5062
  return cmd;
4881
5063
  }
4882
5064
  function makeStoreCommand() {
@@ -4886,10 +5068,10 @@ function makeStoreCommand() {
4886
5068
  if (opts.email) {
4887
5069
  const readline2 = await import('readline');
4888
5070
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
4889
- const password = await new Promise((resolve3) => {
5071
+ const password = await new Promise((resolve4) => {
4890
5072
  rl.question("Password: ", (answer) => {
4891
5073
  rl.close();
4892
- resolve3(answer);
5074
+ resolve4(answer);
4893
5075
  });
4894
5076
  });
4895
5077
  try {
@@ -4975,28 +5157,35 @@ function makeStoreCommand() {
4975
5157
  process.exit(1);
4976
5158
  }
4977
5159
  });
4978
- store.command("publish").description("Publish an asset version to the store").option("--ref <gitRef>", "Git ref to publish from", "HEAD").option("--register", "Register the asset first (for first-time publish)").option("--project-dir <path>", "Project directory", process.cwd()).action(async (opts) => {
4979
- const config = getStoreConfig();
4980
- if (!isStoreAuthenticated(config)) {
4981
- logErr("Not authenticated. Run: skaile store login");
4982
- process.exit(1);
4983
- }
4984
- try {
4985
- const me = await storeFetch(config, "/api/auth/me");
4986
- logInfo("Reading asset from current directory...");
4987
- const res = await storeFetch(config, `/api/assets/${me.slug}/TODO/publish`, {
4988
- method: "POST",
4989
- body: { gitRef: opts.ref }
4990
- });
4991
- console.log();
4992
- logOk(`Published ${S.brand(`@${res.publisher}/${res.slug}`)} v${res.version}`);
4993
- console.log(` ${S.label("Content hash")} ${S.dim(res.contentHash)}`);
4994
- console.log(` ${S.label("Signature")} ${S.dim(`${res.signature?.slice(0, 20)}...`)}`);
4995
- console.log();
4996
- } catch (e) {
4997
- logErr(e.message);
4998
- process.exit(1);
4999
- }
5160
+ store.command("mode <auto|local|remote>").description("Set the catalog resolution mode (not yet wired)").action((_mode) => {
5161
+ logErr(
5162
+ "`skaile store mode` is scaffolded but not yet wired. Store config lives at ~/.skaile/store/config.yaml."
5163
+ );
5164
+ process.exit(2);
5165
+ });
5166
+ store.command("search <query>").description("Search the aggregated catalog (not yet wired)").action((_query) => {
5167
+ logErr("`skaile store search` is scaffolded but not yet wired.");
5168
+ process.exit(2);
5169
+ });
5170
+ store.command("show <ref>").description("Show details + provenance for a manifest (not yet wired)").action((_ref) => {
5171
+ logErr("`skaile store show` is scaffolded but not yet wired.");
5172
+ process.exit(2);
5173
+ });
5174
+ store.command("favourite <ref>").description("Pin a ref to your favourites (not yet wired)").action((_ref) => {
5175
+ logErr("`skaile store favourite` is scaffolded but not yet wired.");
5176
+ process.exit(2);
5177
+ });
5178
+ store.command("unfavourite <ref>").description("Remove a ref from your favourites (not yet wired)").action((_ref) => {
5179
+ logErr("`skaile store unfavourite` is scaffolded but not yet wired.");
5180
+ process.exit(2);
5181
+ });
5182
+ store.command("sync").description("Refresh the local cache from the remote store (not yet wired)").action(() => {
5183
+ logErr("`skaile store sync` is scaffolded but not yet wired.");
5184
+ process.exit(2);
5185
+ });
5186
+ store.command("push").description("Push the local store to a git remote (not yet wired)").option("--remote <name>", "Git remote name", "origin").action(() => {
5187
+ logErr("`skaile store push` is scaffolded but not yet wired.");
5188
+ process.exit(2);
5000
5189
  });
5001
5190
  store.command("yank <version>").description("Yank (soft-delete) a published version").option("--asset <ref>", "Asset reference (@publisher/slug)").action(async (version, opts) => {
5002
5191
  const config = getStoreConfig();
@@ -5037,7 +5226,7 @@ function printTree(node, prefix = "", isLast = true) {
5037
5226
  }
5038
5227
  function makeTreeCommand() {
5039
5228
  return new Command("tree").description("Show full dependency tree").option("--project-dir <path>", "Project directory", process.cwd()).action((opts) => {
5040
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
5229
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
5041
5230
  const root = am2.tree();
5042
5231
  if (root.children.length === 0) {
5043
5232
  logInfo("No dependencies in lock file. Run `skaile install` first.");
@@ -5055,7 +5244,7 @@ function makeUpdateCommand() {
5055
5244
  try {
5056
5245
  const catalogSpinner = p5.spinner();
5057
5246
  catalogSpinner.start("Refreshing catalog cache");
5058
- const remote = await openCatalogSource({ projectDir: path16__default.resolve(opts.projectDir) });
5247
+ const remote = await openCatalogSource({ projectDir: path15__default.resolve(opts.projectDir) });
5059
5248
  const result2 = await remote.refresh();
5060
5249
  catalogSpinner.stop(
5061
5250
  `Catalog refreshed: ${S.heading(String(result2.assetsCached))} assets cached`
@@ -5067,7 +5256,7 @@ function makeUpdateCommand() {
5067
5256
  }
5068
5257
  }
5069
5258
  if (opts.catalogOnly) return;
5070
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
5259
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
5071
5260
  const spinner5 = p5.spinner();
5072
5261
  spinner5.start("Re-deploying assets");
5073
5262
  const result = await am2.install();
@@ -5113,7 +5302,7 @@ function findManifestCandidates(rootPath) {
5113
5302
  return;
5114
5303
  }
5115
5304
  for (const entry of entries) {
5116
- const fullPath = path16__default.join(dir, entry.name);
5305
+ const fullPath = path15__default.join(dir, entry.name);
5117
5306
  if (entry.isDirectory()) {
5118
5307
  if (!SKIP_DIRS.has(entry.name)) walk(fullPath);
5119
5308
  } else if (entry.isFile()) {
@@ -5135,7 +5324,7 @@ function parseMdFrontmatter(content) {
5135
5324
  return parse(fmMatch[1]);
5136
5325
  }
5137
5326
  function validateManifests(rootPath) {
5138
- const absRoot = path16__default.resolve(rootPath);
5327
+ const absRoot = path15__default.resolve(rootPath);
5139
5328
  if (!fs10__default.existsSync(absRoot)) {
5140
5329
  logErr(`Path does not exist: ${absRoot}`);
5141
5330
  return { total: 0, errors: 1, warnings: 0 };
@@ -5156,14 +5345,14 @@ function validateManifests(rootPath) {
5156
5345
  try {
5157
5346
  parsed = c.filePath.endsWith(".json") ? JSON.parse(content) : parse(content);
5158
5347
  } catch (e) {
5159
- const relPath2 = path16__default.relative(absRoot, c.filePath);
5348
+ const relPath2 = path15__default.relative(absRoot, c.filePath);
5160
5349
  logErr(`${relPath2} \u2014 parse error: ${e instanceof Error ? e.message : String(e)}`);
5161
5350
  errors++;
5162
5351
  continue;
5163
5352
  }
5164
5353
  }
5165
5354
  const provider = registry.getProvider(c.kind);
5166
- const relPath = path16__default.relative(absRoot, c.filePath);
5355
+ const relPath = path15__default.relative(absRoot, c.filePath);
5167
5356
  if (!provider) {
5168
5357
  logWarn(`${relPath} [${c.kind}] \u2014 kind "${c.kind}" is not registered, skipping validation`);
5169
5358
  warnings++;
@@ -5185,20 +5374,20 @@ function collectAssetVersions() {
5185
5374
  if (!fs10__default.existsSync(AI_RESOURCES)) return assets;
5186
5375
  const domains = fs10__default.readdirSync(AI_RESOURCES, { withFileTypes: true }).filter((d) => d.isDirectory() && !EXCLUDED_DOMAINS.has(d.name));
5187
5376
  for (const d of domains) {
5188
- const domainDir = path16__default.join(AI_RESOURCES, d.name);
5189
- const skillsDir = path16__default.join(domainDir, "skills");
5377
+ const domainDir = path15__default.join(AI_RESOURCES, d.name);
5378
+ const skillsDir = path15__default.join(domainDir, "skills");
5190
5379
  if (fs10__default.existsSync(skillsDir)) {
5191
5380
  collectSkillVersions(skillsDir, d.name, assets);
5192
5381
  }
5193
- const agentsDir = path16__default.join(domainDir, "agents");
5382
+ const agentsDir = path15__default.join(domainDir, "agents");
5194
5383
  if (fs10__default.existsSync(agentsDir)) {
5195
5384
  collectAgentVersions(agentsDir, d.name, assets);
5196
5385
  }
5197
- const flowsDir = path16__default.join(domainDir, "flows");
5386
+ const flowsDir = path15__default.join(domainDir, "flows");
5198
5387
  if (fs10__default.existsSync(flowsDir)) {
5199
5388
  for (const f of fs10__default.readdirSync(flowsDir)) {
5200
5389
  if (!f.endsWith(".flow.yaml")) continue;
5201
- const fp = path16__default.join(flowsDir, f);
5390
+ const fp = path15__default.join(flowsDir, f);
5202
5391
  const content = fs10__default.readFileSync(fp, "utf-8");
5203
5392
  const parsed = parse(content);
5204
5393
  assets.push({
@@ -5210,11 +5399,11 @@ function collectAssetVersions() {
5210
5399
  });
5211
5400
  }
5212
5401
  }
5213
- const promptsDir = path16__default.join(domainDir, "prompts");
5402
+ const promptsDir = path15__default.join(domainDir, "prompts");
5214
5403
  if (fs10__default.existsSync(promptsDir)) {
5215
5404
  for (const f of fs10__default.readdirSync(promptsDir)) {
5216
5405
  if (!f.endsWith(".prompt.md")) continue;
5217
- const fp = path16__default.join(promptsDir, f);
5406
+ const fp = path15__default.join(promptsDir, f);
5218
5407
  const content = fs10__default.readFileSync(fp, "utf-8");
5219
5408
  const fm = parseSkillFrontmatter(content);
5220
5409
  assets.push({
@@ -5232,8 +5421,8 @@ function collectAssetVersions() {
5232
5421
  function collectSkillVersions(dir, domain, out) {
5233
5422
  for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
5234
5423
  if (!entry.isDirectory()) continue;
5235
- const full = path16__default.join(dir, entry.name);
5236
- const skillMd = path16__default.join(full, "SKILL.md");
5424
+ const full = path15__default.join(dir, entry.name);
5425
+ const skillMd = path15__default.join(full, "SKILL.md");
5237
5426
  if (fs10__default.existsSync(skillMd)) {
5238
5427
  const content = fs10__default.readFileSync(skillMd, "utf-8");
5239
5428
  const fm = parseSkillFrontmatter(content);
@@ -5252,7 +5441,7 @@ function collectSkillVersions(dir, domain, out) {
5252
5441
  function collectAgentVersions(dir, domain, out) {
5253
5442
  for (const entry of fs10__default.readdirSync(dir, { withFileTypes: true })) {
5254
5443
  if (!entry.isDirectory()) continue;
5255
- const agentYaml = path16__default.join(dir, entry.name, "agent.yaml");
5444
+ const agentYaml = path15__default.join(dir, entry.name, "agent.yaml");
5256
5445
  if (!fs10__default.existsSync(agentYaml)) continue;
5257
5446
  const content = fs10__default.readFileSync(agentYaml, "utf-8");
5258
5447
  const parsed = parse(content);
@@ -5283,7 +5472,7 @@ function makeValidateCommand() {
5283
5472
  "Validate asset manifests, versions, and changelogs"
5284
5473
  );
5285
5474
  cmd.argument("[path]", "Path to asset repo or directory to validate", ".").action((targetPath) => {
5286
- const absPath = path16__default.resolve(targetPath);
5475
+ const absPath = path15__default.resolve(targetPath);
5287
5476
  logInfo(`Validating manifests in ${absPath}`);
5288
5477
  const { total, errors } = validateManifests(absPath);
5289
5478
  console.log();
@@ -5304,7 +5493,7 @@ function makeValidateCommand() {
5304
5493
  encoding: "utf-8"
5305
5494
  });
5306
5495
  const changedFiles = new Set(
5307
- diffOutput.trim().split("\n").filter(Boolean).map((f) => path16__default.resolve(AI_RESOURCES, f))
5496
+ diffOutput.trim().split("\n").filter(Boolean).map((f) => path15__default.resolve(AI_RESOURCES, f))
5308
5497
  );
5309
5498
  assets = assets.filter((a) => changedFiles.has(a.filePath));
5310
5499
  } catch {
@@ -5326,7 +5515,7 @@ function makeValidateCommand() {
5326
5515
  if (opts.changedOnly) {
5327
5516
  for (const a of assets) {
5328
5517
  if (!a.version) continue;
5329
- const relPath = path16__default.relative(AI_RESOURCES, a.filePath);
5518
+ const relPath = path15__default.relative(AI_RESOURCES, a.filePath);
5330
5519
  try {
5331
5520
  const headContent = execSync(`git show HEAD:${relPath}`, {
5332
5521
  cwd: AI_RESOURCES,
@@ -5406,7 +5595,7 @@ function makeValidateCommand() {
5406
5595
  let errors = 0;
5407
5596
  for (const domain of modifiedDomains) {
5408
5597
  const changelogModified = modifiedFiles.some(
5409
- (f) => f === `${domain}/CHANGELOG.md` || f === path16__default.join(domain, "CHANGELOG.md")
5598
+ (f) => f === `${domain}/CHANGELOG.md` || f === path15__default.join(domain, "CHANGELOG.md")
5410
5599
  );
5411
5600
  if (changelogModified) {
5412
5601
  logOk(`${domain}/CHANGELOG.md updated`);
@@ -5488,7 +5677,7 @@ function makeVerifyCommand() {
5488
5677
  }
5489
5678
  function makeWhyCommand() {
5490
5679
  return new Command("why").description("Show why an asset is installed (dependency chain)").argument("<ref>", "Asset reference (kind:name)").option("--project-dir <path>", "Project directory", process.cwd()).action((ref, opts) => {
5491
- const am2 = new AssetManager({ projectDir: path16__default.resolve(opts.projectDir) });
5680
+ const am2 = new AssetManager({ projectDir: path15__default.resolve(opts.projectDir) });
5492
5681
  const chain = am2.why(ref);
5493
5682
  if (chain.length === 0) {
5494
5683
  logErr(`${ref} not found in lock file. Run \`skaile install\` first.`);
@@ -5509,7 +5698,7 @@ function makeWhyCommand() {
5509
5698
  var _defaultFormatHelp = Help.prototype.formatHelp;
5510
5699
  var pkg = JSON.parse(
5511
5700
  readFileSync(
5512
- path16__default.resolve(path16__default.dirname(fileURLToPath(import.meta.url)), "../../package.json"),
5701
+ path15__default.resolve(path15__default.dirname(fileURLToPath(import.meta.url)), "../../package.json"),
5513
5702
  "utf-8"
5514
5703
  )
5515
5704
  );
@@ -5573,18 +5762,36 @@ Validation:
5573
5762
  validate versions Check asset version fields and flow pins
5574
5763
  validate changelog Check changelogs for modified domains
5575
5764
 
5576
- Library (Asset Store v2):
5577
- source add <path> Register a local asset source
5578
- source list List registered sources
5579
- source sync [id] Re-discover assets in source(s)
5580
- source remove <id> Unregister a source
5581
- library list [--instances] List cached assets or instances
5582
- library add <ref> Create an instance from an asset def
5583
- library remove <id> Delete an instance
5584
- library show <ref|id> Show details for an asset or instance
5765
+ Sources (github repos of AI assets):
5766
+ source add <git-url> Clone + register a github source
5767
+ source list / show / remove Source registry CRUD
5768
+ source sync [name] Re-fetch upstream changes
5769
+ source patch / propose Contribute back via PR
5770
+ source manifest * Sidecar manifest lifecycle
5771
+
5772
+ Libraries (your authoring workspaces):
5773
+ library init <name> Create a local library (use --git URL to attach a remote)
5774
+ library link <name> <url> Attach a github remote to a local library
5775
+ library create <kind> <name> Scaffold a new asset in a library
5776
+ library list / show / status Library inspection
5777
+ library default <name> Set the default library
5778
+ library rename / set / remove
5779
+ library commit / pull / push / propose / git Git ops (git backend only)
5780
+ library sync <name> Pull then push (as backend permits)
5781
+ library publish / register / yank <ref> Store publish flow (stubs)
5782
+
5783
+ Store (manifest catalog + auth):
5784
+ store login / logout / whoami / yank Auth + admin
5785
+ store mode <auto|local|remote> Resolution mode (stub)
5786
+ store search / show / favourite / unfavourite Catalog browsing (stub)
5787
+ store sync / push Local-store sync (stub)
5788
+
5789
+ Catalog (debug):
5790
+ catalog test / show Probe a catalog endpoint, print resolved config
5791
+
5792
+ Presets:
5585
5793
  preset init [name] Scaffold a .preset.yaml
5586
5794
  preset validate <path> Validate a preset file
5587
- lib-status Show Library health summary
5588
5795
 
5589
5796
  Advanced:
5590
5797
  flow list|show Flow browsing
@@ -5613,24 +5820,24 @@ program.command("init [project-dir]").description("Initialize a project director
5613
5820
  process.exitCode = 1;
5614
5821
  return;
5615
5822
  }
5616
- const resolved = path16__default.resolve(projectDir ?? ".");
5617
- const projectName = path16__default.basename(resolved);
5823
+ const resolved = path15__default.resolve(projectDir ?? ".");
5824
+ const projectName = path15__default.basename(resolved);
5618
5825
  const created = [];
5619
5826
  if (!existsSync11(resolved)) {
5620
5827
  mkdirSync3(resolved, { recursive: true });
5621
5828
  created.push(".");
5622
5829
  }
5623
- const skaileDir = path16__default.join(resolved, ".skaile");
5830
+ const skaileDir = path15__default.join(resolved, ".skaile");
5624
5831
  if (!existsSync11(skaileDir)) {
5625
- mkdirSync3(path16__default.join(skaileDir, "sessions"), { recursive: true });
5832
+ mkdirSync3(path15__default.join(skaileDir, "sessions"), { recursive: true });
5626
5833
  created.push(".skaile/");
5627
5834
  }
5628
- const settingsPath = path16__default.join(skaileDir, "settings.json");
5835
+ const settingsPath = path15__default.join(skaileDir, "settings.json");
5629
5836
  if (!existsSync11(settingsPath)) {
5630
5837
  writeFileSync2(settingsPath, "{}\n");
5631
5838
  created.push(".skaile/settings.json");
5632
5839
  }
5633
- const wsConfigPath = path16__default.join(resolved, "skaile.yaml");
5840
+ const wsConfigPath = path15__default.join(resolved, "skaile.yaml");
5634
5841
  if (!existsSync11(wsConfigPath)) {
5635
5842
  writeFileSync2(
5636
5843
  wsConfigPath,
@@ -5652,14 +5859,14 @@ program.command("init [project-dir]").description("Initialize a project director
5652
5859
  created.push("skaile.yaml");
5653
5860
  }
5654
5861
  for (const dir of new Set(Object.values(DRIVER_TARGETS[backend].local))) {
5655
- const full = path16__default.join(resolved, dir);
5862
+ const full = path15__default.join(resolved, dir);
5656
5863
  if (!existsSync11(full)) {
5657
5864
  mkdirSync3(full, { recursive: true });
5658
5865
  created.push(`${dir}/`);
5659
5866
  }
5660
5867
  }
5661
5868
  if (opts.git) {
5662
- const gitignorePath = path16__default.join(resolved, ".gitignore");
5869
+ const gitignorePath = path15__default.join(resolved, ".gitignore");
5663
5870
  const entries = ["node_modules/", ".skaile/sessions/", "*.log", ".env", ".env.local"];
5664
5871
  const existing = existsSync11(gitignorePath) ? readFileSync5(gitignorePath, "utf-8") : "";
5665
5872
  const have = new Set(existing.split("\n").map((l) => l.trim()));
@@ -5670,7 +5877,7 @@ program.command("init [project-dir]").description("Initialize a project director
5670
5877
  `);
5671
5878
  if (!existing) created.push(".gitignore");
5672
5879
  }
5673
- if (!existsSync11(path16__default.join(resolved, ".git"))) {
5880
+ if (!existsSync11(path15__default.join(resolved, ".git"))) {
5674
5881
  try {
5675
5882
  execSync3("git init", { cwd: resolved, stdio: "pipe" });
5676
5883
  created.push(".git/");
@@ -5700,7 +5907,7 @@ program.command("init [project-dir]").description("Initialize a project director
5700
5907
  logOk(`Initialized project at ${S.heading(resolved)}`);
5701
5908
  console.log();
5702
5909
  console.log(S.heading(" Next steps:"));
5703
- const isCurrentDir = resolved === path16__default.resolve(".");
5910
+ const isCurrentDir = resolved === path15__default.resolve(".");
5704
5911
  let step = 1;
5705
5912
  if (!isCurrentDir) {
5706
5913
  console.log(` ${S.dim(`${step}.`)} ${S.cmd(`cd ${projectDir}`)}`);
@@ -5761,7 +5968,6 @@ program.addCommand(makeSourceCommand());
5761
5968
  program.addCommand(makeLibraryCommand());
5762
5969
  program.addCommand(makeAssetCommand());
5763
5970
  program.addCommand(makePresetCommand());
5764
- program.addCommand(makeLibraryStatusCommand());
5765
5971
  program.command("path").description("Show resolved paths").action(() => {
5766
5972
  console.log();
5767
5973
  console.log(` ${S.dim("ai-assets")} ${S.heading(AI_RESOURCES)}`);