@theglitchking/semantic-memory 1.0.1 → 1.1.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.
package/dist/cli/index.js CHANGED
@@ -1,19 +1,196 @@
1
1
  #!/usr/bin/env node
2
+ import "../chunk-PZ5AY32C.js";
2
3
 
3
4
  // src/cli/index.ts
4
5
  import { program } from "commander";
5
- import { resolve, join, dirname, relative } from "path";
6
- import { existsSync, readFileSync, writeFileSync, rmSync } from "fs";
6
+ import { resolve as resolve2, join as join2, dirname, relative } from "path";
7
+ import { existsSync as existsSync2, readFileSync, writeFileSync, rmSync } from "fs";
7
8
  import { createRequire } from "module";
8
9
  import { spawnSync } from "child_process";
9
10
  import { registerUpdateCommands } from "@theglitchking/claude-plugin-runtime";
11
+
12
+ // src/cli/skills.ts
13
+ import { mkdir, readFile, writeFile, copyFile, readdir, rm } from "fs/promises";
14
+ import { existsSync } from "fs";
15
+ import { join, resolve } from "path";
16
+ import { homedir } from "os";
17
+ import { createHash } from "crypto";
18
+ var MANIFEST_FILE = ".semantic-memory-skill-manifest.json";
19
+ function resolveTarget(agent, scope, projectRoot) {
20
+ const root = resolve(projectRoot);
21
+ const home = homedir();
22
+ const map = {
23
+ claude: { global: join(home, ".claude", "skills"), local: join(root, ".claude", "skills") },
24
+ codex: { global: join(home, ".codex", "skills"), local: join(root, ".codex", "skills") },
25
+ copilot: { global: join(home, ".copilot", "skills"), local: join(root, ".github", "skills") },
26
+ pi: { global: join(home, ".pi", "agent", "skills"), local: join(root, ".pi", "skills") }
27
+ };
28
+ return { agent, scope, path: map[agent][scope] };
29
+ }
30
+ async function listShippedSkills(sourceRoot) {
31
+ const skillsDir = join(sourceRoot, "skills");
32
+ if (!existsSync(skillsDir)) return [];
33
+ const entries = await readdir(skillsDir, { withFileTypes: true });
34
+ const out = [];
35
+ for (const e of entries) {
36
+ if (!e.isDirectory()) continue;
37
+ const dir = join(skillsDir, e.name);
38
+ const skillFile = join(dir, "SKILL.md");
39
+ if (!existsSync(skillFile)) continue;
40
+ out.push({ name: e.name, dir });
41
+ }
42
+ return out;
43
+ }
44
+ async function sha256OfFile(path) {
45
+ const buf = await readFile(path);
46
+ return createHash("sha256").update(buf).digest("hex");
47
+ }
48
+ async function copyBundle(srcDir, destDir) {
49
+ await mkdir(destDir, { recursive: true });
50
+ const entries = await readdir(srcDir, { withFileTypes: true });
51
+ const written = [];
52
+ for (const e of entries) {
53
+ const src = join(srcDir, e.name);
54
+ const dest = join(destDir, e.name);
55
+ if (e.isDirectory()) {
56
+ const childWritten = await copyBundle(src, dest);
57
+ written.push(...childWritten);
58
+ continue;
59
+ }
60
+ if (!e.isFile()) continue;
61
+ await copyFile(src, dest);
62
+ written.push(dest);
63
+ }
64
+ return written;
65
+ }
66
+ async function installSkills(opts) {
67
+ const target = resolveTarget(opts.agent, opts.scope, opts.projectRoot);
68
+ const shipped = await listShippedSkills(opts.sourceRoot);
69
+ const filter = opts.only && opts.only.length > 0 ? new Set(opts.only) : null;
70
+ const toInstall = filter ? shipped.filter((s) => filter.has(s.name)) : shipped;
71
+ if (toInstall.length === 0) {
72
+ return {
73
+ agent: opts.agent,
74
+ scope: opts.scope,
75
+ target_path: target.path,
76
+ installed: [],
77
+ skipped: [],
78
+ reason: filter ? `No matching skills found (only=${[...filter].join(",")}).` : "No shipped skills found at sourceRoot/skills/."
79
+ };
80
+ }
81
+ const manifestPath = join(target.path, MANIFEST_FILE);
82
+ const existing = await readManifest(manifestPath);
83
+ if (existing && !opts.force) {
84
+ const drift = await detectDrift(existing, toInstall);
85
+ if (drift.length > 0) {
86
+ return {
87
+ agent: opts.agent,
88
+ scope: opts.scope,
89
+ target_path: target.path,
90
+ installed: [],
91
+ skipped: toInstall.map((s) => s.name),
92
+ reason: `Drift detected on ${drift.length} skill(s): ${drift.join(", ")}. Pass --force to overwrite.`,
93
+ manifest_path: manifestPath
94
+ };
95
+ }
96
+ }
97
+ await mkdir(target.path, { recursive: true });
98
+ const installed = [];
99
+ const skillEntries = [];
100
+ for (const skill of toInstall) {
101
+ const destDir = join(target.path, skill.name);
102
+ await copyBundle(skill.dir, destDir);
103
+ const skillFile = join(skill.dir, "SKILL.md");
104
+ skillEntries.push({ name: skill.name, sha256: await sha256OfFile(skillFile) });
105
+ installed.push(skill.name);
106
+ }
107
+ const manifest = {
108
+ package: "@theglitchking/semantic-memory",
109
+ version: opts.version,
110
+ agent: opts.agent,
111
+ scope: opts.scope,
112
+ installed_at: (/* @__PURE__ */ new Date()).toISOString(),
113
+ skills: skillEntries
114
+ };
115
+ await writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
116
+ return {
117
+ agent: opts.agent,
118
+ scope: opts.scope,
119
+ target_path: target.path,
120
+ installed,
121
+ skipped: [],
122
+ manifest_path: manifestPath
123
+ };
124
+ }
125
+ async function uninstallSkills(opts) {
126
+ const target = resolveTarget(opts.agent, opts.scope, opts.projectRoot);
127
+ const manifestPath = join(target.path, MANIFEST_FILE);
128
+ const manifest = await readManifest(manifestPath);
129
+ if (!manifest) {
130
+ return {
131
+ agent: opts.agent,
132
+ scope: opts.scope,
133
+ target_path: target.path,
134
+ removed: [],
135
+ manifest_present: false,
136
+ reason: "No semantic-memory manifest found \u2014 nothing to uninstall."
137
+ };
138
+ }
139
+ const removed = [];
140
+ for (const skill of manifest.skills) {
141
+ const dir = join(target.path, skill.name);
142
+ if (existsSync(dir)) {
143
+ await rm(dir, { recursive: true, force: true });
144
+ removed.push(skill.name);
145
+ }
146
+ }
147
+ await rm(manifestPath, { force: true });
148
+ return {
149
+ agent: opts.agent,
150
+ scope: opts.scope,
151
+ target_path: target.path,
152
+ removed,
153
+ manifest_present: true
154
+ };
155
+ }
156
+ async function readManifest(path) {
157
+ if (!existsSync(path)) return null;
158
+ try {
159
+ const raw = await readFile(path, "utf-8");
160
+ const parsed = JSON.parse(raw);
161
+ if (typeof parsed?.package !== "string") return null;
162
+ return parsed;
163
+ } catch {
164
+ return null;
165
+ }
166
+ }
167
+ async function detectDrift(existing, toInstall) {
168
+ const driftNames = [];
169
+ const existingByName = new Map(existing.skills.map((s) => [s.name, s.sha256]));
170
+ for (const skill of toInstall) {
171
+ const sourceSha = await sha256OfFile(join(skill.dir, "SKILL.md"));
172
+ const existingSha = existingByName.get(skill.name);
173
+ if (existingSha !== void 0 && existingSha !== sourceSha) {
174
+ driftNames.push(skill.name);
175
+ }
176
+ }
177
+ return driftNames;
178
+ }
179
+ var SKILL_BUNDLER_AGENTS = ["claude", "codex", "copilot", "pi"];
180
+
181
+ // src/cli/index.ts
10
182
  var require_ = createRequire(import.meta.url);
