@theglitchking/semantic-memory 1.0.0 → 1.1.0
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/.claude-plugin/marketplace.json +4 -4
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +74 -0
- package/commands/contract.md +14 -0
- package/commands/healthcheck.md +21 -3
- package/dist/chunk-CCSX3BHF.js +273 -0
- package/dist/chunk-CCSX3BHF.js.map +1 -0
- package/dist/{chunk-CXTRTCIK.js → chunk-XBAN7GRT.js} +380 -6
- package/dist/chunk-XBAN7GRT.js.map +1 -0
- package/dist/cli/index.js +299 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/core/index.d.ts +276 -3
- package/dist/core/index.js +22 -2
- package/dist/healthcheck-DCFGPI7M.js +14 -0
- package/dist/healthcheck-DCFGPI7M.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +1008 -568
- package/dist/mcp/server.js.map +1 -1
- package/hooks/vault-context.js +130 -1
- package/package.json +1 -1
- package/dist/chunk-CXTRTCIK.js.map +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,19 +1,191 @@
|
|
|
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
184
|
var PKG_NAME = "@theglitchking/semantic-sidekick";
|
|
13
185
|
function runRelink(cwd) {
|
|
14
|
-
const linker =
|
|
15
|
-
const script =
|
|
16
|
-
if (!
|
|
186
|
+
const linker = join2(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "scripts", "link-skills.js");
|
|
187
|
+
const script = existsSync2(linker) ? linker : resolve2(process.cwd(), "scripts", "link-skills.js");
|
|
188
|
+
if (!existsSync2(script)) {
|
|
17
189
|
console.error("link-skills.js not found \u2014 is the package installed?");
|
|
18
190
|
return;
|
|
19
191
|
}
|
|
@@ -24,8 +196,8 @@ function runRelink(cwd) {
|
|
|
24
196
|
});
|
|
25
197
|
}
|
|
26
198
|
function findLocalBin(cwd) {
|
|
27
|
-
const p =
|
|
28
|
-
return
|
|
199
|
+
const p = join2(cwd, "node_modules", "@theglitchking", "semantic-sidekick", "bin", "semantic-sidekick");
|
|
200
|
+
return existsSync2(p) ? p : null;
|
|
29
201
|
}
|
|
30
202
|
function localBinArg(cwd) {
|
|
31
203
|
const abs = findLocalBin(cwd);
|
|
@@ -271,7 +443,7 @@ program.command("search <query>").description("Run a vault search and print top
|
|
|
271
443
|
});
|
|
272
444
|
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
445
|
const { lintVault, formatLintReport } = await import("../lint-GMXQF4RW.js");
|
|
274
|
-
const report = await lintVault(
|
|
446
|
+
const report = await lintVault(resolve2(opts.notes));
|
|
275
447
|
if (opts.json) {
|
|
276
448
|
const out = opts.rule ? report.byRule[opts.rule] : report;
|
|
277
449
|
console.log(JSON.stringify(out, null, 2));
|
|
@@ -294,7 +466,7 @@ program.command("log-event").description("Append a structured event to the vault
|
|
|
294
466
|
}
|
|
295
467
|
}
|
|
296
468
|
try {
|
|
297
|
-
const entry = await logEvent(
|
|
469
|
+
const entry = await logEvent(resolve2(opts.notes), {
|
|
298
470
|
kind: opts.kind,
|
|
299
471
|
summary: opts.summary,
|
|
300
472
|
payload
|
|
@@ -308,7 +480,7 @@ program.command("log-event").description("Append a structured event to the vault
|
|
|
308
480
|
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
481
|
const { logQuery } = await import("../log-LQXIJXIA.js");
|
|
310
482
|
try {
|
|
311
|
-
const entries = await logQuery(
|
|
483
|
+
const entries = await logQuery(resolve2(opts.notes), {
|
|
312
484
|
kind: opts.kind,
|
|
313
485
|
after: opts.after,
|
|
314
486
|
before: opts.before,
|
|
@@ -322,7 +494,7 @@ program.command("log-query").description("Read structured log entries from log.m
|
|
|
322
494
|
});
|
|
323
495
|
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
496
|
const { installDefaultSchema } = await import("../schema-F3RTY6SQ.js");
|
|
325
|
-
const r = await installDefaultSchema(
|
|
497
|
+
const r = await installDefaultSchema(resolve2(opts.notes), opts.force);
|
|
326
498
|
console.log(r.written ? `Installed default schema: ${r.path}` : `Schema already exists: ${r.path} (use --force to overwrite)`);
|
|
327
499
|
process.exit(0);
|
|
328
500
|
});
|
|
@@ -335,8 +507,8 @@ program.command("tools [name]").description("List all MCP tools, or show details
|
|
|
335
507
|
process.exit(0);
|
|
336
508
|
});
|
|
337
509
|
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 =
|
|
339
|
-
if (!
|
|
510
|
+
const notesPath = resolve2(opts.notes);
|
|
511
|
+
if (!existsSync2(notesPath)) {
|
|
340
512
|
console.error(`Error: notes directory not found: ${notesPath}`);
|
|
341
513
|
process.exit(1);
|
|
342
514
|
}
|
|
@@ -388,8 +560,8 @@ program.command("normalize-config").description(
|
|
|
388
560
|
"Rewrite fragile `npx @latest` entries in .mcp.json to the stable node-against-node_modules form (with backup and validation)"
|
|
389
561
|
).option("--dry-run", "print the proposed changes but don't write").action((opts) => {
|
|
390
562
|
const cwd = process.cwd();
|
|
391
|
-
const mcpPath =
|
|
392
|
-
if (!
|
|
563
|
+
const mcpPath = join2(cwd, ".mcp.json");
|
|
564
|
+
if (!existsSync2(mcpPath)) {
|
|
393
565
|
console.log("no .mcp.json in current directory \u2014 nothing to do");
|
|
394
566
|
process.exit(0);
|
|
395
567
|
}
|
|
@@ -429,7 +601,7 @@ run 'npm install --save @theglitchking/semantic-sidekick' first, then re-run thi
|
|
|
429
601
|
console.log("--- (dry-run; no changes written)");
|
|
430
602
|
process.exit(0);
|
|
431
603
|
}
|
|
432
|
-
const bakPath =
|
|
604
|
+
const bakPath = join2(dirname(mcpPath), ".mcp.json.bak");
|
|
433
605
|
try {
|
|
434
606
|
writeFileSync(bakPath, readFileSync(mcpPath, "utf8"));
|
|
435
607
|
console.log(`backup written: ${bakPath}`);
|
|
@@ -450,8 +622,8 @@ ${verify.stderr?.toString() || ""}`);
|
|
|
450
622
|
process.exit(0);
|
|
451
623
|
});
|
|
452
624
|
program.command("healthcheck").description(
|
|
453
|
-
"Verify the local install starts cleanly
|
|
454
|
-
).action(() => {
|
|
625
|
+
"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)."
|
|
626
|
+
).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
627
|
const cwd = process.cwd();
|
|
456
628
|
const bin = findLocalBin(cwd);
|
|
457
629
|
if (!bin) {
|
|
@@ -459,8 +631,8 @@ program.command("healthcheck").description(
|
|
|
459
631
|
console.error(`run 'npm install --save @theglitchking/semantic-sidekick' to install.`);
|
|
460
632
|
process.exit(1);
|
|
461
633
|
}
|
|
462
|
-
const mcpPath =
|
|
463
|
-
if (
|
|
634
|
+
const mcpPath = join2(cwd, ".mcp.json");
|
|
635
|
+
if (existsSync2(mcpPath)) {
|
|
464
636
|
const data = readJsonSafe(mcpPath);
|
|
465
637
|
const entries = data?.mcpServers && typeof data.mcpServers === "object" ? Object.entries(data.mcpServers) : [];
|
|
466
638
|
const fragile = entries.filter(([, e]) => isNpxForm(e)).map(([k]) => k);
|
|
@@ -498,8 +670,113 @@ ${r2.stderr?.toString() || ""}`);
|
|
|
498
670
|
console.error(`ERR_MODULE_NOT_FOUND but could not locate offending cache path in the error.`);
|
|
499
671
|
}
|
|
500
672
|
}
|
|
501
|
-
console.error(stderr
|
|
502
|
-
|
|
673
|
+
if (stderr) console.error(stderr);
|
|
674
|
+
if (r.status !== 0) {
|
|
675
|
+
console.error(`local install failed (exit ${r.status})`);
|
|
676
|
+
process.exit(1);
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
var driftHealthcheckActionPostprocess = async (opts) => {
|
|
680
|
+
try {
|
|
681
|
+
const { runHealthcheck, formatDriftBanner } = await import("../healthcheck-DCFGPI7M.js");
|
|
682
|
+
const projectRoot = process.cwd();
|
|
683
|
+
const vaultCandidate = join2(projectRoot, ".claude", ".vault");
|
|
684
|
+
const vaultPath = existsSync2(vaultCandidate) ? vaultCandidate : void 0;
|
|
685
|
+
const result = await runHealthcheck({
|
|
686
|
+
projectRoot,
|
|
687
|
+
vaultPath,
|
|
688
|
+
tier: opts.fast ? "fast" : "all",
|
|
689
|
+
force: true
|
|
690
|
+
});
|
|
691
|
+
if (opts.json) {
|
|
692
|
+
console.log(JSON.stringify(result, null, 2));
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const banner = formatDriftBanner(result);
|
|
696
|
+
if (banner) {
|
|
697
|
+
console.log("");
|
|
698
|
+
console.log(banner);
|
|
699
|
+
} else {
|
|
700
|
+
console.log("");
|
|
701
|
+
console.log(`\u2713 no drift detected (${result.findings.length} checks ran in ${result.duration_ms}ms)`);
|
|
702
|
+
}
|
|
703
|
+
} catch (err) {
|
|
704
|
+
console.error(`drift check threw: ${err?.message ?? err}`);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
var healthcheckCmd = program.commands.find((c) => c.name() === "healthcheck");
|
|
708
|
+
if (healthcheckCmd) {
|
|
709
|
+
healthcheckCmd.hook("postAction", async (thisCmd) => {
|
|
710
|
+
const opts = thisCmd.opts();
|
|
711
|
+
await driftHealthcheckActionPostprocess({ fast: !!opts.fast, json: !!opts.json });
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
function parseAgent(input) {
|
|
715
|
+
const a = input.toLowerCase();
|
|
716
|
+
if (!SKILL_BUNDLER_AGENTS.includes(a)) {
|
|
717
|
+
console.error(`Unknown agent: ${input}. Supported: ${SKILL_BUNDLER_AGENTS.join(", ")}.`);
|
|
718
|
+
process.exit(2);
|
|
719
|
+
}
|
|
720
|
+
return a;
|
|
721
|
+
}
|
|
722
|
+
function parseScope(input) {
|
|
723
|
+
if (input !== "global" && input !== "local") {
|
|
724
|
+
console.error(`Unknown scope: ${input}. Use 'global' or 'local'.`);
|
|
725
|
+
process.exit(2);
|
|
726
|
+
}
|
|
727
|
+
return input;
|
|
728
|
+
}
|
|
729
|
+
function findSourceRoot() {
|
|
730
|
+
for (const pkg of ["semantic-memory", "semantic-sidekick"]) {
|
|
731
|
+
const installed = join2(process.cwd(), "node_modules", "@theglitchking", pkg);
|
|
732
|
+
if (existsSync2(installed)) return installed;
|
|
733
|
+
}
|
|
734
|
+
const dev = resolve2(new URL("../../", import.meta.url).pathname);
|
|
735
|
+
return dev;
|
|
736
|
+
}
|
|
737
|
+
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.");
|
|
738
|
+
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) => {
|
|
739
|
+
const scope = parseScope(opts.scope);
|
|
740
|
+
const agents = (opts.agent && opts.agent.length > 0 ? opts.agent : SKILL_BUNDLER_AGENTS).map(parseAgent);
|
|
741
|
+
const out = agents.map((a) => resolveTarget(a, scope, opts.project));
|
|
742
|
+
console.log(JSON.stringify(out, null, 2));
|
|
743
|
+
});
|
|
744
|
+
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) => {
|
|
745
|
+
const agent = parseAgent(opts.agent);
|
|
746
|
+
const scope = parseScope(opts.scope);
|
|
747
|
+
if (agent === "claude") {
|
|
748
|
+
console.error(
|
|
749
|
+
"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."
|
|
750
|
+
);
|
|
751
|
+
process.exit(2);
|
|
752
|
+
}
|
|
753
|
+
const sourceRoot = findSourceRoot();
|
|
754
|
+
const result = await installSkills({
|
|
755
|
+
agent,
|
|
756
|
+
scope,
|
|
757
|
+
sourceRoot,
|
|
758
|
+
projectRoot: opts.project,
|
|
759
|
+
version,
|
|
760
|
+
only: opts.only,
|
|
761
|
+
force: opts.force === true
|
|
762
|
+
});
|
|
763
|
+
console.log(JSON.stringify(result, null, 2));
|
|
764
|
+
if (result.installed.length === 0 && result.reason) process.exit(1);
|
|
765
|
+
});
|
|
766
|
+
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) => {
|
|
767
|
+
const agent = parseAgent(opts.agent);
|
|
768
|
+
const scope = parseScope(opts.scope);
|
|
769
|
+
if (agent === "claude") {
|
|
770
|
+
console.error("Claude skill uninstalls go through the npm uninstall flow. The skills CLI is for non-Claude agents.");
|
|
771
|
+
process.exit(2);
|
|
772
|
+
}
|
|
773
|
+
const result = await uninstallSkills({ agent, scope, projectRoot: opts.project });
|
|
774
|
+
console.log(JSON.stringify(result, null, 2));
|
|
775
|
+
});
|
|
776
|
+
skillsCmd.command("list").description("List the skill bundles shipped with this plugin version.").action(async () => {
|
|
777
|
+
const sourceRoot = findSourceRoot();
|
|
778
|
+
const shipped = await listShippedSkills(sourceRoot);
|
|
779
|
+
console.log(JSON.stringify(shipped.map((s) => s.name), null, 2));
|
|
503
780
|
});
|
|
504
781
|
program.parse();
|
|
505
782
|
//# sourceMappingURL=index.js.map
|