@skill-map/cli 0.14.1 → 0.16.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/README.md +16 -0
- package/dist/cli/tutorial/sm-tutorial.md +944 -0
- package/dist/cli.js +463 -366
- package/dist/cli.js.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +23 -7
- package/dist/kernel/index.js +8 -5
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/chunk-7PFTODKS.js +1031 -0
- package/dist/ui/{chunk-WFJRSBK6.js → chunk-A4RBO3TD.js} +1 -1
- package/dist/ui/{chunk-TEPC3SFH.js → chunk-KPEISNOV.js} +1 -1
- package/dist/ui/{chunk-T5SUVDLE.js → chunk-S5C4U3I3.js} +1 -1
- package/dist/ui/chunk-TG6IWVEC.js +54 -0
- package/dist/ui/{chunk-DOJURY6T.js → chunk-TGJQE3TH.js} +1 -1
- package/dist/ui/{chunk-G6SL4UFD.js → chunk-UGEECDPV.js} +1 -1
- package/dist/ui/{chunk-VJAWM5V3.js → chunk-UTJNQ3I2.js} +3 -3
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-Z2AVUR5B.js +1 -0
- package/package.json +2 -2
- package/dist/cli/guide/sm-guide.md +0 -798
- package/dist/ui/chunk-AVRC55YV.js +0 -971
- package/dist/ui/chunk-ZF7H74JY.js +0 -114
- package/dist/ui/main-TG4BEOVI.js +0 -1
- /package/dist/config/defaults/{skill-mapignore → skillmapignore} +0 -0
package/dist/cli.js
CHANGED
|
@@ -225,7 +225,7 @@ var JOBS_DIRNAME = "jobs";
|
|
|
225
225
|
var PLUGINS_DIRNAME = "plugins";
|
|
226
226
|
var SETTINGS_FILENAME = "settings.json";
|
|
227
227
|
var LOCAL_SETTINGS_FILENAME = "settings.local.json";
|
|
228
|
-
var IGNORE_FILENAME = ".
|
|
228
|
+
var IGNORE_FILENAME = ".skillmapignore";
|
|
229
229
|
var DEFAULT_DB_REL = `${SKILL_MAP_DIR}/${DB_FILENAME}`;
|
|
230
230
|
var GITIGNORE_ENTRIES = [
|
|
231
231
|
`${SKILL_MAP_DIR}/${LOCAL_SETTINGS_FILENAME}`,
|
|
@@ -609,7 +609,7 @@ function loadBundledIgnoreText() {
|
|
|
609
609
|
return loadDefaultsText();
|
|
610
610
|
}
|
|
611
611
|
function readIgnoreFileText(scopeRoot) {
|
|
612
|
-
const path = resolve2(scopeRoot, ".
|
|
612
|
+
const path = resolve2(scopeRoot, ".skillmapignore");
|
|
613
613
|
if (!existsSync2(path)) return void 0;
|
|
614
614
|
try {
|
|
615
615
|
return readFileSync(path, "utf8");
|
|
@@ -626,11 +626,11 @@ function loadDefaultsText() {
|
|
|
626
626
|
function readDefaultsFromDisk() {
|
|
627
627
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
628
628
|
const candidates = [
|
|
629
|
-
resolve2(here, "../../config/defaults/
|
|
629
|
+
resolve2(here, "../../config/defaults/skillmapignore"),
|
|
630
630
|
// src/kernel/scan/ → src/config/defaults/
|
|
631
|
-
resolve2(here, "../config/defaults/
|
|
631
|
+
resolve2(here, "../config/defaults/skillmapignore"),
|
|
632
632
|
// dist/cli.js → dist/config/defaults/ (siblings)
|
|
633
|
-
resolve2(here, "config/defaults/
|
|
633
|
+
resolve2(here, "config/defaults/skillmapignore")
|
|
634
634
|
];
|
|
635
635
|
for (const candidate of candidates) {
|
|
636
636
|
if (existsSync2(candidate)) {
|
|
@@ -2958,7 +2958,7 @@ var AsyncMutex = class {
|
|
|
2958
2958
|
this.#locked = true;
|
|
2959
2959
|
return;
|
|
2960
2960
|
}
|
|
2961
|
-
await new Promise((
|
|
2961
|
+
await new Promise((resolve23) => this.#waiters.push(resolve23));
|
|
2962
2962
|
this.#locked = true;
|
|
2963
2963
|
}
|
|
2964
2964
|
unlock() {
|
|
@@ -7353,109 +7353,16 @@ var GraphCommand = class extends SmCommand {
|
|
|
7353
7353
|
}
|
|
7354
7354
|
};
|
|
7355
7355
|
|
|
7356
|
-
// cli/commands/guide.ts
|
|
7357
|
-
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
7358
|
-
import { writeFile } from "fs/promises";
|
|
7359
|
-
import { dirname as dirname9, join as join10, resolve as resolve13 } from "path";
|
|
7360
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7361
|
-
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
7362
|
-
|
|
7363
|
-
// cli/i18n/guide.texts.ts
|
|
7364
|
-
var GUIDE_TEXTS = {
|
|
7365
|
-
// Success — written to stdout after `<cwd>/sm-guide.md` is created.
|
|
7366
|
-
written: 'Listo. sm-guide.md creado en {{cwd}}. Abr\xED Claude Code ac\xE1 y decile "ejecut\xE1 @sm-guide.md" para arrancar la gu\xEDa interactiva.\n',
|
|
7367
|
-
// Refusal — `sm-guide.md` already exists and `--force` was not set.
|
|
7368
|
-
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
7369
|
-
alreadyExists: "sm guide: sm-guide.md ya existe en {{cwd}}. Us\xE1 `--force` para sobrescribir.\n",
|
|
7370
|
-
// I/O failure on write or on reading the bundled SKILL source.
|
|
7371
|
-
writeFailed: "sm guide: no se pudo escribir sm-guide.md: {{message}}\n",
|
|
7372
|
-
sourceMissing: "sm guide: no se pudo leer la gu\xEDa empaquetada (SKILL.md) desde la instalaci\xF3n. Reinstal\xE1 @skill-map/cli o report\xE1 el bug.\n"
|
|
7373
|
-
};
|
|
7374
|
-
|
|
7375
|
-
// cli/commands/guide.ts
|
|
7376
|
-
var SM_GUIDE_FILENAME = "sm-guide.md";
|
|
7377
|
-
var GuideCommand = class extends SmCommand {
|
|
7378
|
-
static paths = [["guide"]];
|
|
7379
|
-
static usage = Command8.Usage({
|
|
7380
|
-
category: "Setup",
|
|
7381
|
-
description: "Materialize the interactive tester guide (sm-guide.md) in the current directory.",
|
|
7382
|
-
details: `
|
|
7383
|
-
Drops the canonical SKILL.md content as ./sm-guide.md so a tester
|
|
7384
|
-
can open Claude Code in the cwd and load the file as a skill by
|
|
7385
|
-
typing "ejecut\xE1 @sm-guide.md". Top-level only \u2014 no subdirectory
|
|
7386
|
-
is created.
|
|
7387
|
-
|
|
7388
|
-
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
7389
|
-
overwrite an existing sm-guide.md unless --force is passed.
|
|
7390
|
-
`,
|
|
7391
|
-
examples: [
|
|
7392
|
-
["Materialize the guide in the cwd", "$0 guide"],
|
|
7393
|
-
["Overwrite an existing sm-guide.md", "$0 guide --force"]
|
|
7394
|
-
]
|
|
7395
|
-
});
|
|
7396
|
-
force = Option8.Boolean("--force", false, {
|
|
7397
|
-
description: "Overwrite an existing sm-guide.md without prompting."
|
|
7398
|
-
});
|
|
7399
|
-
async run() {
|
|
7400
|
-
const ctx = defaultRuntimeContext();
|
|
7401
|
-
const target = join10(ctx.cwd, SM_GUIDE_FILENAME);
|
|
7402
|
-
if (await pathExists(target) && !this.force) {
|
|
7403
|
-
this.context.stderr.write(tx(GUIDE_TEXTS.alreadyExists, { cwd: ctx.cwd }));
|
|
7404
|
-
return ExitCode.Error;
|
|
7405
|
-
}
|
|
7406
|
-
let body;
|
|
7407
|
-
try {
|
|
7408
|
-
body = loadBundledGuideText();
|
|
7409
|
-
} catch {
|
|
7410
|
-
this.context.stderr.write(GUIDE_TEXTS.sourceMissing);
|
|
7411
|
-
return ExitCode.Error;
|
|
7412
|
-
}
|
|
7413
|
-
try {
|
|
7414
|
-
await writeFile(target, body);
|
|
7415
|
-
} catch (err) {
|
|
7416
|
-
this.context.stderr.write(
|
|
7417
|
-
tx(GUIDE_TEXTS.writeFailed, { message: formatErrorMessage(err) })
|
|
7418
|
-
);
|
|
7419
|
-
return ExitCode.Error;
|
|
7420
|
-
}
|
|
7421
|
-
this.context.stdout.write(tx(GUIDE_TEXTS.written, { cwd: ctx.cwd }));
|
|
7422
|
-
return ExitCode.Ok;
|
|
7423
|
-
}
|
|
7424
|
-
};
|
|
7425
|
-
var cachedGuide = null;
|
|
7426
|
-
function loadBundledGuideText() {
|
|
7427
|
-
if (cachedGuide !== null) return cachedGuide;
|
|
7428
|
-
cachedGuide = readGuideFromDisk();
|
|
7429
|
-
return cachedGuide;
|
|
7430
|
-
}
|
|
7431
|
-
function readGuideFromDisk() {
|
|
7432
|
-
const here = dirname9(fileURLToPath5(import.meta.url));
|
|
7433
|
-
const candidates = [
|
|
7434
|
-
// dev: src/cli/commands/ → repo-root .claude/skills/sm-guide/SKILL.md
|
|
7435
|
-
resolve13(here, "../../../.claude/skills/sm-guide/SKILL.md"),
|
|
7436
|
-
// bundled: dist/cli.js → dist/cli/guide/sm-guide.md (sibling)
|
|
7437
|
-
resolve13(here, "cli/guide/sm-guide.md"),
|
|
7438
|
-
// bundled fallback: any-depth → cli/guide/sm-guide.md
|
|
7439
|
-
resolve13(here, "../cli/guide/sm-guide.md")
|
|
7440
|
-
];
|
|
7441
|
-
for (const candidate of candidates) {
|
|
7442
|
-
if (existsSync12(candidate)) {
|
|
7443
|
-
return readFileSync10(candidate, "utf8");
|
|
7444
|
-
}
|
|
7445
|
-
}
|
|
7446
|
-
throw new Error(`SKILL.md not found in any candidate location (last tried: ${candidates[candidates.length - 1]})`);
|
|
7447
|
-
}
|
|
7448
|
-
|
|
7449
7356
|
// cli/commands/help.ts
|
|
7450
|
-
import { readFileSync as
|
|
7357
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
7451
7358
|
import { createRequire as createRequire4 } from "module";
|
|
7452
|
-
import { resolve as
|
|
7453
|
-
import { Command as
|
|
7359
|
+
import { resolve as resolve13 } from "path";
|
|
7360
|
+
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
7454
7361
|
|
|
7455
7362
|
// package.json
|
|
7456
7363
|
var package_default = {
|
|
7457
7364
|
name: "@skill-map/cli",
|
|
7458
|
-
version: "0.
|
|
7365
|
+
version: "0.16.0",
|
|
7459
7366
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
7460
7367
|
license: "MIT",
|
|
7461
7368
|
type: "module",
|
|
@@ -7514,7 +7421,7 @@ var package_default = {
|
|
|
7514
7421
|
},
|
|
7515
7422
|
dependencies: {
|
|
7516
7423
|
"@hono/node-server": "2.0.1",
|
|
7517
|
-
"@skill-map/spec": "0.
|
|
7424
|
+
"@skill-map/spec": "0.16.0",
|
|
7518
7425
|
ajv: "8.18.0",
|
|
7519
7426
|
"ajv-formats": "3.0.1",
|
|
7520
7427
|
chokidar: "5.0.0",
|
|
@@ -7631,9 +7538,9 @@ var HELP_TEXTS = {
|
|
|
7631
7538
|
};
|
|
7632
7539
|
|
|
7633
7540
|
// cli/commands/help.ts
|
|
7634
|
-
var HelpCommand = class extends
|
|
7541
|
+
var HelpCommand = class extends Command8 {
|
|
7635
7542
|
static paths = [["help"]];
|
|
7636
|
-
static usage =
|
|
7543
|
+
static usage = Command8.Usage({
|
|
7637
7544
|
category: "Introspection",
|
|
7638
7545
|
description: "Self-describing introspection. --format human|md|json.",
|
|
7639
7546
|
details: `
|
|
@@ -7647,8 +7554,8 @@ var HelpCommand = class extends Command9 {
|
|
|
7647
7554
|
json \u2014 structured surface dump per spec/cli-contract.md.
|
|
7648
7555
|
`
|
|
7649
7556
|
});
|
|
7650
|
-
verbParts =
|
|
7651
|
-
format =
|
|
7557
|
+
verbParts = Option8.Rest({ required: 0 });
|
|
7558
|
+
format = Option8.String("--format", "human");
|
|
7652
7559
|
async execute() {
|
|
7653
7560
|
const format = normalizeFormat(this.format);
|
|
7654
7561
|
if (!format) {
|
|
@@ -7770,8 +7677,8 @@ function resolveSpecVersion() {
|
|
|
7770
7677
|
try {
|
|
7771
7678
|
const req = createRequire4(import.meta.url);
|
|
7772
7679
|
const indexPath = req.resolve("@skill-map/spec/index.json");
|
|
7773
|
-
const pkgPath =
|
|
7774
|
-
const pkg = JSON.parse(
|
|
7680
|
+
const pkgPath = resolve13(indexPath, "..", "package.json");
|
|
7681
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf8"));
|
|
7775
7682
|
return pkg.version;
|
|
7776
7683
|
} catch {
|
|
7777
7684
|
return "unknown";
|
|
@@ -7966,7 +7873,7 @@ function renderCompactOverview(verbs) {
|
|
|
7966
7873
|
lines.push(HELP_TEXTS.compactFooter);
|
|
7967
7874
|
return lines.join("\n") + "\n";
|
|
7968
7875
|
}
|
|
7969
|
-
var RootHelpCommand = class extends
|
|
7876
|
+
var RootHelpCommand = class extends Command8 {
|
|
7970
7877
|
static paths = [["-h"], ["--help"]];
|
|
7971
7878
|
async execute() {
|
|
7972
7879
|
const rawDefs = this.cli.definitions();
|
|
@@ -8022,13 +7929,13 @@ function registeredVerbPaths(cli2) {
|
|
|
8022
7929
|
}
|
|
8023
7930
|
|
|
8024
7931
|
// cli/commands/init.ts
|
|
8025
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile
|
|
8026
|
-
import { join as
|
|
8027
|
-
import { Command as
|
|
7932
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
|
|
7933
|
+
import { join as join10 } from "path";
|
|
7934
|
+
import { Command as Command9, Option as Option9 } from "clipanion";
|
|
8028
7935
|
|
|
8029
7936
|
// kernel/orchestrator.ts
|
|
8030
7937
|
import { createHash } from "crypto";
|
|
8031
|
-
import { existsSync as
|
|
7938
|
+
import { existsSync as existsSync12, statSync as statSync3 } from "fs";
|
|
8032
7939
|
import { Tiktoken } from "js-tiktoken/lite";
|
|
8033
7940
|
import cl100k_base from "js-tiktoken/ranks/cl100k_base";
|
|
8034
7941
|
import yaml2 from "js-yaml";
|
|
@@ -8163,7 +8070,7 @@ function validateRoots(roots) {
|
|
|
8163
8070
|
throw new Error(ORCHESTRATOR_TEXTS.runScanRootEmptyArray);
|
|
8164
8071
|
}
|
|
8165
8072
|
for (const root of roots) {
|
|
8166
|
-
if (!
|
|
8073
|
+
if (!existsSync12(root) || !statSync3(root).isDirectory()) {
|
|
8167
8074
|
throw new Error(tx(ORCHESTRATOR_TEXTS.runScanRootMissing, { root }));
|
|
8168
8075
|
}
|
|
8169
8076
|
}
|
|
@@ -8939,15 +8846,18 @@ function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
|
|
|
8939
8846
|
}
|
|
8940
8847
|
|
|
8941
8848
|
// kernel/scan/watcher.ts
|
|
8942
|
-
import { resolve as
|
|
8849
|
+
import { resolve as resolve14, relative as relative4, sep as sep2 } from "path";
|
|
8943
8850
|
import chokidar from "chokidar";
|
|
8944
8851
|
function createChokidarWatcher(opts) {
|
|
8945
|
-
const absRoots = opts.roots.map((r) =>
|
|
8946
|
-
const
|
|
8947
|
-
const
|
|
8852
|
+
const absRoots = opts.roots.map((r) => resolve14(opts.cwd, r));
|
|
8853
|
+
const ignoreFilterOpt = opts.ignoreFilter;
|
|
8854
|
+
const getFilter = ignoreFilterOpt === void 0 ? void 0 : typeof ignoreFilterOpt === "function" ? ignoreFilterOpt : () => ignoreFilterOpt;
|
|
8855
|
+
const ignored = getFilter ? (path) => {
|
|
8856
|
+
const filter = getFilter();
|
|
8857
|
+
if (!filter) return false;
|
|
8948
8858
|
const rel = relativePathFromRoots(path, absRoots);
|
|
8949
8859
|
if (rel === null) return false;
|
|
8950
|
-
return
|
|
8860
|
+
return filter.ignores(rel);
|
|
8951
8861
|
} : void 0;
|
|
8952
8862
|
const watcher = chokidar.watch(absRoots, {
|
|
8953
8863
|
ignoreInitial: true,
|
|
@@ -9188,13 +9098,13 @@ function createCliProgressEmitter(stderr) {
|
|
|
9188
9098
|
// cli/commands/init.ts
|
|
9189
9099
|
var InitCommand = class extends SmCommand {
|
|
9190
9100
|
static paths = [["init"]];
|
|
9191
|
-
static usage =
|
|
9101
|
+
static usage = Command9.Usage({
|
|
9192
9102
|
category: "Setup",
|
|
9193
9103
|
description: "Bootstrap the current scope: scaffold .skill-map/, provision DB, run first scan.",
|
|
9194
9104
|
details: `
|
|
9195
9105
|
Project scope (default): creates ./.skill-map/ with settings.json,
|
|
9196
9106
|
settings.local.json, and skill-map.db. Drops a starter
|
|
9197
|
-
.
|
|
9107
|
+
.skillmapignore at the scope root and appends the DB + local
|
|
9198
9108
|
settings to .gitignore.
|
|
9199
9109
|
|
|
9200
9110
|
Global scope (-g): same scaffolding under ~/.skill-map/. No
|
|
@@ -9212,16 +9122,16 @@ var InitCommand = class extends SmCommand {
|
|
|
9212
9122
|
["Preview what would be created", "$0 init --dry-run"]
|
|
9213
9123
|
]
|
|
9214
9124
|
});
|
|
9215
|
-
noScan =
|
|
9125
|
+
noScan = Option9.Boolean("--no-scan", false, {
|
|
9216
9126
|
description: "Skip the first scan after scaffolding."
|
|
9217
9127
|
});
|
|
9218
|
-
force =
|
|
9219
|
-
description: "Overwrite an existing settings.json / settings.local.json / .
|
|
9128
|
+
force = Option9.Boolean("--force", false, {
|
|
9129
|
+
description: "Overwrite an existing settings.json / settings.local.json / .skillmapignore."
|
|
9220
9130
|
});
|
|
9221
|
-
strict =
|
|
9131
|
+
strict = Option9.Boolean("--strict", false, {
|
|
9222
9132
|
description: "Strict mode: fail on any layered-loader warning AND promote frontmatter warnings to errors during the first scan. Same flag as sm scan / sm config."
|
|
9223
9133
|
});
|
|
9224
|
-
dryRun =
|
|
9134
|
+
dryRun = Option9.Boolean("-n,--dry-run", false, {
|
|
9225
9135
|
description: "Preview the scope provisioning without touching the filesystem or the DB. Honours --force for the would-overwrite preview. Skips the first scan unconditionally \u2014 dry-run never persists."
|
|
9226
9136
|
});
|
|
9227
9137
|
// CLI orchestrator: paths setup + dry-run branch (delegated to
|
|
@@ -9232,7 +9142,7 @@ var InitCommand = class extends SmCommand {
|
|
|
9232
9142
|
async run() {
|
|
9233
9143
|
const ctx = defaultRuntimeContext();
|
|
9234
9144
|
const scopeRoot = this.global ? ctx.homedir : ctx.cwd;
|
|
9235
|
-
const skillMapDir =
|
|
9145
|
+
const skillMapDir = join10(scopeRoot, SKILL_MAP_DIR);
|
|
9236
9146
|
const settingsPath = defaultSettingsPath(scopeRoot);
|
|
9237
9147
|
const localPath = defaultLocalSettingsPath(scopeRoot);
|
|
9238
9148
|
const ignorePath = defaultIgnoreFilePath(scopeRoot);
|
|
@@ -9256,17 +9166,17 @@ var InitCommand = class extends SmCommand {
|
|
|
9256
9166
|
return ExitCode.Ok;
|
|
9257
9167
|
}
|
|
9258
9168
|
await mkdir2(skillMapDir, { recursive: true });
|
|
9259
|
-
await
|
|
9169
|
+
await writeFile(settingsPath, JSON.stringify({ schemaVersion: 1 }, null, 2) + "\n");
|
|
9260
9170
|
if (!await pathExists(localPath) || this.force) {
|
|
9261
|
-
await
|
|
9171
|
+
await writeFile(localPath, "{}\n");
|
|
9262
9172
|
}
|
|
9263
9173
|
if (!await pathExists(ignorePath) || this.force) {
|
|
9264
|
-
await
|
|
9174
|
+
await writeFile(ignorePath, loadBundledIgnoreText());
|
|
9265
9175
|
}
|
|
9266
9176
|
if (!this.global) {
|
|
9267
9177
|
const updated = await ensureGitignoreEntries(scopeRoot, GITIGNORE_ENTRIES);
|
|
9268
9178
|
if (updated) {
|
|
9269
|
-
const gitignorePath =
|
|
9179
|
+
const gitignorePath = join10(scopeRoot, ".gitignore");
|
|
9270
9180
|
this.context.stdout.write(
|
|
9271
9181
|
GITIGNORE_ENTRIES.length === 1 ? tx(INIT_TEXTS.gitignoreUpdatedSingular, { path: gitignorePath }) : tx(INIT_TEXTS.gitignoreUpdatedPlural, {
|
|
9272
9182
|
path: gitignorePath,
|
|
@@ -9305,7 +9215,7 @@ async function dryRunFileMessage(path) {
|
|
|
9305
9215
|
}
|
|
9306
9216
|
async function writeDryRunGitignorePlan(stdout, scopeRoot) {
|
|
9307
9217
|
const wouldAdd = await previewGitignoreEntries(scopeRoot, GITIGNORE_ENTRIES);
|
|
9308
|
-
const gitignorePath =
|
|
9218
|
+
const gitignorePath = join10(scopeRoot, ".gitignore");
|
|
9309
9219
|
if (wouldAdd.length === 0) {
|
|
9310
9220
|
stdout.write(tx(INIT_TEXTS.dryRunWouldLeaveGitignoreUnchanged, { path: gitignorePath }));
|
|
9311
9221
|
} else if (wouldAdd.length === 1) {
|
|
@@ -9380,7 +9290,7 @@ async function runFirstScan(scopeRoot, homedir3, dbPath, strict, stdout, stderr)
|
|
|
9380
9290
|
return hasErrors ? ExitCode.Issues : ExitCode.Ok;
|
|
9381
9291
|
}
|
|
9382
9292
|
async function previewGitignoreEntries(scopeRoot, entries) {
|
|
9383
|
-
const path =
|
|
9293
|
+
const path = join10(scopeRoot, ".gitignore");
|
|
9384
9294
|
const body = await pathExists(path) ? await readFile2(path, "utf8") : "";
|
|
9385
9295
|
const present = new Set(
|
|
9386
9296
|
body.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"))
|
|
@@ -9388,7 +9298,7 @@ async function previewGitignoreEntries(scopeRoot, entries) {
|
|
|
9388
9298
|
return entries.filter((entry) => !present.has(entry));
|
|
9389
9299
|
}
|
|
9390
9300
|
async function ensureGitignoreEntries(scopeRoot, entries) {
|
|
9391
|
-
const path =
|
|
9301
|
+
const path = join10(scopeRoot, ".gitignore");
|
|
9392
9302
|
let body = "";
|
|
9393
9303
|
if (await pathExists(path)) {
|
|
9394
9304
|
body = await readFile2(path, "utf8");
|
|
@@ -9405,12 +9315,12 @@ async function ensureGitignoreEntries(scopeRoot, entries) {
|
|
|
9405
9315
|
present.add(entry);
|
|
9406
9316
|
changed = true;
|
|
9407
9317
|
}
|
|
9408
|
-
if (changed) await
|
|
9318
|
+
if (changed) await writeFile(path, body);
|
|
9409
9319
|
return changed;
|
|
9410
9320
|
}
|
|
9411
9321
|
|
|
9412
9322
|
// cli/commands/history.ts
|
|
9413
|
-
import { Command as
|
|
9323
|
+
import { Command as Command10, Option as Option10 } from "clipanion";
|
|
9414
9324
|
|
|
9415
9325
|
// cli/i18n/option-validators.texts.ts
|
|
9416
9326
|
var OPTION_VALIDATORS_TEXTS = {
|
|
@@ -9499,7 +9409,7 @@ function parseStatuses(input, stderr) {
|
|
|
9499
9409
|
}
|
|
9500
9410
|
var HistoryCommand = class extends SmCommand {
|
|
9501
9411
|
static paths = [["history"]];
|
|
9502
|
-
static usage =
|
|
9412
|
+
static usage = Command10.Usage({
|
|
9503
9413
|
category: "History",
|
|
9504
9414
|
description: "Filter execution records. --json emits an array conforming to execution-record.schema.json.",
|
|
9505
9415
|
details: `
|
|
@@ -9519,12 +9429,12 @@ var HistoryCommand = class extends SmCommand {
|
|
|
9519
9429
|
["Machine-readable, scoped to one node", "$0 history -n skills/foo.md --json"]
|
|
9520
9430
|
]
|
|
9521
9431
|
});
|
|
9522
|
-
node =
|
|
9523
|
-
action =
|
|
9524
|
-
status =
|
|
9525
|
-
since =
|
|
9526
|
-
until =
|
|
9527
|
-
limit =
|
|
9432
|
+
node = Option10.String("-n", { required: false });
|
|
9433
|
+
action = Option10.String("--action", { required: false });
|
|
9434
|
+
status = Option10.String("--status", { required: false });
|
|
9435
|
+
since = Option10.String("--since", { required: false });
|
|
9436
|
+
until = Option10.String("--until", { required: false });
|
|
9437
|
+
limit = Option10.String("--limit", { required: false });
|
|
9528
9438
|
// CLI list verb: many optional filter flags (`--node`, `--action`,
|
|
9529
9439
|
// `--status`, `--since`, `--until`, `--limit`, `--json`, `--quiet`)
|
|
9530
9440
|
// each adding a guarded mutation to the filter or render path. Each
|
|
@@ -9572,7 +9482,7 @@ var HistoryCommand = class extends SmCommand {
|
|
|
9572
9482
|
};
|
|
9573
9483
|
var HistoryStatsCommand = class extends SmCommand {
|
|
9574
9484
|
static paths = [["history", "stats"]];
|
|
9575
|
-
static usage =
|
|
9485
|
+
static usage = Command10.Usage({
|
|
9576
9486
|
category: "History",
|
|
9577
9487
|
description: "Aggregate counts, tokens, periods, top nodes, and error rates over state_executions. --json conforms to history-stats.schema.json.",
|
|
9578
9488
|
details: `
|
|
@@ -9590,10 +9500,10 @@ var HistoryStatsCommand = class extends SmCommand {
|
|
|
9590
9500
|
["Top 5 nodes, JSON", "$0 history stats --top 5 --json"]
|
|
9591
9501
|
]
|
|
9592
9502
|
});
|
|
9593
|
-
since =
|
|
9594
|
-
until =
|
|
9595
|
-
period =
|
|
9596
|
-
top =
|
|
9503
|
+
since = Option10.String("--since", { required: false });
|
|
9504
|
+
until = Option10.String("--until", { required: false });
|
|
9505
|
+
period = Option10.String("--period", { required: false });
|
|
9506
|
+
top = Option10.String("--top", { required: false });
|
|
9597
9507
|
// CLI stats verb: range parsing + window flags + period flag + JSON
|
|
9598
9508
|
// branch + per-period iteration. Each branch is a single-purpose
|
|
9599
9509
|
// gate; the data work lives in `aggregateHistoryStats`.
|
|
@@ -9774,11 +9684,11 @@ function formatRow(...cols) {
|
|
|
9774
9684
|
|
|
9775
9685
|
// cli/commands/jobs.ts
|
|
9776
9686
|
import { unlink } from "fs/promises";
|
|
9777
|
-
import { Command as
|
|
9687
|
+
import { Command as Command11, Option as Option11 } from "clipanion";
|
|
9778
9688
|
|
|
9779
9689
|
// kernel/jobs/orphan-files.ts
|
|
9780
9690
|
import { readdirSync as readdirSync6, statSync as statSync4 } from "fs";
|
|
9781
|
-
import { join as
|
|
9691
|
+
import { join as join11, resolve as resolve15 } from "path";
|
|
9782
9692
|
function findOrphanJobFiles(jobsDir, referencedPaths) {
|
|
9783
9693
|
let entries;
|
|
9784
9694
|
try {
|
|
@@ -9793,7 +9703,7 @@ function findOrphanJobFiles(jobsDir, referencedPaths) {
|
|
|
9793
9703
|
const orphans = [];
|
|
9794
9704
|
for (const name of entries) {
|
|
9795
9705
|
if (!name.endsWith(".md")) continue;
|
|
9796
|
-
const abs =
|
|
9706
|
+
const abs = resolve15(join11(jobsDir, name));
|
|
9797
9707
|
if (!referencedPaths.has(abs)) orphans.push(abs);
|
|
9798
9708
|
}
|
|
9799
9709
|
orphans.sort();
|
|
@@ -9822,7 +9732,7 @@ var JOBS_TEXTS = {
|
|
|
9822
9732
|
// cli/commands/jobs.ts
|
|
9823
9733
|
var JobPruneCommand = class extends SmCommand {
|
|
9824
9734
|
static paths = [["job", "prune"]];
|
|
9825
|
-
static usage =
|
|
9735
|
+
static usage = Command11.Usage({
|
|
9826
9736
|
category: "Jobs",
|
|
9827
9737
|
description: "Retention GC for completed / failed jobs (per config policy). --orphan-files removes MD files with no DB row.",
|
|
9828
9738
|
details: `
|
|
@@ -9849,10 +9759,10 @@ var JobPruneCommand = class extends SmCommand {
|
|
|
9849
9759
|
["Preview without touching the DB", "$0 job prune --dry-run --json"]
|
|
9850
9760
|
]
|
|
9851
9761
|
});
|
|
9852
|
-
orphanFiles =
|
|
9762
|
+
orphanFiles = Option11.Boolean("--orphan-files", false, {
|
|
9853
9763
|
description: "Also remove MD files in .skill-map/jobs/ that have no matching state_jobs row."
|
|
9854
9764
|
});
|
|
9855
|
-
dryRun =
|
|
9765
|
+
dryRun = Option11.Boolean("-n,--dry-run", false, {
|
|
9856
9766
|
description: "Report what would be pruned without touching the DB or filesystem."
|
|
9857
9767
|
});
|
|
9858
9768
|
async run() {
|
|
@@ -9969,7 +9879,7 @@ function formatPolicy(seconds) {
|
|
|
9969
9879
|
}
|
|
9970
9880
|
|
|
9971
9881
|
// cli/commands/list.ts
|
|
9972
|
-
import { Command as
|
|
9882
|
+
import { Command as Command12, Option as Option12 } from "clipanion";
|
|
9973
9883
|
|
|
9974
9884
|
// cli/i18n/list.texts.ts
|
|
9975
9885
|
var LIST_TEXTS = {
|
|
@@ -9997,7 +9907,7 @@ var SORT_BY = {
|
|
|
9997
9907
|
var PATH_COL_WIDTH = 50;
|
|
9998
9908
|
var ListCommand = class extends SmCommand {
|
|
9999
9909
|
static paths = [["list"]];
|
|
10000
|
-
static usage =
|
|
9910
|
+
static usage = Command12.Usage({
|
|
10001
9911
|
category: "Browse",
|
|
10002
9912
|
description: "Tabular listing of nodes. --json emits an array conforming to node.schema.json.",
|
|
10003
9913
|
details: `
|
|
@@ -10018,10 +9928,10 @@ var ListCommand = class extends SmCommand {
|
|
|
10018
9928
|
["Only nodes with issues, machine-readable", "$0 list --issue --json"]
|
|
10019
9929
|
]
|
|
10020
9930
|
});
|
|
10021
|
-
kind =
|
|
10022
|
-
issue =
|
|
10023
|
-
sortBy =
|
|
10024
|
-
limit =
|
|
9931
|
+
kind = Option12.String("--kind", { required: false });
|
|
9932
|
+
issue = Option12.Boolean("--issue", false);
|
|
9933
|
+
sortBy = Option12.String("--sort-by", { required: false });
|
|
9934
|
+
limit = Option12.String("--limit", { required: false });
|
|
10025
9935
|
async run() {
|
|
10026
9936
|
let sortColumn = "path";
|
|
10027
9937
|
let sortDirection = "asc";
|
|
@@ -10123,7 +10033,7 @@ function formatRow2(path, kind, out, inCount, ext, issues, bytes) {
|
|
|
10123
10033
|
}
|
|
10124
10034
|
|
|
10125
10035
|
// cli/commands/orphans.ts
|
|
10126
|
-
import { Command as
|
|
10036
|
+
import { Command as Command13, Option as Option13 } from "clipanion";
|
|
10127
10037
|
|
|
10128
10038
|
// cli/i18n/orphans.texts.ts
|
|
10129
10039
|
var ORPHANS_TEXTS = {
|
|
@@ -10178,7 +10088,7 @@ function isStringArray(v) {
|
|
|
10178
10088
|
}
|
|
10179
10089
|
var OrphansCommand = class extends SmCommand {
|
|
10180
10090
|
static paths = [["orphans"]];
|
|
10181
|
-
static usage =
|
|
10091
|
+
static usage = Command13.Usage({
|
|
10182
10092
|
category: "Browse",
|
|
10183
10093
|
description: "List orphan / auto-rename issues from the last scan. --json emits an array conforming to issue.schema.json.",
|
|
10184
10094
|
details: `
|
|
@@ -10193,7 +10103,7 @@ var OrphansCommand = class extends SmCommand {
|
|
|
10193
10103
|
["Just the ambiguous ones, JSON", "$0 orphans --kind ambiguous --json"]
|
|
10194
10104
|
]
|
|
10195
10105
|
});
|
|
10196
|
-
kind =
|
|
10106
|
+
kind = Option13.String("--kind", { required: false });
|
|
10197
10107
|
async run() {
|
|
10198
10108
|
let ruleFilter = null;
|
|
10199
10109
|
if (this.kind !== void 0) {
|
|
@@ -10231,7 +10141,7 @@ var OrphansCommand = class extends SmCommand {
|
|
|
10231
10141
|
};
|
|
10232
10142
|
var OrphansReconcileCommand = class extends SmCommand {
|
|
10233
10143
|
static paths = [["orphans", "reconcile"]];
|
|
10234
|
-
static usage =
|
|
10144
|
+
static usage = Command13.Usage({
|
|
10235
10145
|
category: "Browse",
|
|
10236
10146
|
description: "Migrate state_* FKs from an orphan path to a live node, resolving the orphan issue.",
|
|
10237
10147
|
details: `
|
|
@@ -10247,9 +10157,9 @@ var OrphansReconcileCommand = class extends SmCommand {
|
|
|
10247
10157
|
["Reattach orphan history", "$0 orphans reconcile skills/old.md --to skills/new.md"]
|
|
10248
10158
|
]
|
|
10249
10159
|
});
|
|
10250
|
-
orphanPath =
|
|
10251
|
-
to =
|
|
10252
|
-
dryRun =
|
|
10160
|
+
orphanPath = Option13.String({ required: true });
|
|
10161
|
+
to = Option13.String("--to", { required: true });
|
|
10162
|
+
dryRun = Option13.Boolean("-n,--dry-run", false);
|
|
10253
10163
|
async run() {
|
|
10254
10164
|
const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
|
|
10255
10165
|
if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
|
|
@@ -10319,7 +10229,7 @@ var OrphansReconcileCommand = class extends SmCommand {
|
|
|
10319
10229
|
};
|
|
10320
10230
|
var OrphansUndoRenameCommand = class extends SmCommand {
|
|
10321
10231
|
static paths = [["orphans", "undo-rename"]];
|
|
10322
|
-
static usage =
|
|
10232
|
+
static usage = Command13.Usage({
|
|
10323
10233
|
category: "Browse",
|
|
10324
10234
|
description: "Reverse a medium- or ambiguous-confidence auto-rename. Migrates state_* FKs back, emits a new orphan on the prior path.",
|
|
10325
10235
|
details: `
|
|
@@ -10339,10 +10249,10 @@ var OrphansUndoRenameCommand = class extends SmCommand {
|
|
|
10339
10249
|
["Undo an ambiguous, picking a candidate", "$0 orphans undo-rename skills/new.md --from skills/old-a.md"]
|
|
10340
10250
|
]
|
|
10341
10251
|
});
|
|
10342
|
-
newPath =
|
|
10343
|
-
from =
|
|
10344
|
-
force =
|
|
10345
|
-
dryRun =
|
|
10252
|
+
newPath = Option13.String({ required: true });
|
|
10253
|
+
from = Option13.String("--from", { required: false });
|
|
10254
|
+
force = Option13.Boolean("--force", false);
|
|
10255
|
+
dryRun = Option13.Boolean("-n,--dry-run", false);
|
|
10346
10256
|
async run() {
|
|
10347
10257
|
const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
|
|
10348
10258
|
if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
|
|
@@ -10506,9 +10416,9 @@ var ORPHANS_COMMANDS = [
|
|
|
10506
10416
|
];
|
|
10507
10417
|
|
|
10508
10418
|
// cli/commands/plugins.ts
|
|
10509
|
-
import { existsSync as
|
|
10510
|
-
import { join as
|
|
10511
|
-
import { Command as
|
|
10419
|
+
import { existsSync as existsSync13 } from "fs";
|
|
10420
|
+
import { join as join12, resolve as resolve16 } from "path";
|
|
10421
|
+
import { Command as Command14, Option as Option14 } from "clipanion";
|
|
10512
10422
|
|
|
10513
10423
|
// cli/i18n/plugins.texts.ts
|
|
10514
10424
|
var PLUGINS_TEXTS = {
|
|
@@ -10555,8 +10465,8 @@ var PLUGINS_TEXTS = {
|
|
|
10555
10465
|
rowStatusOkPad: "ok ",
|
|
10556
10466
|
rowStatusOffPad: "off ",
|
|
10557
10467
|
builtInBundleHeader: "{{status}} {{id}}@built-in (granularity={{granularity}})",
|
|
10558
|
-
builtInBundleKindsLine: "
|
|
10559
|
-
builtInExtensionRow: "
|
|
10468
|
+
builtInBundleKindsLine: " {{kinds}}",
|
|
10469
|
+
builtInExtensionRow: "{{stat}} {{kind}}:{{qualifiedId}}@{{version}}",
|
|
10560
10470
|
pluginRow: "{{statusIcon}} {{id}}@{{version}}{{granularitySuffix}}{{tail}}",
|
|
10561
10471
|
pluginRowGranularitySuffix: " (granularity={{granularity}})",
|
|
10562
10472
|
pluginRowTailEnabled: " \xB7 {{kinds}}",
|
|
@@ -10584,7 +10494,7 @@ var PLUGINS_TEXTS = {
|
|
|
10584
10494
|
|
|
10585
10495
|
// cli/commands/plugins.ts
|
|
10586
10496
|
function resolveSearchPaths2(opts, cwd, homedir3) {
|
|
10587
|
-
if (opts.pluginDir) return [
|
|
10497
|
+
if (opts.pluginDir) return [resolve16(opts.pluginDir)];
|
|
10588
10498
|
const ctx = { cwd, homedir: homedir3 };
|
|
10589
10499
|
const project = defaultProjectPluginsDir(ctx);
|
|
10590
10500
|
const user = defaultUserPluginsDir(ctx);
|
|
@@ -10653,12 +10563,12 @@ function builtInRows(resolveEnabled) {
|
|
|
10653
10563
|
}
|
|
10654
10564
|
var PluginsListCommand = class extends SmCommand {
|
|
10655
10565
|
static paths = [["plugins", "list"]];
|
|
10656
|
-
static usage =
|
|
10566
|
+
static usage = Command14.Usage({
|
|
10657
10567
|
category: "Plugins",
|
|
10658
10568
|
description: "List discovered plugins and their load status.",
|
|
10659
10569
|
details: "Scans <scope>/.skill-map/plugins and ~/.skill-map/plugins (or --plugin-dir <path>). Built-in bundles (claude, core) are listed alongside user plugins."
|
|
10660
10570
|
});
|
|
10661
|
-
pluginDir =
|
|
10571
|
+
pluginDir = Option14.String("--plugin-dir", { required: false });
|
|
10662
10572
|
async run() {
|
|
10663
10573
|
const plugins = await loadAll({ global: this.global, pluginDir: this.pluginDir });
|
|
10664
10574
|
const resolveEnabled = await buildResolver(this.global);
|
|
@@ -10688,13 +10598,15 @@ function renderBuiltInBundleRow(bundle) {
|
|
|
10688
10598
|
})
|
|
10689
10599
|
);
|
|
10690
10600
|
if (bundle.granularity === "bundle") {
|
|
10691
|
-
const
|
|
10692
|
-
|
|
10601
|
+
for (const ext of bundle.extensions) {
|
|
10602
|
+
const line = `${ext.kind}:${qualifiedExtensionId(bundle.id, ext.id)}@${ext.version}`;
|
|
10603
|
+
lines.push(tx(PLUGINS_TEXTS.builtInBundleKindsLine, { kinds: line }));
|
|
10604
|
+
}
|
|
10693
10605
|
} else {
|
|
10694
10606
|
for (const ext of bundle.extensions) {
|
|
10695
10607
|
lines.push(
|
|
10696
10608
|
tx(PLUGINS_TEXTS.builtInExtensionRow, {
|
|
10697
|
-
stat: ext.enabled ? PLUGINS_TEXTS.
|
|
10609
|
+
stat: ext.enabled ? PLUGINS_TEXTS.rowStatusOk : PLUGINS_TEXTS.rowStatusOff,
|
|
10698
10610
|
kind: ext.kind,
|
|
10699
10611
|
qualifiedId: qualifiedExtensionId(bundle.id, ext.id),
|
|
10700
10612
|
version: ext.version
|
|
@@ -10720,12 +10632,12 @@ function renderPluginRow(p) {
|
|
|
10720
10632
|
}
|
|
10721
10633
|
var PluginsShowCommand = class extends SmCommand {
|
|
10722
10634
|
static paths = [["plugins", "show"]];
|
|
10723
|
-
static usage =
|
|
10635
|
+
static usage = Command14.Usage({
|
|
10724
10636
|
category: "Plugins",
|
|
10725
10637
|
description: "Show a single plugin's manifest + loaded extensions."
|
|
10726
10638
|
});
|
|
10727
|
-
id =
|
|
10728
|
-
pluginDir =
|
|
10639
|
+
id = Option14.String({ required: true });
|
|
10640
|
+
pluginDir = Option14.String("--plugin-dir", { required: false });
|
|
10729
10641
|
async run() {
|
|
10730
10642
|
const plugins = await loadAll({ global: this.global, pluginDir: this.pluginDir });
|
|
10731
10643
|
const resolveEnabled = await buildResolver(this.global);
|
|
@@ -10902,7 +10814,7 @@ function appendUnknownKindWarnings(out, extractorQualifiedId, applicableKinds, k
|
|
|
10902
10814
|
}
|
|
10903
10815
|
function expandHome(p, homedir3) {
|
|
10904
10816
|
if (p === "~") return homedir3;
|
|
10905
|
-
if (p.startsWith("~/")) return
|
|
10817
|
+
if (p.startsWith("~/")) return join12(homedir3, p.slice(2));
|
|
10906
10818
|
return p;
|
|
10907
10819
|
}
|
|
10908
10820
|
function collectExplorationDirWarnings(plugins, homedir3) {
|
|
@@ -10911,7 +10823,7 @@ function collectExplorationDirWarnings(plugins, homedir3) {
|
|
|
10911
10823
|
const dir = instance["explorationDir"];
|
|
10912
10824
|
if (typeof dir !== "string" || dir.length === 0) return;
|
|
10913
10825
|
const resolved = expandHome(dir, homedir3);
|
|
10914
|
-
if (!
|
|
10826
|
+
if (!existsSync13(resolved)) {
|
|
10915
10827
|
out.push({
|
|
10916
10828
|
providerQualifiedId: qualifiedExtensionId(pluginId, id),
|
|
10917
10829
|
explorationDir: dir,
|
|
@@ -10923,12 +10835,12 @@ function collectExplorationDirWarnings(plugins, homedir3) {
|
|
|
10923
10835
|
}
|
|
10924
10836
|
var PluginsDoctorCommand = class extends SmCommand {
|
|
10925
10837
|
static paths = [["plugins", "doctor"]];
|
|
10926
|
-
static usage =
|
|
10838
|
+
static usage = Command14.Usage({
|
|
10927
10839
|
category: "Plugins",
|
|
10928
10840
|
description: "Run the full load pass and summarise by failure mode.",
|
|
10929
10841
|
details: "Exit code 0 when every plugin loads or is intentionally disabled; 1 when any plugin is in an error / incompat state."
|
|
10930
10842
|
});
|
|
10931
|
-
pluginDir =
|
|
10843
|
+
pluginDir = Option14.String("--plugin-dir", { required: false });
|
|
10932
10844
|
// Doctor verb: counts by status + applicableKinds warnings +
|
|
10933
10845
|
// explorationDir warnings + bad-plugins issues, each with its own
|
|
10934
10846
|
// gated render. Branching is intrinsic to the multi-section diagnostic
|
|
@@ -11094,8 +11006,8 @@ function resolveToggleTarget(id, catalogue, verb) {
|
|
|
11094
11006
|
return { key: bundle.id };
|
|
11095
11007
|
}
|
|
11096
11008
|
var TogglePluginsBase = class extends SmCommand {
|
|
11097
|
-
all =
|
|
11098
|
-
id =
|
|
11009
|
+
all = Option14.Boolean("--all", false);
|
|
11010
|
+
id = Option14.String({ required: false });
|
|
11099
11011
|
// eslint-disable-next-line complexity
|
|
11100
11012
|
async toggle(enabled) {
|
|
11101
11013
|
const verb = enabled ? "enable" : "disable";
|
|
@@ -11146,7 +11058,7 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
11146
11058
|
};
|
|
11147
11059
|
var PluginsEnableCommand = class extends TogglePluginsBase {
|
|
11148
11060
|
static paths = [["plugins", "enable"]];
|
|
11149
|
-
static usage =
|
|
11061
|
+
static usage = Command14.Usage({
|
|
11150
11062
|
category: "Plugins",
|
|
11151
11063
|
description: "Enable a plugin (or --all). Persists in config_plugins.",
|
|
11152
11064
|
details: `
|
|
@@ -11168,7 +11080,7 @@ var PluginsEnableCommand = class extends TogglePluginsBase {
|
|
|
11168
11080
|
};
|
|
11169
11081
|
var PluginsDisableCommand = class extends TogglePluginsBase {
|
|
11170
11082
|
static paths = [["plugins", "disable"]];
|
|
11171
|
-
static usage =
|
|
11083
|
+
static usage = Command14.Usage({
|
|
11172
11084
|
category: "Plugins",
|
|
11173
11085
|
description: "Disable a plugin (or --all). Persists in config_plugins; does not delete files.",
|
|
11174
11086
|
details: `
|
|
@@ -11204,8 +11116,8 @@ var PLUGIN_COMMANDS = [
|
|
|
11204
11116
|
|
|
11205
11117
|
// cli/commands/refresh.ts
|
|
11206
11118
|
import { readFile as readFile3 } from "fs/promises";
|
|
11207
|
-
import { resolve as
|
|
11208
|
-
import { Command as
|
|
11119
|
+
import { resolve as resolve18 } from "path";
|
|
11120
|
+
import { Command as Command15, Option as Option15 } from "clipanion";
|
|
11209
11121
|
|
|
11210
11122
|
// cli/i18n/refresh.texts.ts
|
|
11211
11123
|
var REFRESH_TEXTS = {
|
|
@@ -11234,12 +11146,12 @@ var REFRESH_TEXTS = {
|
|
|
11234
11146
|
};
|
|
11235
11147
|
|
|
11236
11148
|
// cli/util/path-guard.ts
|
|
11237
|
-
import { isAbsolute as isAbsolute3, resolve as
|
|
11149
|
+
import { isAbsolute as isAbsolute3, resolve as resolve17, sep as sep3 } from "path";
|
|
11238
11150
|
function assertContained2(cwd, rel) {
|
|
11239
11151
|
if (isAbsolute3(rel)) {
|
|
11240
11152
|
throw new Error(`node path is absolute, refusing to read: ${rel}`);
|
|
11241
11153
|
}
|
|
11242
|
-
const abs =
|
|
11154
|
+
const abs = resolve17(cwd, rel);
|
|
11243
11155
|
if (abs !== cwd && !abs.startsWith(cwd + sep3)) {
|
|
11244
11156
|
throw new Error(`node path escapes repo root: ${rel}`);
|
|
11245
11157
|
}
|
|
@@ -11248,7 +11160,7 @@ function assertContained2(cwd, rel) {
|
|
|
11248
11160
|
// cli/commands/refresh.ts
|
|
11249
11161
|
var RefreshCommand = class extends SmCommand {
|
|
11250
11162
|
static paths = [["refresh"]];
|
|
11251
|
-
static usage =
|
|
11163
|
+
static usage = Command15.Usage({
|
|
11252
11164
|
category: "Scan",
|
|
11253
11165
|
description: "Refresh enrichment rows: granular (single node) or batch (every stale row).",
|
|
11254
11166
|
details: `
|
|
@@ -11273,11 +11185,11 @@ var RefreshCommand = class extends SmCommand {
|
|
|
11273
11185
|
["Refresh every node with stale enrichments", "$0 refresh --stale"]
|
|
11274
11186
|
]
|
|
11275
11187
|
});
|
|
11276
|
-
nodePath =
|
|
11277
|
-
stale =
|
|
11188
|
+
nodePath = Option15.String({ name: "node", required: false });
|
|
11189
|
+
stale = Option15.Boolean("--stale", false, {
|
|
11278
11190
|
description: "Refresh every node whose probabilistic enrichment row is flagged stale=1."
|
|
11279
11191
|
});
|
|
11280
|
-
noPlugins =
|
|
11192
|
+
noPlugins = Option15.Boolean("--no-plugins", false, {
|
|
11281
11193
|
description: "Skip drop-in plugin discovery; use only the built-in extractor set."
|
|
11282
11194
|
});
|
|
11283
11195
|
// The remaining cyclomatic count comes from CLI ergonomics that don't
|
|
@@ -11413,7 +11325,7 @@ var RefreshCommand = class extends SmCommand {
|
|
|
11413
11325
|
let body;
|
|
11414
11326
|
try {
|
|
11415
11327
|
assertContained2(cwd, node.path);
|
|
11416
|
-
const raw = await readFile3(
|
|
11328
|
+
const raw = await readFile3(resolve18(cwd, node.path), "utf8");
|
|
11417
11329
|
body = stripFrontmatterFence(raw);
|
|
11418
11330
|
} catch (err) {
|
|
11419
11331
|
this.context.stderr.write(
|
|
@@ -11462,7 +11374,7 @@ function stripFrontmatterFence(text) {
|
|
|
11462
11374
|
var REFRESH_COMMANDS = [RefreshCommand];
|
|
11463
11375
|
|
|
11464
11376
|
// cli/commands/scan.ts
|
|
11465
|
-
import { Command as
|
|
11377
|
+
import { Command as Command17, Option as Option17 } from "clipanion";
|
|
11466
11378
|
|
|
11467
11379
|
// cli/i18n/scan.texts.ts
|
|
11468
11380
|
var SCAN_TEXTS = {
|
|
@@ -11654,7 +11566,8 @@ async function runEphemeralPath(opts, dbPath, strict, loadPrior, runScanWith) {
|
|
|
11654
11566
|
}
|
|
11655
11567
|
|
|
11656
11568
|
// cli/commands/watch.ts
|
|
11657
|
-
import {
|
|
11569
|
+
import { resolve as resolve19 } from "path";
|
|
11570
|
+
import { Command as Command16, Option as Option16 } from "clipanion";
|
|
11658
11571
|
|
|
11659
11572
|
// cli/i18n/watch.texts.ts
|
|
11660
11573
|
var WATCH_TEXTS = {
|
|
@@ -11677,20 +11590,24 @@ async function runWatchLoop(opts) {
|
|
|
11677
11590
|
const { context } = opts;
|
|
11678
11591
|
const runtimeCtx = defaultRuntimeContext();
|
|
11679
11592
|
const { cwd } = runtimeCtx;
|
|
11593
|
+
const loadEffectiveConfig = () => loadConfig({ scope: "project", strict: opts.strict, ...runtimeCtx }).effective;
|
|
11594
|
+
const buildCurrentIgnoreFilter = (cfgIn) => {
|
|
11595
|
+
const text = readIgnoreFileText(cwd);
|
|
11596
|
+
const filterOpts = {};
|
|
11597
|
+
if (cfgIn.ignore.length > 0) filterOpts.configIgnore = cfgIn.ignore;
|
|
11598
|
+
if (text !== void 0) filterOpts.ignoreFileText = text;
|
|
11599
|
+
return buildIgnoreFilter(filterOpts);
|
|
11600
|
+
};
|
|
11680
11601
|
let cfg;
|
|
11681
11602
|
try {
|
|
11682
|
-
cfg =
|
|
11603
|
+
cfg = loadEffectiveConfig();
|
|
11683
11604
|
} catch (err) {
|
|
11684
11605
|
const message = formatErrorMessage(err);
|
|
11685
11606
|
context.stderr.write(tx(WATCH_TEXTS.configLoadFailure, { message }));
|
|
11686
11607
|
return ExitCode.Error;
|
|
11687
11608
|
}
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
if (cfg.ignore.length > 0) ignoreFilterOpts.configIgnore = cfg.ignore;
|
|
11691
|
-
if (ignoreFileText !== void 0) ignoreFilterOpts.ignoreFileText = ignoreFileText;
|
|
11692
|
-
const ignoreFilter = buildIgnoreFilter(ignoreFilterOpts);
|
|
11693
|
-
const strict = opts.strict || cfg.scan.strict === true;
|
|
11609
|
+
let ignoreFilter = buildCurrentIgnoreFilter(cfg);
|
|
11610
|
+
let strict = opts.strict || cfg.scan.strict === true;
|
|
11694
11611
|
const debounceMs = cfg.scan.watch.debounceMs;
|
|
11695
11612
|
const dbPath = defaultProjectDbPath(runtimeCtx);
|
|
11696
11613
|
const pluginRuntime = opts.noPlugins ? emptyPluginRuntime() : await loadPluginRuntime({ scope: "project" });
|
|
@@ -11799,7 +11716,11 @@ async function runWatchLoop(opts) {
|
|
|
11799
11716
|
roots: opts.roots,
|
|
11800
11717
|
cwd,
|
|
11801
11718
|
debounceMs,
|
|
11802
|
-
|
|
11719
|
+
// Pass a getter, NOT the filter directly: the meta-file watcher
|
|
11720
|
+
// below mutates `ignoreFilter` after a `.skillmapignore` /
|
|
11721
|
+
// `.skill-map/settings.json` edit, and chokidar's `ignored`
|
|
11722
|
+
// predicate must read the current value on every event.
|
|
11723
|
+
ignoreFilter: () => ignoreFilter,
|
|
11803
11724
|
onBatch: async () => {
|
|
11804
11725
|
const next = await handleBatch();
|
|
11805
11726
|
if (next === "stop") {
|
|
@@ -11811,6 +11732,29 @@ async function runWatchLoop(opts) {
|
|
|
11811
11732
|
context.stderr.write(tx(WATCH_TEXTS.watcherError, { message: err.message }));
|
|
11812
11733
|
}
|
|
11813
11734
|
});
|
|
11735
|
+
const metaWatcher = createChokidarWatcher({
|
|
11736
|
+
roots: [
|
|
11737
|
+
resolve19(cwd, ".skillmapignore"),
|
|
11738
|
+
resolve19(cwd, ".skill-map", "settings.json")
|
|
11739
|
+
],
|
|
11740
|
+
cwd,
|
|
11741
|
+
debounceMs,
|
|
11742
|
+
onBatch: async () => {
|
|
11743
|
+
if (stopRequested) return;
|
|
11744
|
+
try {
|
|
11745
|
+
cfg = loadEffectiveConfig();
|
|
11746
|
+
ignoreFilter = buildCurrentIgnoreFilter(cfg);
|
|
11747
|
+
strict = opts.strict || cfg.scan.strict === true;
|
|
11748
|
+
await handleBatch();
|
|
11749
|
+
} catch (err) {
|
|
11750
|
+
const message = formatErrorMessage(err);
|
|
11751
|
+
context.stderr.write(tx(WATCH_TEXTS.batchFailed, { message }));
|
|
11752
|
+
}
|
|
11753
|
+
},
|
|
11754
|
+
onError: (err) => {
|
|
11755
|
+
context.stderr.write(tx(WATCH_TEXTS.watcherError, { message: err.message }));
|
|
11756
|
+
}
|
|
11757
|
+
});
|
|
11814
11758
|
const onSignal = () => {
|
|
11815
11759
|
if (stopRequested) return;
|
|
11816
11760
|
stopRequested = true;
|
|
@@ -11819,12 +11763,14 @@ async function runWatchLoop(opts) {
|
|
|
11819
11763
|
process.once("SIGINT", onSignal);
|
|
11820
11764
|
process.once("SIGTERM", onSignal);
|
|
11821
11765
|
await watcher.ready;
|
|
11766
|
+
await metaWatcher.ready;
|
|
11822
11767
|
if (!opts.json) {
|
|
11823
11768
|
context.stderr.write(WATCH_TEXTS.ready);
|
|
11824
11769
|
}
|
|
11825
11770
|
await stopped;
|
|
11826
11771
|
process.removeListener("SIGINT", onSignal);
|
|
11827
11772
|
process.removeListener("SIGTERM", onSignal);
|
|
11773
|
+
await metaWatcher.close();
|
|
11828
11774
|
await watcher.close();
|
|
11829
11775
|
if (!opts.json) {
|
|
11830
11776
|
context.stderr.write(tx(WATCH_TEXTS.stopped, { batchCount }));
|
|
@@ -11833,13 +11779,13 @@ async function runWatchLoop(opts) {
|
|
|
11833
11779
|
}
|
|
11834
11780
|
var WatchCommand = class extends SmCommand {
|
|
11835
11781
|
static paths = [["watch"]];
|
|
11836
|
-
static usage =
|
|
11782
|
+
static usage = Command16.Usage({
|
|
11837
11783
|
category: "Scan",
|
|
11838
11784
|
description: "Watch roots and run an incremental scan after each debounced batch of filesystem events.",
|
|
11839
11785
|
details: `
|
|
11840
11786
|
Long-running version of 'sm scan --changed'. Subscribes to the
|
|
11841
11787
|
given roots via chokidar, applies the same ignore chain
|
|
11842
|
-
(.
|
|
11788
|
+
(.skillmapignore + config.ignore + bundled defaults), and
|
|
11843
11789
|
triggers an incremental scan after each debounced batch.
|
|
11844
11790
|
|
|
11845
11791
|
Default debounce is 300ms; configure via 'scan.watch.debounceMs'
|
|
@@ -11857,17 +11803,17 @@ var WatchCommand = class extends SmCommand {
|
|
|
11857
11803
|
["Stream ScanResult per batch as ndjson", "$0 watch --json"]
|
|
11858
11804
|
]
|
|
11859
11805
|
});
|
|
11860
|
-
roots =
|
|
11861
|
-
noTokens =
|
|
11806
|
+
roots = Option16.Rest({ name: "roots" });
|
|
11807
|
+
noTokens = Option16.Boolean("--no-tokens", false, {
|
|
11862
11808
|
description: "Skip per-node token counts (cl100k_base BPE)."
|
|
11863
11809
|
});
|
|
11864
|
-
strict =
|
|
11810
|
+
strict = Option16.Boolean("--strict", false, {
|
|
11865
11811
|
description: "Promote frontmatter-validation findings from warn to error inside each batch. Does not change the watcher exit code."
|
|
11866
11812
|
});
|
|
11867
|
-
noPlugins =
|
|
11813
|
+
noPlugins = Option16.Boolean("--no-plugins", false, {
|
|
11868
11814
|
description: "Skip drop-in plugin discovery for the watcher session."
|
|
11869
11815
|
});
|
|
11870
|
-
maxConsecutiveFailures =
|
|
11816
|
+
maxConsecutiveFailures = Option16.String("--max-consecutive-failures", {
|
|
11871
11817
|
required: false,
|
|
11872
11818
|
description: "Shut down with exit 2 after N consecutive batch failures (default 5; 0 disables the breaker)."
|
|
11873
11819
|
});
|
|
@@ -11905,7 +11851,7 @@ function parseBreakerLimit(raw, stderr) {
|
|
|
11905
11851
|
// cli/commands/scan.ts
|
|
11906
11852
|
var ScanCommand = class extends SmCommand {
|
|
11907
11853
|
static paths = [["scan"]];
|
|
11908
|
-
static usage =
|
|
11854
|
+
static usage = Command17.Usage({
|
|
11909
11855
|
category: "Scan",
|
|
11910
11856
|
description: "Scan roots for markdown nodes, run extractors and rules.",
|
|
11911
11857
|
details: `
|
|
@@ -11934,29 +11880,29 @@ var ScanCommand = class extends SmCommand {
|
|
|
11934
11880
|
["What would the next incremental scan persist?", "$0 scan --changed -n --json"]
|
|
11935
11881
|
]
|
|
11936
11882
|
});
|
|
11937
|
-
roots =
|
|
11938
|
-
noBuiltIns =
|
|
11883
|
+
roots = Option17.Rest({ name: "roots" });
|
|
11884
|
+
noBuiltIns = Option17.Boolean("--no-built-ins", false, {
|
|
11939
11885
|
description: "Skip the built-in extension set. Yields a zero-filled ScanResult (kernel-empty-boot parity); skips DB persistence."
|
|
11940
11886
|
});
|
|
11941
|
-
noPlugins =
|
|
11887
|
+
noPlugins = Option17.Boolean("--no-plugins", false, {
|
|
11942
11888
|
description: "Skip drop-in plugin discovery. Only the built-in set runs. Combine with --no-built-ins for a fully empty pipeline."
|
|
11943
11889
|
});
|
|
11944
|
-
noTokens =
|
|
11890
|
+
noTokens = Option17.Boolean("--no-tokens", false, {
|
|
11945
11891
|
description: "Skip per-node token counts (cl100k_base BPE). Leaves node.tokens undefined; spec-valid since the field is optional."
|
|
11946
11892
|
});
|
|
11947
|
-
dryRun =
|
|
11893
|
+
dryRun = Option17.Boolean("-n,--dry-run", false, {
|
|
11948
11894
|
description: "Run the scan in memory and skip every DB write. Combined with --changed, still opens the DB read-side to load the prior snapshot."
|
|
11949
11895
|
});
|
|
11950
|
-
changed =
|
|
11896
|
+
changed = Option17.Boolean("--changed", false, {
|
|
11951
11897
|
description: "Incremental scan: reuse unchanged nodes from the persisted prior snapshot. Degrades to a full scan if no prior snapshot exists."
|
|
11952
11898
|
});
|
|
11953
|
-
allowEmpty =
|
|
11899
|
+
allowEmpty = Option17.Boolean("--allow-empty", false, {
|
|
11954
11900
|
description: "Allow a zero-result scan to wipe an already-populated DB (replace-all replace by zero rows). Off by default to avoid the typo-trap where an invalid root silently clears your data."
|
|
11955
11901
|
});
|
|
11956
|
-
strict =
|
|
11902
|
+
strict = Option17.Boolean("--strict", false, {
|
|
11957
11903
|
description: "Promote frontmatter-validation findings from warn to error (exit code 1 on any violation). Overrides scan.strict from config when both are set."
|
|
11958
11904
|
});
|
|
11959
|
-
watch =
|
|
11905
|
+
watch = Option17.Boolean("--watch", false, {
|
|
11960
11906
|
description: "Long-running mode: watch the roots and trigger an incremental scan after each debounced batch of filesystem events. Alias of `sm watch`."
|
|
11961
11907
|
});
|
|
11962
11908
|
async run() {
|
|
@@ -12054,11 +12000,11 @@ var ScanCommand = class extends SmCommand {
|
|
|
12054
12000
|
};
|
|
12055
12001
|
|
|
12056
12002
|
// cli/commands/scan-compare.ts
|
|
12057
|
-
import { existsSync as
|
|
12058
|
-
import { Command as
|
|
12003
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
12004
|
+
import { Command as Command18, Option as Option18 } from "clipanion";
|
|
12059
12005
|
var ScanCompareCommand = class extends SmCommand {
|
|
12060
12006
|
static paths = [["scan", "compare-with"]];
|
|
12061
|
-
static usage =
|
|
12007
|
+
static usage = Command18.Usage({
|
|
12062
12008
|
category: "Scan",
|
|
12063
12009
|
description: "Run a fresh scan in memory and emit a delta against the saved ScanResult dump at <dump>. Read-only.",
|
|
12064
12010
|
details: `
|
|
@@ -12086,15 +12032,15 @@ var ScanCompareCommand = class extends SmCommand {
|
|
|
12086
12032
|
["JSON output for tooling", "$0 scan compare-with baseline.json --json"]
|
|
12087
12033
|
]
|
|
12088
12034
|
});
|
|
12089
|
-
dump =
|
|
12090
|
-
roots =
|
|
12091
|
-
noTokens =
|
|
12035
|
+
dump = Option18.String({ required: true });
|
|
12036
|
+
roots = Option18.Rest({ name: "roots" });
|
|
12037
|
+
noTokens = Option18.Boolean("--no-tokens", false, {
|
|
12092
12038
|
description: "Skip per-node token counts during the fresh scan."
|
|
12093
12039
|
});
|
|
12094
|
-
strict =
|
|
12040
|
+
strict = Option18.Boolean("--strict", false, {
|
|
12095
12041
|
description: "Promote layered-config warnings and frontmatter-validation findings from warn to error."
|
|
12096
12042
|
});
|
|
12097
|
-
noPlugins =
|
|
12043
|
+
noPlugins = Option18.Boolean("--no-plugins", false, {
|
|
12098
12044
|
description: "Skip drop-in plugin discovery."
|
|
12099
12045
|
});
|
|
12100
12046
|
// Cyclomatic count comes from CLI ergonomics: 3 distinct try/catch
|
|
@@ -12165,12 +12111,12 @@ var ScanCompareCommand = class extends SmCommand {
|
|
|
12165
12111
|
}
|
|
12166
12112
|
};
|
|
12167
12113
|
function loadAndValidateDump(path) {
|
|
12168
|
-
if (!
|
|
12114
|
+
if (!existsSync14(path)) {
|
|
12169
12115
|
throw new Error(tx(SCAN_TEXTS.compareDumpNotFound, { path }));
|
|
12170
12116
|
}
|
|
12171
12117
|
let raw;
|
|
12172
12118
|
try {
|
|
12173
|
-
raw =
|
|
12119
|
+
raw = readFileSync11(path, "utf8");
|
|
12174
12120
|
} catch (err) {
|
|
12175
12121
|
const message = formatErrorMessage(err);
|
|
12176
12122
|
throw new Error(tx(SCAN_TEXTS.compareDumpReadFailed, { path, message }), { cause: err });
|
|
@@ -12279,8 +12225,8 @@ function renderDeltaIssues(issues) {
|
|
|
12279
12225
|
|
|
12280
12226
|
// cli/commands/serve.ts
|
|
12281
12227
|
import { spawn } from "child_process";
|
|
12282
|
-
import { existsSync as
|
|
12283
|
-
import { Command as
|
|
12228
|
+
import { existsSync as existsSync18 } from "fs";
|
|
12229
|
+
import { Command as Command19, Option as Option19 } from "clipanion";
|
|
12284
12230
|
|
|
12285
12231
|
// server/index.ts
|
|
12286
12232
|
import { serve } from "@hono/node-server";
|
|
@@ -12461,7 +12407,7 @@ function contentTypeFor(format) {
|
|
|
12461
12407
|
}
|
|
12462
12408
|
|
|
12463
12409
|
// server/health.ts
|
|
12464
|
-
import { existsSync as
|
|
12410
|
+
import { existsSync as existsSync15 } from "fs";
|
|
12465
12411
|
var FALLBACK_SCHEMA_VERSION = "1";
|
|
12466
12412
|
function buildHealth(deps) {
|
|
12467
12413
|
return {
|
|
@@ -12470,7 +12416,7 @@ function buildHealth(deps) {
|
|
|
12470
12416
|
specVersion: deps.specVersion,
|
|
12471
12417
|
implVersion: VERSION,
|
|
12472
12418
|
scope: deps.scope,
|
|
12473
|
-
db:
|
|
12419
|
+
db: existsSync15(deps.dbPath) ? "present" : "missing"
|
|
12474
12420
|
};
|
|
12475
12421
|
}
|
|
12476
12422
|
async function resolveSpecVersion2() {
|
|
@@ -12910,9 +12856,9 @@ function emptyScanResult() {
|
|
|
12910
12856
|
}
|
|
12911
12857
|
|
|
12912
12858
|
// server/static.ts
|
|
12913
|
-
import { existsSync as
|
|
12859
|
+
import { existsSync as existsSync16 } from "fs";
|
|
12914
12860
|
import { readFile as readFile5 } from "fs/promises";
|
|
12915
|
-
import { extname, join as
|
|
12861
|
+
import { extname, join as join13 } from "path";
|
|
12916
12862
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
12917
12863
|
var INDEX_HTML = "index.html";
|
|
12918
12864
|
var PLACEHOLDER_HTML = `<!doctype html>
|
|
@@ -12943,8 +12889,8 @@ function createSpaFallback(uiDist) {
|
|
|
12943
12889
|
return async (c, _next) => {
|
|
12944
12890
|
if (c.req.method !== "GET" && c.req.method !== "HEAD") return c.notFound();
|
|
12945
12891
|
if (uiDist === null) return htmlResponse(c, PLACEHOLDER_HTML);
|
|
12946
|
-
const indexPath =
|
|
12947
|
-
if (!
|
|
12892
|
+
const indexPath = join13(uiDist, INDEX_HTML);
|
|
12893
|
+
if (!existsSync16(indexPath)) return htmlResponse(c, PLACEHOLDER_HTML);
|
|
12948
12894
|
return fileResponse(c, indexPath);
|
|
12949
12895
|
};
|
|
12950
12896
|
}
|
|
@@ -13257,6 +13203,9 @@ function buildKindRegistry(providers) {
|
|
|
13257
13203
|
return registry;
|
|
13258
13204
|
}
|
|
13259
13205
|
|
|
13206
|
+
// server/watcher.ts
|
|
13207
|
+
import { resolve as resolve20 } from "path";
|
|
13208
|
+
|
|
13260
13209
|
// server/events.ts
|
|
13261
13210
|
function buildWatcherStartedEvent(data) {
|
|
13262
13211
|
return {
|
|
@@ -13279,18 +13228,24 @@ function buildWatcherErrorEvent(data) {
|
|
|
13279
13228
|
var WATCH_ROOT = ".";
|
|
13280
13229
|
function createWatcherService(opts) {
|
|
13281
13230
|
let chokidarHandle = null;
|
|
13231
|
+
let metaHandle = null;
|
|
13282
13232
|
let stopped = false;
|
|
13283
13233
|
const start = async () => {
|
|
13284
|
-
const
|
|
13234
|
+
const cwd = opts.runtimeContext.cwd;
|
|
13235
|
+
const loadEffectiveConfig = () => loadConfig({
|
|
13285
13236
|
scope: opts.options.scope,
|
|
13286
|
-
cwd
|
|
13237
|
+
cwd,
|
|
13287
13238
|
homedir: opts.runtimeContext.homedir
|
|
13288
13239
|
}).effective;
|
|
13289
|
-
const
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13240
|
+
const buildCurrentIgnoreFilter = (cfgIn) => {
|
|
13241
|
+
const ignoreFileText = readIgnoreFileText(cwd);
|
|
13242
|
+
const filterOpts = {};
|
|
13243
|
+
if (cfgIn.ignore.length > 0) filterOpts.configIgnore = cfgIn.ignore;
|
|
13244
|
+
if (ignoreFileText !== void 0) filterOpts.ignoreFileText = ignoreFileText;
|
|
13245
|
+
return buildIgnoreFilter(filterOpts);
|
|
13246
|
+
};
|
|
13247
|
+
let cfg = loadEffectiveConfig();
|
|
13248
|
+
let ignoreFilter = buildCurrentIgnoreFilter(cfg);
|
|
13294
13249
|
const debounceMs = opts.debounceMsOverride ?? cfg.scan.watch.debounceMs;
|
|
13295
13250
|
const pluginRuntime = opts.options.noPlugins ? emptyPluginRuntime() : await loadPluginRuntime({ scope: opts.options.scope });
|
|
13296
13251
|
for (const warn of pluginRuntime.warnings) {
|
|
@@ -13321,7 +13276,12 @@ function createWatcherService(opts) {
|
|
|
13321
13276
|
roots: [WATCH_ROOT],
|
|
13322
13277
|
cwd: opts.runtimeContext.cwd,
|
|
13323
13278
|
debounceMs,
|
|
13324
|
-
|
|
13279
|
+
// Pass a getter, NOT the filter directly: the meta-file watcher
|
|
13280
|
+
// below mutates `ignoreFilter` after a `.skillmapignore` /
|
|
13281
|
+
// `.skill-map/settings.json` edit, and chokidar's `ignored`
|
|
13282
|
+
// predicate must read the current value on every event. See
|
|
13283
|
+
// `kernel/scan/watcher.ts` for the supported shapes.
|
|
13284
|
+
ignoreFilter: () => ignoreFilter,
|
|
13325
13285
|
onBatch: async () => {
|
|
13326
13286
|
if (stopped) return;
|
|
13327
13287
|
try {
|
|
@@ -13348,6 +13308,43 @@ function createWatcherService(opts) {
|
|
|
13348
13308
|
if ("ready" in chokidarHandle && chokidarHandle.ready instanceof Promise) {
|
|
13349
13309
|
await chokidarHandle.ready;
|
|
13350
13310
|
}
|
|
13311
|
+
metaHandle = createChokidarWatcher({
|
|
13312
|
+
roots: [
|
|
13313
|
+
resolve20(cwd, ".skillmapignore"),
|
|
13314
|
+
resolve20(cwd, ".skill-map", "settings.json")
|
|
13315
|
+
],
|
|
13316
|
+
cwd,
|
|
13317
|
+
debounceMs,
|
|
13318
|
+
// No `ignoreFilter` — these specific paths must always be observed,
|
|
13319
|
+
// regardless of any user pattern.
|
|
13320
|
+
onBatch: async () => {
|
|
13321
|
+
if (stopped) return;
|
|
13322
|
+
try {
|
|
13323
|
+
cfg = loadEffectiveConfig();
|
|
13324
|
+
ignoreFilter = buildCurrentIgnoreFilter(cfg);
|
|
13325
|
+
await runOneBatch();
|
|
13326
|
+
} catch (err) {
|
|
13327
|
+
const message = formatErrorMessage(err);
|
|
13328
|
+
log.warn(
|
|
13329
|
+
tx(SERVER_TEXTS.watcherBatchFailed, {
|
|
13330
|
+
message: sanitizeForTerminal(message)
|
|
13331
|
+
})
|
|
13332
|
+
);
|
|
13333
|
+
}
|
|
13334
|
+
},
|
|
13335
|
+
onError: (err) => {
|
|
13336
|
+
const message = err.message;
|
|
13337
|
+
log.warn(
|
|
13338
|
+
tx(SERVER_TEXTS.watcherError, {
|
|
13339
|
+
message: sanitizeForTerminal(message)
|
|
13340
|
+
})
|
|
13341
|
+
);
|
|
13342
|
+
}
|
|
13343
|
+
});
|
|
13344
|
+
if ("ready" in metaHandle && metaHandle.ready instanceof Promise) {
|
|
13345
|
+
await metaHandle.ready;
|
|
13346
|
+
}
|
|
13347
|
+
await runInitialBatch({ isStopped: () => stopped, runOneBatch });
|
|
13351
13348
|
opts.broadcaster.broadcast(
|
|
13352
13349
|
buildWatcherStartedEvent({ roots: [WATCH_ROOT], debounceMs })
|
|
13353
13350
|
);
|
|
@@ -13361,19 +13358,23 @@ function createWatcherService(opts) {
|
|
|
13361
13358
|
const stop = async () => {
|
|
13362
13359
|
if (stopped) return;
|
|
13363
13360
|
stopped = true;
|
|
13364
|
-
|
|
13361
|
+
const closeQuietly = async (handle, label) => {
|
|
13362
|
+
if (!handle) return;
|
|
13365
13363
|
try {
|
|
13366
|
-
await
|
|
13364
|
+
await handle.close();
|
|
13367
13365
|
} catch (err) {
|
|
13368
13366
|
const message = err instanceof Error ? err.message : String(err);
|
|
13369
13367
|
log.warn(
|
|
13370
13368
|
tx(SERVER_TEXTS.watcherCloseFailed, {
|
|
13371
|
-
message: sanitizeForTerminal(message)
|
|
13369
|
+
message: sanitizeForTerminal(`${label}: ${message}`)
|
|
13372
13370
|
})
|
|
13373
13371
|
);
|
|
13374
13372
|
}
|
|
13375
|
-
|
|
13376
|
-
|
|
13373
|
+
};
|
|
13374
|
+
await closeQuietly(metaHandle, "meta-watcher");
|
|
13375
|
+
metaHandle = null;
|
|
13376
|
+
await closeQuietly(chokidarHandle, "primary");
|
|
13377
|
+
chokidarHandle = null;
|
|
13377
13378
|
};
|
|
13378
13379
|
return { start, stop };
|
|
13379
13380
|
}
|
|
@@ -13430,6 +13431,19 @@ async function persistOutcome(dbPath, ran) {
|
|
|
13430
13431
|
(writer) => writer.scans.persist(result, { renameOps, extractorRuns, enrichments })
|
|
13431
13432
|
);
|
|
13432
13433
|
}
|
|
13434
|
+
async function runInitialBatch(deps) {
|
|
13435
|
+
if (deps.isStopped()) return;
|
|
13436
|
+
try {
|
|
13437
|
+
await deps.runOneBatch();
|
|
13438
|
+
} catch (err) {
|
|
13439
|
+
const message = formatErrorMessage(err);
|
|
13440
|
+
log.warn(
|
|
13441
|
+
tx(SERVER_TEXTS.watcherBatchFailed, {
|
|
13442
|
+
message: sanitizeForTerminal(message)
|
|
13443
|
+
})
|
|
13444
|
+
);
|
|
13445
|
+
}
|
|
13446
|
+
}
|
|
13433
13447
|
|
|
13434
13448
|
// server/options.ts
|
|
13435
13449
|
var DEFAULT_PORT = 4242;
|
|
@@ -13534,10 +13548,10 @@ function validateWatcherDebounce(value) {
|
|
|
13534
13548
|
}
|
|
13535
13549
|
|
|
13536
13550
|
// server/paths.ts
|
|
13537
|
-
import { existsSync as
|
|
13538
|
-
import { dirname as
|
|
13539
|
-
import { fileURLToPath as
|
|
13540
|
-
var DEFAULT_UI_REL =
|
|
13551
|
+
import { existsSync as existsSync17, statSync as statSync5 } from "fs";
|
|
13552
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join14, resolve as resolve21 } from "path";
|
|
13553
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13554
|
+
var DEFAULT_UI_REL = join14("ui", "dist", "ui", "browser");
|
|
13541
13555
|
var PACKAGE_UI_REL = "ui";
|
|
13542
13556
|
var INDEX_HTML2 = "index.html";
|
|
13543
13557
|
function resolveDefaultUiDist(ctx) {
|
|
@@ -13546,13 +13560,13 @@ function resolveDefaultUiDist(ctx) {
|
|
|
13546
13560
|
return walkUpForUi(ctx.cwd);
|
|
13547
13561
|
}
|
|
13548
13562
|
function resolveExplicitUiDist(ctx, raw) {
|
|
13549
|
-
return isAbsolute5(raw) ? raw :
|
|
13563
|
+
return isAbsolute5(raw) ? raw : resolve21(ctx.cwd, raw);
|
|
13550
13564
|
}
|
|
13551
13565
|
function isUiBundleDir(path) {
|
|
13552
|
-
if (!
|
|
13566
|
+
if (!existsSync17(path)) return false;
|
|
13553
13567
|
try {
|
|
13554
13568
|
if (!statSync5(path).isDirectory()) return false;
|
|
13555
|
-
return
|
|
13569
|
+
return existsSync17(join14(path, INDEX_HTML2));
|
|
13556
13570
|
} catch {
|
|
13557
13571
|
return false;
|
|
13558
13572
|
}
|
|
@@ -13560,7 +13574,7 @@ function isUiBundleDir(path) {
|
|
|
13560
13574
|
function resolvePackageBundledUi() {
|
|
13561
13575
|
let here;
|
|
13562
13576
|
try {
|
|
13563
|
-
here =
|
|
13577
|
+
here = dirname9(fileURLToPath5(import.meta.url));
|
|
13564
13578
|
} catch {
|
|
13565
13579
|
return null;
|
|
13566
13580
|
}
|
|
@@ -13569,22 +13583,22 @@ function resolvePackageBundledUi() {
|
|
|
13569
13583
|
function resolvePackageBundledUiFrom(here) {
|
|
13570
13584
|
let current = here;
|
|
13571
13585
|
for (let i = 0; i < 8; i++) {
|
|
13572
|
-
const candidate =
|
|
13586
|
+
const candidate = join14(current, PACKAGE_UI_REL);
|
|
13573
13587
|
if (isUiBundleDir(candidate)) return candidate;
|
|
13574
|
-
const distHere =
|
|
13588
|
+
const distHere = join14(current, "dist", PACKAGE_UI_REL);
|
|
13575
13589
|
if (isUiBundleDir(distHere)) return distHere;
|
|
13576
|
-
const parent =
|
|
13590
|
+
const parent = dirname9(current);
|
|
13577
13591
|
if (parent === current) return null;
|
|
13578
13592
|
current = parent;
|
|
13579
13593
|
}
|
|
13580
13594
|
return null;
|
|
13581
13595
|
}
|
|
13582
13596
|
function walkUpForUi(startDir) {
|
|
13583
|
-
let current =
|
|
13597
|
+
let current = resolve21(startDir);
|
|
13584
13598
|
for (let i = 0; i < 64; i++) {
|
|
13585
|
-
const candidate =
|
|
13599
|
+
const candidate = join14(current, DEFAULT_UI_REL);
|
|
13586
13600
|
if (isUiBundleDir(candidate)) return candidate;
|
|
13587
|
-
const parent =
|
|
13601
|
+
const parent = dirname9(current);
|
|
13588
13602
|
if (parent === current) return null;
|
|
13589
13603
|
current = parent;
|
|
13590
13604
|
}
|
|
@@ -13810,15 +13824,9 @@ function renderFiglet(input) {
|
|
|
13810
13824
|
greenUnderline,
|
|
13811
13825
|
greenUnderlineClose,
|
|
13812
13826
|
violetOpen,
|
|
13813
|
-
violetClose
|
|
13814
|
-
greenOpen,
|
|
13815
|
-
greenClose
|
|
13827
|
+
violetClose
|
|
13816
13828
|
} = resolveAnsi(input.colorEnabled);
|
|
13817
|
-
const logoLines = LOGO_LINES.map((line
|
|
13818
|
-
const open = i < 3 ? violetOpen : greenOpen;
|
|
13819
|
-
const close = i < 3 ? violetClose : greenClose;
|
|
13820
|
-
return `${open}${line}${close}`;
|
|
13821
|
-
});
|
|
13829
|
+
const logoLines = LOGO_LINES.map((line) => `${violetOpen}${line}${violetClose}`);
|
|
13822
13830
|
const versionText = `v${input.version}`;
|
|
13823
13831
|
const versionPad = Math.max(0, LOGO_WIDTH - versionText.length);
|
|
13824
13832
|
const versionLine = `${" ".repeat(versionPad)}${dimOpen}${versionText}${dimClose}`;
|
|
@@ -13842,9 +13850,7 @@ var EMPTY_ANSI = {
|
|
|
13842
13850
|
greenUnderline: "",
|
|
13843
13851
|
greenUnderlineClose: "",
|
|
13844
13852
|
violetOpen: "",
|
|
13845
|
-
violetClose: ""
|
|
13846
|
-
greenOpen: "",
|
|
13847
|
-
greenClose: ""
|
|
13853
|
+
violetClose: ""
|
|
13848
13854
|
};
|
|
13849
13855
|
var ENABLED_ANSI = {
|
|
13850
13856
|
dimOpen: ESC.dim,
|
|
@@ -13852,9 +13858,7 @@ var ENABLED_ANSI = {
|
|
|
13852
13858
|
greenUnderline: `${ESC.green}${ESC.underline}`,
|
|
13853
13859
|
greenUnderlineClose: ESC.reset,
|
|
13854
13860
|
violetOpen: ESC.violet,
|
|
13855
|
-
violetClose: ESC.reset
|
|
13856
|
-
greenOpen: ESC.green,
|
|
13857
|
-
greenClose: ESC.reset
|
|
13861
|
+
violetClose: ESC.reset
|
|
13858
13862
|
};
|
|
13859
13863
|
function resolveAnsi(colorEnabled) {
|
|
13860
13864
|
return colorEnabled ? ENABLED_ANSI : EMPTY_ANSI;
|
|
@@ -13880,7 +13884,7 @@ function formatCwdPath(cwd) {
|
|
|
13880
13884
|
// cli/commands/serve.ts
|
|
13881
13885
|
var ServeCommand = class extends SmCommand {
|
|
13882
13886
|
static paths = [["serve"]];
|
|
13883
|
-
static usage =
|
|
13887
|
+
static usage = Command19.Usage({
|
|
13884
13888
|
category: "Setup",
|
|
13885
13889
|
description: "Start the Hono BFF (single-port: REST + WebSocket + SPA bundle).",
|
|
13886
13890
|
details: `
|
|
@@ -13905,22 +13909,22 @@ var ServeCommand = class extends SmCommand {
|
|
|
13905
13909
|
["Point at a pre-built UI bundle", "$0 serve --ui-dist ./ui/dist/browser"]
|
|
13906
13910
|
]
|
|
13907
13911
|
});
|
|
13908
|
-
port =
|
|
13912
|
+
port = Option19.String("--port", {
|
|
13909
13913
|
required: false,
|
|
13910
13914
|
description: "Listening port (default 4242). 0 = OS-assigned."
|
|
13911
13915
|
});
|
|
13912
|
-
host =
|
|
13916
|
+
host = Option19.String("--host", {
|
|
13913
13917
|
required: false,
|
|
13914
13918
|
description: "Listening host (default 127.0.0.1). Loopback-only enforced when --dev-cors is set."
|
|
13915
13919
|
});
|
|
13916
|
-
scope =
|
|
13920
|
+
scope = Option19.String("--scope", {
|
|
13917
13921
|
required: false,
|
|
13918
13922
|
description: "project | global. Alias for -g/--global. Default: project."
|
|
13919
13923
|
});
|
|
13920
|
-
noBuiltIns =
|
|
13924
|
+
noBuiltIns = Option19.Boolean("--no-built-ins", false, {
|
|
13921
13925
|
description: "Skip built-in plugin registration (parity with sm scan --no-built-ins)."
|
|
13922
13926
|
});
|
|
13923
|
-
noPlugins =
|
|
13927
|
+
noPlugins = Option19.Boolean("--no-plugins", false, {
|
|
13924
13928
|
description: "Skip drop-in plugin discovery."
|
|
13925
13929
|
});
|
|
13926
13930
|
// `Option.Boolean('--open', true)` — Clipanion's parser auto-derives
|
|
@@ -13930,24 +13934,24 @@ var ServeCommand = class extends SmCommand {
|
|
|
13930
13934
|
// two registrations for the same flag and rejects the invocation
|
|
13931
13935
|
// with "Ambiguous Syntax Error". Same convention shipped by every
|
|
13932
13936
|
// other `--no-...` flag in the CLI tree.
|
|
13933
|
-
open =
|
|
13937
|
+
open = Option19.Boolean("--open", true, {
|
|
13934
13938
|
description: "Auto-open the SPA in the user's default browser after listen. --no-open opts out."
|
|
13935
13939
|
});
|
|
13936
|
-
devCors =
|
|
13940
|
+
devCors = Option19.Boolean("--dev-cors", false, {
|
|
13937
13941
|
description: "Enable permissive CORS for the Angular dev-server proxy workflow."
|
|
13938
13942
|
});
|
|
13939
13943
|
// `--ui-dist` is intentionally undocumented in the Usage block above
|
|
13940
13944
|
// (the demo build pipeline + tests rely on it; everyday users never
|
|
13941
13945
|
// need it). Clipanion still exposes it on the parser; the Usage
|
|
13942
13946
|
// omission is the "hidden" contract per the 14.1 brief.
|
|
13943
|
-
uiDist =
|
|
13944
|
-
noWatcher =
|
|
13947
|
+
uiDist = Option19.String("--ui-dist", { required: false, hidden: true });
|
|
13948
|
+
noWatcher = Option19.Boolean("--no-watcher", false, {
|
|
13945
13949
|
description: "Disable the chokidar-fed scan-and-broadcast loop. Use only for CI / read-only deployments."
|
|
13946
13950
|
});
|
|
13947
13951
|
// `--watcher-debounce-ms` is undocumented sugar for advanced users
|
|
13948
13952
|
// who want to tighten / relax the watcher's batching window without
|
|
13949
13953
|
// editing settings.json. Hidden flag — the Usage block omits it.
|
|
13950
|
-
watcherDebounceMs =
|
|
13954
|
+
watcherDebounceMs = Option19.String("--watcher-debounce-ms", { required: false, hidden: true });
|
|
13951
13955
|
// Long-running daemon — `done in <…>` after a graceful shutdown is
|
|
13952
13956
|
// noise. Mirrors `sm watch`'s opt-out.
|
|
13953
13957
|
emitElapsed = false;
|
|
@@ -13975,7 +13979,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
13975
13979
|
return ExitCode.Error;
|
|
13976
13980
|
}
|
|
13977
13981
|
const dbPath = resolveDbPath({ global: this.global, db: this.db, ...runtimeCtx });
|
|
13978
|
-
if (this.db !== void 0 && !
|
|
13982
|
+
if (this.db !== void 0 && !existsSync18(dbPath)) {
|
|
13979
13983
|
this.context.stderr.write(
|
|
13980
13984
|
tx(SERVE_TEXTS.dbNotFound, { path: sanitizeForTerminal(dbPath) })
|
|
13981
13985
|
);
|
|
@@ -14162,7 +14166,7 @@ function tryOpenBrowser(url, stderr) {
|
|
|
14162
14166
|
}
|
|
14163
14167
|
|
|
14164
14168
|
// cli/commands/show.ts
|
|
14165
|
-
import { Command as
|
|
14169
|
+
import { Command as Command20, Option as Option20 } from "clipanion";
|
|
14166
14170
|
|
|
14167
14171
|
// cli/i18n/show.texts.ts
|
|
14168
14172
|
var SHOW_TEXTS = {
|
|
@@ -14202,7 +14206,7 @@ var SHOW_TEXTS = {
|
|
|
14202
14206
|
// cli/commands/show.ts
|
|
14203
14207
|
var ShowCommand = class extends SmCommand {
|
|
14204
14208
|
static paths = [["show"]];
|
|
14205
|
-
static usage =
|
|
14209
|
+
static usage = Command20.Usage({
|
|
14206
14210
|
category: "Browse",
|
|
14207
14211
|
description: "Node detail: weight, frontmatter, links, issues.",
|
|
14208
14212
|
details: `
|
|
@@ -14218,7 +14222,7 @@ var ShowCommand = class extends SmCommand {
|
|
|
14218
14222
|
["Machine-readable detail", "$0 show .claude/agents/architect.md --json"]
|
|
14219
14223
|
]
|
|
14220
14224
|
});
|
|
14221
|
-
nodePath =
|
|
14225
|
+
nodePath = Option20.String({ required: true });
|
|
14222
14226
|
async run() {
|
|
14223
14227
|
const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
|
|
14224
14228
|
if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
|
|
@@ -14367,7 +14371,7 @@ function rankConfidenceForGrouping(c) {
|
|
|
14367
14371
|
}
|
|
14368
14372
|
|
|
14369
14373
|
// cli/commands/stubs.ts
|
|
14370
|
-
import { Command as
|
|
14374
|
+
import { Command as Command21, Option as Option21 } from "clipanion";
|
|
14371
14375
|
|
|
14372
14376
|
// cli/i18n/stubs.texts.ts
|
|
14373
14377
|
var STUBS_TEXTS = {
|
|
@@ -14382,9 +14386,9 @@ function notImplemented(cmd, verb) {
|
|
|
14382
14386
|
cmd.context.stderr.write(tx(STUBS_TEXTS.notImplemented, { verb }));
|
|
14383
14387
|
return ExitCode.Error;
|
|
14384
14388
|
}
|
|
14385
|
-
var DoctorCommand = class extends
|
|
14389
|
+
var DoctorCommand = class extends Command21 {
|
|
14386
14390
|
static paths = [["doctor"]];
|
|
14387
|
-
static usage =
|
|
14391
|
+
static usage = Command21.Usage({
|
|
14388
14392
|
category: "Setup",
|
|
14389
14393
|
description: planned("Diagnostic report: DB integrity, pending migrations, orphan rows, plugin status, runner availability.")
|
|
14390
14394
|
});
|
|
@@ -14392,23 +14396,23 @@ var DoctorCommand = class extends Command22 {
|
|
|
14392
14396
|
return notImplemented(this, "doctor");
|
|
14393
14397
|
}
|
|
14394
14398
|
};
|
|
14395
|
-
var FindingsCommand = class extends
|
|
14399
|
+
var FindingsCommand = class extends Command21 {
|
|
14396
14400
|
static paths = [["findings"]];
|
|
14397
|
-
static usage =
|
|
14401
|
+
static usage = Command21.Usage({
|
|
14398
14402
|
category: "Browse",
|
|
14399
14403
|
description: planned("Probabilistic findings: injection, stale summaries, low confidence.")
|
|
14400
14404
|
});
|
|
14401
|
-
kind =
|
|
14402
|
-
since =
|
|
14403
|
-
threshold =
|
|
14404
|
-
json =
|
|
14405
|
+
kind = Option21.String("--kind", { required: false });
|
|
14406
|
+
since = Option21.String("--since", { required: false });
|
|
14407
|
+
threshold = Option21.String("--threshold", { required: false });
|
|
14408
|
+
json = Option21.Boolean("--json", false);
|
|
14405
14409
|
async execute() {
|
|
14406
14410
|
return notImplemented(this, "findings");
|
|
14407
14411
|
}
|
|
14408
14412
|
};
|
|
14409
|
-
var ActionsListCommand = class extends
|
|
14413
|
+
var ActionsListCommand = class extends Command21 {
|
|
14410
14414
|
static paths = [["actions", "list"]];
|
|
14411
|
-
static usage =
|
|
14415
|
+
static usage = Command21.Usage({
|
|
14412
14416
|
category: "Jobs",
|
|
14413
14417
|
description: planned("Registered action types (manifest view).")
|
|
14414
14418
|
});
|
|
@@ -14416,121 +14420,121 @@ var ActionsListCommand = class extends Command22 {
|
|
|
14416
14420
|
return notImplemented(this, "actions list");
|
|
14417
14421
|
}
|
|
14418
14422
|
};
|
|
14419
|
-
var ActionsShowCommand = class extends
|
|
14423
|
+
var ActionsShowCommand = class extends Command21 {
|
|
14420
14424
|
static paths = [["actions", "show"]];
|
|
14421
|
-
static usage =
|
|
14425
|
+
static usage = Command21.Usage({
|
|
14422
14426
|
category: "Jobs",
|
|
14423
14427
|
description: planned("Full action manifest, including preconditions and expected duration.")
|
|
14424
14428
|
});
|
|
14425
|
-
id =
|
|
14429
|
+
id = Option21.String({ required: true });
|
|
14426
14430
|
async execute() {
|
|
14427
14431
|
return notImplemented(this, "actions show");
|
|
14428
14432
|
}
|
|
14429
14433
|
};
|
|
14430
|
-
var JobSubmitCommand = class extends
|
|
14434
|
+
var JobSubmitCommand = class extends Command21 {
|
|
14431
14435
|
static paths = [["job", "submit"]];
|
|
14432
|
-
static usage =
|
|
14436
|
+
static usage = Command21.Usage({
|
|
14433
14437
|
category: "Jobs",
|
|
14434
14438
|
description: planned("Enqueue a single job or fan out to every matching node (--all).")
|
|
14435
14439
|
});
|
|
14436
|
-
action =
|
|
14437
|
-
node =
|
|
14438
|
-
all =
|
|
14439
|
-
run =
|
|
14440
|
-
force =
|
|
14441
|
-
ttl =
|
|
14442
|
-
priority =
|
|
14440
|
+
action = Option21.String({ required: true });
|
|
14441
|
+
node = Option21.String("-n", { required: false });
|
|
14442
|
+
all = Option21.Boolean("--all", false);
|
|
14443
|
+
run = Option21.Boolean("--run", false);
|
|
14444
|
+
force = Option21.Boolean("--force", false);
|
|
14445
|
+
ttl = Option21.String("--ttl", { required: false });
|
|
14446
|
+
priority = Option21.String("--priority", { required: false });
|
|
14443
14447
|
async execute() {
|
|
14444
14448
|
return notImplemented(this, "job submit");
|
|
14445
14449
|
}
|
|
14446
14450
|
};
|
|
14447
|
-
var JobListCommand = class extends
|
|
14451
|
+
var JobListCommand = class extends Command21 {
|
|
14448
14452
|
static paths = [["job", "list"]];
|
|
14449
|
-
static usage =
|
|
14450
|
-
status =
|
|
14451
|
-
action =
|
|
14452
|
-
node =
|
|
14453
|
+
static usage = Command21.Usage({ category: "Jobs", description: planned("List jobs.") });
|
|
14454
|
+
status = Option21.String("--status", { required: false });
|
|
14455
|
+
action = Option21.String("--action", { required: false });
|
|
14456
|
+
node = Option21.String("--node", { required: false });
|
|
14453
14457
|
async execute() {
|
|
14454
14458
|
return notImplemented(this, "job list");
|
|
14455
14459
|
}
|
|
14456
14460
|
};
|
|
14457
|
-
var JobShowCommand = class extends
|
|
14461
|
+
var JobShowCommand = class extends Command21 {
|
|
14458
14462
|
static paths = [["job", "show"]];
|
|
14459
|
-
static usage =
|
|
14460
|
-
id =
|
|
14463
|
+
static usage = Command21.Usage({ category: "Jobs", description: planned("Job detail: state, claim time, TTL, runner, content hash.") });
|
|
14464
|
+
id = Option21.String({ required: true });
|
|
14461
14465
|
async execute() {
|
|
14462
14466
|
return notImplemented(this, "job show");
|
|
14463
14467
|
}
|
|
14464
14468
|
};
|
|
14465
|
-
var JobPreviewCommand = class extends
|
|
14469
|
+
var JobPreviewCommand = class extends Command21 {
|
|
14466
14470
|
static paths = [["job", "preview"]];
|
|
14467
|
-
static usage =
|
|
14468
|
-
id =
|
|
14471
|
+
static usage = Command21.Usage({ category: "Jobs", description: planned("Render the job MD file without executing.") });
|
|
14472
|
+
id = Option21.String({ required: true });
|
|
14469
14473
|
async execute() {
|
|
14470
14474
|
return notImplemented(this, "job preview");
|
|
14471
14475
|
}
|
|
14472
14476
|
};
|
|
14473
|
-
var JobClaimCommand = class extends
|
|
14477
|
+
var JobClaimCommand = class extends Command21 {
|
|
14474
14478
|
static paths = [["job", "claim"]];
|
|
14475
|
-
static usage =
|
|
14479
|
+
static usage = Command21.Usage({
|
|
14476
14480
|
category: "Jobs",
|
|
14477
14481
|
description: planned("Atomic primitive: return next queued job id, mark it running.")
|
|
14478
14482
|
});
|
|
14479
|
-
filter =
|
|
14483
|
+
filter = Option21.String("--filter", { required: false });
|
|
14480
14484
|
async execute() {
|
|
14481
14485
|
return notImplemented(this, "job claim");
|
|
14482
14486
|
}
|
|
14483
14487
|
};
|
|
14484
|
-
var JobRunCommand = class extends
|
|
14488
|
+
var JobRunCommand = class extends Command21 {
|
|
14485
14489
|
static paths = [["job", "run"]];
|
|
14486
|
-
static usage =
|
|
14490
|
+
static usage = Command21.Usage({
|
|
14487
14491
|
category: "Jobs",
|
|
14488
14492
|
description: planned("Full CLI-runner loop: claim + spawn + record.")
|
|
14489
14493
|
});
|
|
14490
|
-
all =
|
|
14491
|
-
max =
|
|
14494
|
+
all = Option21.Boolean("--all", false);
|
|
14495
|
+
max = Option21.String("--max", { required: false });
|
|
14492
14496
|
async execute() {
|
|
14493
14497
|
return notImplemented(this, "job run");
|
|
14494
14498
|
}
|
|
14495
14499
|
};
|
|
14496
|
-
var JobStatusCommand = class extends
|
|
14500
|
+
var JobStatusCommand = class extends Command21 {
|
|
14497
14501
|
static paths = [["job", "status"]];
|
|
14498
|
-
static usage =
|
|
14502
|
+
static usage = Command21.Usage({
|
|
14499
14503
|
category: "Jobs",
|
|
14500
14504
|
description: planned("Counts (per status) or single-job status.")
|
|
14501
14505
|
});
|
|
14502
|
-
id =
|
|
14506
|
+
id = Option21.String({ required: false });
|
|
14503
14507
|
async execute() {
|
|
14504
14508
|
return notImplemented(this, "job status");
|
|
14505
14509
|
}
|
|
14506
14510
|
};
|
|
14507
|
-
var JobCancelCommand = class extends
|
|
14511
|
+
var JobCancelCommand = class extends Command21 {
|
|
14508
14512
|
static paths = [["job", "cancel"]];
|
|
14509
|
-
static usage =
|
|
14513
|
+
static usage = Command21.Usage({
|
|
14510
14514
|
category: "Jobs",
|
|
14511
14515
|
description: planned("Force a running job to failed with reason user-cancelled.")
|
|
14512
14516
|
});
|
|
14513
|
-
id =
|
|
14514
|
-
all =
|
|
14517
|
+
id = Option21.String({ required: false });
|
|
14518
|
+
all = Option21.Boolean("--all", false);
|
|
14515
14519
|
async execute() {
|
|
14516
14520
|
return notImplemented(this, "job cancel");
|
|
14517
14521
|
}
|
|
14518
14522
|
};
|
|
14519
|
-
var RecordCommand = class extends
|
|
14523
|
+
var RecordCommand = class extends Command21 {
|
|
14520
14524
|
static paths = [["record"]];
|
|
14521
|
-
static usage =
|
|
14525
|
+
static usage = Command21.Usage({
|
|
14522
14526
|
category: "Jobs",
|
|
14523
14527
|
description: planned("Close a running job with success or failure. Nonce is the sole credential.")
|
|
14524
14528
|
});
|
|
14525
|
-
id =
|
|
14526
|
-
nonce =
|
|
14527
|
-
status =
|
|
14528
|
-
report =
|
|
14529
|
-
tokensIn =
|
|
14530
|
-
tokensOut =
|
|
14531
|
-
durationMs =
|
|
14532
|
-
model =
|
|
14533
|
-
error =
|
|
14529
|
+
id = Option21.String("--id", { required: true });
|
|
14530
|
+
nonce = Option21.String("--nonce", { required: true });
|
|
14531
|
+
status = Option21.String("--status", { required: true });
|
|
14532
|
+
report = Option21.String("--report", { required: false });
|
|
14533
|
+
tokensIn = Option21.String("--tokens-in", { required: false });
|
|
14534
|
+
tokensOut = Option21.String("--tokens-out", { required: false });
|
|
14535
|
+
durationMs = Option21.String("--duration-ms", { required: false });
|
|
14536
|
+
model = Option21.String("--model", { required: false });
|
|
14537
|
+
error = Option21.String("--error", { required: false });
|
|
14534
14538
|
async execute() {
|
|
14535
14539
|
return notImplemented(this, "record");
|
|
14536
14540
|
}
|
|
@@ -14551,6 +14555,99 @@ var STUB_COMMANDS = [
|
|
|
14551
14555
|
RecordCommand
|
|
14552
14556
|
];
|
|
14553
14557
|
|
|
14558
|
+
// cli/commands/tutorial.ts
|
|
14559
|
+
import { existsSync as existsSync19, readFileSync as readFileSync12 } from "fs";
|
|
14560
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
14561
|
+
import { dirname as dirname10, join as join15, resolve as resolve22 } from "path";
|
|
14562
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
14563
|
+
import { Command as Command22, Option as Option22 } from "clipanion";
|
|
14564
|
+
|
|
14565
|
+
// cli/i18n/tutorial.texts.ts
|
|
14566
|
+
var TUTORIAL_TEXTS = {
|
|
14567
|
+
// Success — written to stdout after `<cwd>/sm-tutorial.md` is created.
|
|
14568
|
+
written: 'Done. sm-tutorial.md created at {{cwd}}. Open Claude Code here and tell it "run @sm-tutorial.md" to start the interactive tutorial.\n',
|
|
14569
|
+
// Refusal — `sm-tutorial.md` already exists and `--force` was not set.
|
|
14570
|
+
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
14571
|
+
alreadyExists: "sm tutorial: sm-tutorial.md already exists at {{cwd}}. Pass `--force` to overwrite.\n",
|
|
14572
|
+
// I/O failure on write or on reading the bundled SKILL source.
|
|
14573
|
+
writeFailed: "sm tutorial: failed to write sm-tutorial.md: {{message}}\n",
|
|
14574
|
+
sourceMissing: "sm tutorial: could not read the bundled tutorial (SKILL.md) from the install. Reinstall @skill-map/cli or report the bug.\n"
|
|
14575
|
+
};
|
|
14576
|
+
|
|
14577
|
+
// cli/commands/tutorial.ts
|
|
14578
|
+
var SM_TUTORIAL_FILENAME = "sm-tutorial.md";
|
|
14579
|
+
var TutorialCommand = class extends SmCommand {
|
|
14580
|
+
static paths = [["tutorial"]];
|
|
14581
|
+
static usage = Command22.Usage({
|
|
14582
|
+
category: "Setup",
|
|
14583
|
+
description: "Materialize the interactive tester tutorial (sm-tutorial.md) in the current directory.",
|
|
14584
|
+
details: `
|
|
14585
|
+
Drops the canonical SKILL.md content as ./sm-tutorial.md so a tester
|
|
14586
|
+
can open Claude Code in the cwd and load the file as a skill by
|
|
14587
|
+
typing "ejecut\xE1 @sm-tutorial.md". Top-level only \u2014 no subdirectory
|
|
14588
|
+
is created.
|
|
14589
|
+
|
|
14590
|
+
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
14591
|
+
overwrite an existing sm-tutorial.md unless --force is passed.
|
|
14592
|
+
`,
|
|
14593
|
+
examples: [
|
|
14594
|
+
["Materialize the tutorial in the cwd", "$0 tutorial"],
|
|
14595
|
+
["Overwrite an existing sm-tutorial.md", "$0 tutorial --force"]
|
|
14596
|
+
]
|
|
14597
|
+
});
|
|
14598
|
+
force = Option22.Boolean("--force", false, {
|
|
14599
|
+
description: "Overwrite an existing sm-tutorial.md without prompting."
|
|
14600
|
+
});
|
|
14601
|
+
async run() {
|
|
14602
|
+
const ctx = defaultRuntimeContext();
|
|
14603
|
+
const target = join15(ctx.cwd, SM_TUTORIAL_FILENAME);
|
|
14604
|
+
if (await pathExists(target) && !this.force) {
|
|
14605
|
+
this.context.stderr.write(tx(TUTORIAL_TEXTS.alreadyExists, { cwd: ctx.cwd }));
|
|
14606
|
+
return ExitCode.Error;
|
|
14607
|
+
}
|
|
14608
|
+
let body;
|
|
14609
|
+
try {
|
|
14610
|
+
body = loadBundledTutorialText();
|
|
14611
|
+
} catch {
|
|
14612
|
+
this.context.stderr.write(TUTORIAL_TEXTS.sourceMissing);
|
|
14613
|
+
return ExitCode.Error;
|
|
14614
|
+
}
|
|
14615
|
+
try {
|
|
14616
|
+
await writeFile2(target, body);
|
|
14617
|
+
} catch (err) {
|
|
14618
|
+
this.context.stderr.write(
|
|
14619
|
+
tx(TUTORIAL_TEXTS.writeFailed, { message: formatErrorMessage(err) })
|
|
14620
|
+
);
|
|
14621
|
+
return ExitCode.Error;
|
|
14622
|
+
}
|
|
14623
|
+
this.context.stdout.write(tx(TUTORIAL_TEXTS.written, { cwd: ctx.cwd }));
|
|
14624
|
+
return ExitCode.Ok;
|
|
14625
|
+
}
|
|
14626
|
+
};
|
|
14627
|
+
var cachedTutorial = null;
|
|
14628
|
+
function loadBundledTutorialText() {
|
|
14629
|
+
if (cachedTutorial !== null) return cachedTutorial;
|
|
14630
|
+
cachedTutorial = readTutorialFromDisk();
|
|
14631
|
+
return cachedTutorial;
|
|
14632
|
+
}
|
|
14633
|
+
function readTutorialFromDisk() {
|
|
14634
|
+
const here = dirname10(fileURLToPath6(import.meta.url));
|
|
14635
|
+
const candidates = [
|
|
14636
|
+
// dev: src/cli/commands/ → repo-root .claude/skills/sm-tutorial/SKILL.md
|
|
14637
|
+
resolve22(here, "../../../.claude/skills/sm-tutorial/SKILL.md"),
|
|
14638
|
+
// bundled: dist/cli.js → dist/cli/tutorial/sm-tutorial.md (sibling)
|
|
14639
|
+
resolve22(here, "cli/tutorial/sm-tutorial.md"),
|
|
14640
|
+
// bundled fallback: any-depth → cli/tutorial/sm-tutorial.md
|
|
14641
|
+
resolve22(here, "../cli/tutorial/sm-tutorial.md")
|
|
14642
|
+
];
|
|
14643
|
+
for (const candidate of candidates) {
|
|
14644
|
+
if (existsSync19(candidate)) {
|
|
14645
|
+
return readFileSync12(candidate, "utf8");
|
|
14646
|
+
}
|
|
14647
|
+
}
|
|
14648
|
+
throw new Error(`SKILL.md not found in any candidate location (last tried: ${candidates[candidates.length - 1]})`);
|
|
14649
|
+
}
|
|
14650
|
+
|
|
14554
14651
|
// cli/commands/version.ts
|
|
14555
14652
|
import { Command as Command23 } from "clipanion";
|
|
14556
14653
|
|
|
@@ -14634,7 +14731,7 @@ cli.register(Builtins.VersionCommand);
|
|
|
14634
14731
|
cli.register(RootHelpCommand);
|
|
14635
14732
|
cli.register(HelpCommand);
|
|
14636
14733
|
cli.register(InitCommand);
|
|
14637
|
-
cli.register(
|
|
14734
|
+
cli.register(TutorialCommand);
|
|
14638
14735
|
cli.register(ScanCommand);
|
|
14639
14736
|
cli.register(ScanCompareCommand);
|
|
14640
14737
|
cli.register(ServeCommand);
|