11
183
  var { version } = require_("../../package.json");
12
- var PKG_NAME = "@theglitchking/semantic-sidekick";
184
+ var PKG_NAME = "@theglitchking/semantic-memory";
185
+ var LEGACY_PKG_NAME = "@theglitchking/semantic-sidekick";
13
186
  function runRelink(cwd) {
14
- const linker = join(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "scripts", "link-skills.js");
15
- const script = existsSync(linker) ? linker : resolve(process.cwd(), "scripts", "link-skills.js");
16
- if (!existsSync(script)) {
187
+ const candidates = [
188
+ join2(cwd, "node_modules", "@theglitchking", "semantic-memory", "scripts", "link-skills.js"),
189
+ join2(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "scripts", "link-skills.js"),
190
+ resolve2(process.cwd(), "scripts", "link-skills.js")
191
+ ];
192
+ const script = candidates.find((p) => existsSync2(p));
193
+ if (!script) {
17
194
  console.error("link-skills.js not found \u2014 is the package installed?");
18
195
  return;
19
196
  }
@@ -24,8 +201,14 @@ function runRelink(cwd) {
24
201
  });
25
202
  }
26
203
  function findLocalBin(cwd) {
27
- const p = join(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "bin", "semantic-sidekick");
28
- return existsSync(p) ? p : null;
204
+ const candidates = [
205
+ join2(cwd, "node_modules", "@theglitchking", "semantic-memory", "bin", "semantic-memory"),
206
+ join2(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "bin", "semantic-sidekick")
207
+ ];
208
+ for (const p of candidates) {
209
+ if (existsSync2(p)) return p;
210
+ }
211
+ return null;
29
212
  }
30
213
  function localBinArg(cwd) {
31
214
  const abs = findLocalBin(cwd);
@@ -45,7 +228,9 @@ function isNpxForm(entry) {
45
228
  if (!entry || typeof entry !== "object") return false;
46
229
  const cmd = entry.command;
47
230
  const args = Array.isArray(entry.args) ? entry.args : [];
48
- return cmd === "npx" && args.some((a) => typeof a === "string" && a.includes(PKG_NAME));
231
+ return cmd === "npx" && args.some(
232
+ (a) => typeof a === "string" && (a.includes(PKG_NAME) || a.includes(LEGACY_PKG_NAME))
233
+ );
49
234
  }
50
235
  function extractNotesPath(entry) {
51
236
  const args = Array.isArray(entry?.args) ? entry.args : [];
@@ -218,7 +403,7 @@ var TOOL_CATEGORIES = {
218
403
  function printToolList() {
219
404
  console.log("\nSemantic Pages \u2014 21 MCP Tools\n");
220
405
  console.log("Usage: These tools are available via MCP when the server is running.");
221
- console.log(" Run `semantic-sidekick tools <name>` for details on a specific tool.\n");
406
+ console.log(" Run `semantic-memory tools <name>` for details on a specific tool.\n");
222
407
  for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {
223
408
  console.log(` ${category}:`);
224
409
  for (const name of tools) {
@@ -227,13 +412,13 @@ function printToolList() {
227
412
  }
228
413
  console.log();
229
414
  }
230
- console.log("Run `semantic-sidekick tools <tool-name>` for arguments and examples.");
415
+ console.log("Run `semantic-memory tools <tool-name>` for arguments and examples.");
231
416
  }
232
417
  function printToolDetail(name) {
233
418
  const tool = TOOL_HELP[name];
234
419
  if (!tool) {
235
420
  console.error(`Unknown tool: ${name}`);
236
- console.error(`Run \`semantic-sidekick tools\` to see all available tools.`);
421
+ console.error(`Run \`semantic-memory tools\` to see all available tools.`);
237
422
  process.exit(1);
238
423
  }
239
424
  console.log(`
@@ -271,7 +456,7 @@ program.command("search <query>").description("Run a vault search and print top
271
456
  });
272
457
  program.command("lint").description("Lint the vault against vault.schema.yml (schema violations + missing provenance + stale)").requiredOption("--notes <path>", "Path to markdown notes directory").option("--rule <name>", "Limit output to one rule: schema_violations | missing_provenance | stale").option("--json", "Emit JSON instead of the human-readable report").option("--strict", "Exit non-zero on warnings too (default: exit non-zero only on errors)").action(async (opts) => {
273
458
  const { lintVault, formatLintReport } = await import("../lint-GMXQF4RW.js");
274
- const report = await lintVault(resolve(opts.notes));
459
+ const report = await lintVault(resolve2(opts.notes));
275
460
  if (opts.json) {
276
461
  const out = opts.rule ? report.byRule[opts.rule] : report;
277
462
  console.log(JSON.stringify(out, null, 2));
@@ -294,7 +479,7 @@ program.command("log-event").description("Append a structured event to the vault
294
479
  }
295
480
  }
296
481
  try {
297
- const entry = await logEvent(resolve(opts.notes), {
482
+ const entry = await logEvent(resolve2(opts.notes), {
298
483
  kind: opts.kind,
299
484
  summary: opts.summary,
300
485
  payload
@@ -308,7 +493,7 @@ program.command("log-event").description("Append a structured event to the vault
308
493
  program.command("log-query").description("Read structured log entries from log.md \u2014 filters by kind, date range, limit").requiredOption("--notes <path>", "Path to markdown notes directory").option("--kind <name>", "Filter by kind (ingest, synthesis, error, mode_change, etc.)").option("--after <iso>", "ISO timestamp \u2014 only entries on or after").option("--before <iso>", "ISO timestamp \u2014 only entries on or before").option("--limit <n>", "Max entries (most recent)", (v) => parseInt(v, 10)).action(async (opts) => {
309
494
  const { logQuery } = await import("../log-LQXIJXIA.js");
310
495
  try {
311
- const entries = await logQuery(resolve(opts.notes), {
496
+ const entries = await logQuery(resolve2(opts.notes), {
312
497
  kind: opts.kind,
313
498
  after: opts.after,
314
499
  before: opts.before,
@@ -322,7 +507,7 @@ program.command("log-query").description("Read structured log entries from log.m
322
507
  });
323
508
  program.command("install-schema").description("Bootstrap vault.schema.yml in the vault root with the default schema").requiredOption("--notes <path>", "Path to markdown notes directory").option("--force", "Overwrite existing schema file").action(async (opts) => {
324
509
  const { installDefaultSchema } = await import("../schema-F3RTY6SQ.js");
325
- const r = await installDefaultSchema(resolve(opts.notes), opts.force);
510
+ const r = await installDefaultSchema(resolve2(opts.notes), opts.force);
326
511
  console.log(r.written ? `Installed default schema: ${r.path}` : `Schema already exists: ${r.path} (use --force to overwrite)`);
327
512
  process.exit(0);
328
513
  });
@@ -335,8 +520,8 @@ program.command("tools [name]").description("List all MCP tools, or show details
335
520
  process.exit(0);
336
521
  });
337
522
  program.command("serve", { isDefault: true }).description("Start the MCP server (default command)").requiredOption("--notes <path>", "Path to markdown notes directory").option("--reindex", "Force full reindex and exit").option("--stats", "Show vault statistics and exit").option("--wait-for-ready", "Block startup until index is fully built before serving (default: index in background; tools return 'Indexing in progress' until ready)").option("--read-only", "Suppress write tools (create_note, update_note, delete_note, move_note, update_frontmatter, manage_tags, rename_tag) \u2014 use for shared docs vaults owned by another tool").option("--model <name>", "Embedding model to use (default: all-MiniLM-L6-v2, fast; use nomic-ai/nomic-embed-text-v1.5 for higher quality)").option("--workers <n>", "Number of worker threads for parallel embedding", parseInt).option("--batch-size <n>", "Texts per ONNX forward pass (default: 8)", parseInt).option("--no-quantized", "Use full-precision model instead of quantized (slower, slightly higher quality)").option("--no-watch", "Disable file watcher").action(async (opts) => {
338
- const notesPath = resolve(opts.notes);
339
- if (!existsSync(notesPath)) {
523
+ const notesPath = resolve2(opts.notes);
524
+ if (!existsSync2(notesPath)) {
340
525
  console.error(`Error: notes directory not found: ${notesPath}`);
341
526
  process.exit(1);
342
527
  }
@@ -380,16 +565,16 @@ program.command("serve", { isDefault: true }).description("Start the MCP server
380
565
  });
381
566
  registerUpdateCommands(program, {
382
567
  packageName: PKG_NAME,
383
- pluginName: "semantic-sidekick",
384
- configFile: "semantic-sidekick.json",
568
+ pluginName: "semantic-memory",
569
+ configFile: "semantic-memory.json",
385
570
  onAfterUpdate: (cwd) => runRelink(cwd)
386
571
  });
387
572
  program.command("normalize-config").description(
388
573
  "Rewrite fragile `npx @latest` entries in .mcp.json to the stable node-against-node_modules form (with backup and validation)"
389
574
  ).option("--dry-run", "print the proposed changes but don't write").action((opts) => {
390
575
  const cwd = process.cwd();
391
- const mcpPath = join(cwd, ".mcp.json");
392
- if (!existsSync(mcpPath)) {
576
+ const mcpPath = join2(cwd, ".mcp.json");
577
+ if (!existsSync2(mcpPath)) {
393
578
  console.log("no .mcp.json in current directory \u2014 nothing to do");
394
579
  process.exit(0);
395
580
  }
@@ -401,8 +586,8 @@ program.command("normalize-config").description(
401
586
  const bin = localBinArg(cwd);
402
587
  if (!bin) {
403
588
  console.error(
404
- `no local install found at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick.
405
- run 'npm install --save @theglitchking/semantic-sidekick' first, then re-run this command.`
589
+ `no local install found at ./node_modules/@theglitchking/semantic-memory/bin/semantic-memory (or the legacy semantic-sidekick path).
590
+ run 'npm install --save @theglitchking/semantic-memory' first, then re-run this command.`
406
591
  );
407
592
  process.exit(1);
408
593
  }
@@ -429,7 +614,7 @@ run 'npm install --save @theglitchking/semantic-sidekick' first, then re-run thi
429
614
  console.log("--- (dry-run; no changes written)");
430
615
  process.exit(0);
431
616
  }
432
- const bakPath = join(dirname(mcpPath), ".mcp.json.bak");
617
+ const bakPath = join2(dirname(mcpPath), ".mcp.json.bak");
433
618
  try {
434
619
  writeFileSync(bakPath, readFileSync(mcpPath, "utf8"));
435
620
  console.log(`backup written: ${bakPath}`);
@@ -450,17 +635,17 @@ ${verify.stderr?.toString() || ""}`);
450
635
  process.exit(0);
451
636
  });
452
637
  program.command("healthcheck").description(
453
- "Verify the local install starts cleanly; self-heal common npx-cache corruption (ERR_MODULE_NOT_FOUND)"
454
- ).action(() => {
638
+ "Verify the local install starts cleanly + run drift detection. Self-heals common npx-cache corruption (ERR_MODULE_NOT_FOUND). With --fast, skips the slow tier (full vault lint)."
639
+ ).option("--fast", "Run only the fast-tier drift checks (file-system probes). Skips the slow tier (full vault lint).", false).option("--json", "Emit structured JSON output instead of human-readable text.", false).action(async (opts) => {
455
640
  const cwd = process.cwd();
456
641
  const bin = findLocalBin(cwd);
457
642
  if (!bin) {
458
- console.error(`no local install at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick`);
459
- console.error(`run 'npm install --save @theglitchking/semantic-sidekick' to install.`);
643
+ console.error(`no local install at ./node_modules/@theglitchking/semantic-memory/bin/semantic-memory (or legacy semantic-sidekick path)`);
644
+ console.error(`run 'npm install --save @theglitchking/semantic-memory' to install.`);
460
645
  process.exit(1);
461
646
  }
462
- const mcpPath = join(cwd, ".mcp.json");
463
- if (existsSync(mcpPath)) {
647
+ const mcpPath = join2(cwd, ".mcp.json");
648
+ if (existsSync2(mcpPath)) {
464
649
  const data = readJsonSafe(mcpPath);
465
650
  const entries = data?.mcpServers && typeof data.mcpServers === "object" ? Object.entries(data.mcpServers) : [];
466
651
  const fragile = entries.filter(([, e]) => isNpxForm(e)).map(([k]) => k);
@@ -469,7 +654,7 @@ program.command("healthcheck").description(
469
654
  `\u26A0\uFE0F .mcp.json uses the fragile npx-@latest form for: ${fragile.join(", ")}`
470
655
  );
471
656
  console.warn(` Rewrite to the stable form:`);
472
- console.warn(` npx --no @theglitchking/semantic-sidekick normalize-config`);
657
+ console.warn(` npx --no @theglitchking/semantic-memory normalize-config`);
473
658
  }
474
659
  }
475
660
  const r = spawnSync("node", [bin, "--version"], { cwd, stdio: "pipe", timeout: 15e3 });
@@ -498,8 +683,113 @@ ${r2.stderr?.toString() || ""}`);
498
683
  console.error(`ERR_MODULE_NOT_FOUND but could not locate offending cache path in the error.`);
499
684
  }
500
685
  }
501
- console.error(stderr || `local install failed (exit ${r.status})`);
502
- process.exit(1);
686
+ if (stderr) console.error(stderr);
687
+ if (r.status !== 0) {
688
+ console.error(`local install failed (exit ${r.status})`);
689
+ process.exit(1);
690
+ }
691
+ });
692
+ var driftHealthcheckActionPostprocess = async (opts) => {
693
+ try {
694
+ const { runHealthcheck, formatDriftBanner } = await import("../healthcheck-DCFGPI7M.js");
695
+ const projectRoot = process.cwd();
696
+ const vaultCandidate = join2(projectRoot, ".claude", ".vault");
697
+ const vaultPath = existsSync2(vaultCandidate) ? vaultCandidate : void 0;
698
+ const result = await runHealthcheck({
699
+ projectRoot,
700
+ vaultPath,
701
+ tier: opts.fast ? "fast" : "all",
702
+ force: true
703
+ });
704
+ if (opts.json) {
705
+ console.log(JSON.stringify(result, null, 2));
706
+ return;
707
+ }
708
+ const banner = formatDriftBanner(result);
709
+ if (banner) {
710
+ console.log("");
711
+ console.log(banner);
712
+ } else {
713
+ console.log("");
714
+ console.log(`\u2713 no drift detected (${result.findings.length} checks ran in ${result.duration_ms}ms)`);
715
+ }
716
+ } catch (err) {
717
+ console.error(`drift check threw: ${err?.message ?? err}`);
718
+ }
719
+ };
720
+ var healthcheckCmd = program.commands.find((c) => c.name() === "healthcheck");
721
+ if (healthcheckCmd) {
722
+ healthcheckCmd.hook("postAction", async (thisCmd) => {
723
+ const opts = thisCmd.opts();
724
+ await driftHealthcheckActionPostprocess({ fast: !!opts.fast, json: !!opts.json });
725
+ });
726
+ }
727
+ function parseAgent(input) {
728
+ const a = input.toLowerCase();
729
+ if (!SKILL_BUNDLER_AGENTS.includes(a)) {
730
+ console.error(`Unknown agent: ${input}. Supported: ${SKILL_BUNDLER_AGENTS.join(", ")}.`);
731
+ process.exit(2);
732
+ }
733
+ return a;
734
+ }
735
+ function parseScope(input) {
736
+ if (input !== "global" && input !== "local") {
737
+ console.error(`Unknown scope: ${input}. Use 'global' or 'local'.`);
738
+ process.exit(2);
739
+ }
740
+ return input;
741
+ }
742
+ function findSourceRoot() {
743
+ for (const pkg of ["semantic-memory", "semantic-sidekick"]) {
744
+ const installed = join2(process.cwd(), "node_modules", "@theglitchking", pkg);
745
+ if (existsSync2(installed)) return installed;
746
+ }
747
+ const dev = resolve2(new URL("../../", import.meta.url).pathname);
748
+ return dev;
749
+ }
750
+ var skillsCmd = program.command("skills").description("Install, target, or uninstall skill bundles for non-Claude agents (codex, copilot, pi). Claude installs continue to use the npm postinstall flow.");
751
+ skillsCmd.command("targets").description("Preview where skill bundles would be installed for one or more agents.").option("--agent <name...>", "One or more agents (default: all). Repeatable.", void 0).option("--scope <scope>", "global or local (default: local)", "local").option("--project <path>", "Project root for local-scope paths (default: cwd)", process.cwd()).action((opts) => {
752
+ const scope = parseScope(opts.scope);
753
+ const agents = (opts.agent && opts.agent.length > 0 ? opts.agent : SKILL_BUNDLER_AGENTS).map(parseAgent);
754
+ const out = agents.map((a) => resolveTarget(a, scope, opts.project));
755
+ console.log(JSON.stringify(out, null, 2));
756
+ });
757
+ skillsCmd.command("install").description("Install skill bundles into an agent's skill directory. Non-destructive by default; --force to overwrite.").requiredOption("--agent <name>", "Agent runtime (claude, codex, copilot, pi)").option("--scope <scope>", "global or local (default: local)", "local").option("--project <path>", "Project root for local-scope paths (default: cwd)", process.cwd()).option("--only <names...>", "Restrict to specific skill names (default: all shipped)").option("--force", "Overwrite even if drift is detected against an existing manifest", false).action(async (opts) => {
758
+ const agent = parseAgent(opts.agent);
759
+ const scope = parseScope(opts.scope);
760
+ if (agent === "claude") {
761
+ console.error(
762
+ "Claude skill installs are handled by the npm postinstall (claude-plugin-runtime). Run `npm install @theglitchking/semantic-memory` instead \u2014 that flow symlinks skills into ~/.claude/skills/ or .claude/skills/ automatically. The skills CLI is intended for non-Claude agents (codex, copilot, pi) which do not have that postinstall integration."
763
+ );
764
+ process.exit(2);
765
+ }
766
+ const sourceRoot = findSourceRoot();
767
+ const result = await installSkills({
768
+ agent,
769
+ scope,
770
+ sourceRoot,
771
+ projectRoot: opts.project,
772
+ version,
773
+ only: opts.only,
774
+ force: opts.force === true
775
+ });
776
+ console.log(JSON.stringify(result, null, 2));
777
+ if (result.installed.length === 0 && result.reason) process.exit(1);
778
+ });
779
+ skillsCmd.command("uninstall").description("Remove skill bundles tracked by the semantic-memory manifest. User-written skills outside the manifest are left untouched.").requiredOption("--agent <name>", "Agent runtime (claude, codex, copilot, pi)").option("--scope <scope>", "global or local (default: local)", "local").option("--project <path>", "Project root for local-scope paths (default: cwd)", process.cwd()).action(async (opts) => {
780
+ const agent = parseAgent(opts.agent);
781
+ const scope = parseScope(opts.scope);
782
+ if (agent === "claude") {
783
+ console.error("Claude skill uninstalls go through the npm uninstall flow. The skills CLI is for non-Claude agents.");
784
+ process.exit(2);
785
+ }
786
+ const result = await uninstallSkills({ agent, scope, projectRoot: opts.project });
787
+ console.log(JSON.stringify(result, null, 2));
788
+ });
789
+ skillsCmd.command("list").description("List the skill bundles shipped with this plugin version.").action(async () => {
790
+ const sourceRoot = findSourceRoot();
791
+ const shipped = await listShippedSkills(sourceRoot);
792
+ console.log(JSON.stringify(shipped.map((s) => s.name), null, 2));
503
793
  });
504
794
  program.parse();
505
795
  //# sourceMappingURL=index.js.map