@skill-map/cli 0.14.1 → 0.15.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/dist/cli.js CHANGED
@@ -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 readFileSync11 } from "fs";
7357
+ import { readFileSync as readFileSync10 } from "fs";
7451
7358
  import { createRequire as createRequire4 } from "module";
7452
- import { resolve as resolve14 } from "path";
7453
- import { Command as Command9, Option as Option9 } from "clipanion";
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.14.1",
7365
+ version: "0.15.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.14.1",
7424
+ "@skill-map/spec": "0.15.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 Command9 {
7541
+ var HelpCommand = class extends Command8 {
7635
7542
  static paths = [["help"]];
7636
- static usage = Command9.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 = Option9.Rest({ required: 0 });
7651
- format = Option9.String("--format", "human");
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 = resolve14(indexPath, "..", "package.json");
7774
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
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 Command9 {
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 as writeFile2 } from "fs/promises";
8026
- import { join as join11 } from "path";
8027
- import { Command as Command10, Option as Option10 } from "clipanion";
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 existsSync13, statSync as statSync3 } from "fs";
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 (!existsSync13(root) || !statSync3(root).isDirectory()) {
8073
+ if (!existsSync12(root) || !statSync3(root).isDirectory()) {
8167
8074
  throw new Error(tx(ORCHESTRATOR_TEXTS.runScanRootMissing, { root }));
8168
8075
  }
8169
8076
  }
@@ -8939,10 +8846,10 @@ function recomputeExternalRefsCount(nodes, externalLinks, cachedPaths) {
8939
8846
  }
8940
8847
 
8941
8848
  // kernel/scan/watcher.ts
8942
- import { resolve as resolve15, relative as relative4, sep as sep2 } from "path";
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) => resolve15(opts.cwd, r));
8852
+ const absRoots = opts.roots.map((r) => resolve14(opts.cwd, r));
8946
8853
  const ignoreFilter = opts.ignoreFilter;
8947
8854
  const ignored = ignoreFilter ? (path) => {
8948
8855
  const rel = relativePathFromRoots(path, absRoots);
@@ -9188,7 +9095,7 @@ function createCliProgressEmitter(stderr) {
9188
9095
  // cli/commands/init.ts
9189
9096
  var InitCommand = class extends SmCommand {
9190
9097
  static paths = [["init"]];
9191
- static usage = Command10.Usage({
9098
+ static usage = Command9.Usage({
9192
9099
  category: "Setup",
9193
9100
  description: "Bootstrap the current scope: scaffold .skill-map/, provision DB, run first scan.",
9194
9101
  details: `
@@ -9212,16 +9119,16 @@ var InitCommand = class extends SmCommand {
9212
9119
  ["Preview what would be created", "$0 init --dry-run"]
9213
9120
  ]
9214
9121
  });
9215
- noScan = Option10.Boolean("--no-scan", false, {
9122
+ noScan = Option9.Boolean("--no-scan", false, {
9216
9123
  description: "Skip the first scan after scaffolding."
9217
9124
  });
9218
- force = Option10.Boolean("--force", false, {
9125
+ force = Option9.Boolean("--force", false, {
9219
9126
  description: "Overwrite an existing settings.json / settings.local.json / .skill-mapignore."
9220
9127
  });
9221
- strict = Option10.Boolean("--strict", false, {
9128
+ strict = Option9.Boolean("--strict", false, {
9222
9129
  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
9130
  });
9224
- dryRun = Option10.Boolean("-n,--dry-run", false, {
9131
+ dryRun = Option9.Boolean("-n,--dry-run", false, {
9225
9132
  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
9133
  });
9227
9134
  // CLI orchestrator: paths setup + dry-run branch (delegated to
@@ -9232,7 +9139,7 @@ var InitCommand = class extends SmCommand {
9232
9139
  async run() {
9233
9140
  const ctx = defaultRuntimeContext();
9234
9141
  const scopeRoot = this.global ? ctx.homedir : ctx.cwd;
9235
- const skillMapDir = join11(scopeRoot, SKILL_MAP_DIR);
9142
+ const skillMapDir = join10(scopeRoot, SKILL_MAP_DIR);
9236
9143
  const settingsPath = defaultSettingsPath(scopeRoot);
9237
9144
  const localPath = defaultLocalSettingsPath(scopeRoot);
9238
9145
  const ignorePath = defaultIgnoreFilePath(scopeRoot);
@@ -9256,17 +9163,17 @@ var InitCommand = class extends SmCommand {
9256
9163
  return ExitCode.Ok;
9257
9164
  }
9258
9165
  await mkdir2(skillMapDir, { recursive: true });
9259
- await writeFile2(settingsPath, JSON.stringify({ schemaVersion: 1 }, null, 2) + "\n");
9166
+ await writeFile(settingsPath, JSON.stringify({ schemaVersion: 1 }, null, 2) + "\n");
9260
9167
  if (!await pathExists(localPath) || this.force) {
9261
- await writeFile2(localPath, "{}\n");
9168
+ await writeFile(localPath, "{}\n");
9262
9169
  }
9263
9170
  if (!await pathExists(ignorePath) || this.force) {
9264
- await writeFile2(ignorePath, loadBundledIgnoreText());
9171
+ await writeFile(ignorePath, loadBundledIgnoreText());
9265
9172
  }
9266
9173
  if (!this.global) {
9267
9174
  const updated = await ensureGitignoreEntries(scopeRoot, GITIGNORE_ENTRIES);
9268
9175
  if (updated) {
9269
- const gitignorePath = join11(scopeRoot, ".gitignore");
9176
+ const gitignorePath = join10(scopeRoot, ".gitignore");
9270
9177
  this.context.stdout.write(
9271
9178
  GITIGNORE_ENTRIES.length === 1 ? tx(INIT_TEXTS.gitignoreUpdatedSingular, { path: gitignorePath }) : tx(INIT_TEXTS.gitignoreUpdatedPlural, {
9272
9179
  path: gitignorePath,
@@ -9305,7 +9212,7 @@ async function dryRunFileMessage(path) {
9305
9212
  }
9306
9213
  async function writeDryRunGitignorePlan(stdout, scopeRoot) {
9307
9214
  const wouldAdd = await previewGitignoreEntries(scopeRoot, GITIGNORE_ENTRIES);
9308
- const gitignorePath = join11(scopeRoot, ".gitignore");
9215
+ const gitignorePath = join10(scopeRoot, ".gitignore");
9309
9216
  if (wouldAdd.length === 0) {
9310
9217
  stdout.write(tx(INIT_TEXTS.dryRunWouldLeaveGitignoreUnchanged, { path: gitignorePath }));
9311
9218
  } else if (wouldAdd.length === 1) {
@@ -9380,7 +9287,7 @@ async function runFirstScan(scopeRoot, homedir3, dbPath, strict, stdout, stderr)
9380
9287
  return hasErrors ? ExitCode.Issues : ExitCode.Ok;
9381
9288
  }
9382
9289
  async function previewGitignoreEntries(scopeRoot, entries) {
9383
- const path = join11(scopeRoot, ".gitignore");
9290
+ const path = join10(scopeRoot, ".gitignore");
9384
9291
  const body = await pathExists(path) ? await readFile2(path, "utf8") : "";
9385
9292
  const present = new Set(
9386
9293
  body.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"))
@@ -9388,7 +9295,7 @@ async function previewGitignoreEntries(scopeRoot, entries) {
9388
9295
  return entries.filter((entry) => !present.has(entry));
9389
9296
  }
9390
9297
  async function ensureGitignoreEntries(scopeRoot, entries) {
9391
- const path = join11(scopeRoot, ".gitignore");
9298
+ const path = join10(scopeRoot, ".gitignore");
9392
9299
  let body = "";
9393
9300
  if (await pathExists(path)) {
9394
9301
  body = await readFile2(path, "utf8");
@@ -9405,12 +9312,12 @@ async function ensureGitignoreEntries(scopeRoot, entries) {
9405
9312
  present.add(entry);
9406
9313
  changed = true;
9407
9314
  }
9408
- if (changed) await writeFile2(path, body);
9315
+ if (changed) await writeFile(path, body);
9409
9316
  return changed;
9410
9317
  }
9411
9318
 
9412
9319
  // cli/commands/history.ts
9413
- import { Command as Command11, Option as Option11 } from "clipanion";
9320
+ import { Command as Command10, Option as Option10 } from "clipanion";
9414
9321
 
9415
9322
  // cli/i18n/option-validators.texts.ts
9416
9323
  var OPTION_VALIDATORS_TEXTS = {
@@ -9499,7 +9406,7 @@ function parseStatuses(input, stderr) {
9499
9406
  }
9500
9407
  var HistoryCommand = class extends SmCommand {
9501
9408
  static paths = [["history"]];
9502
- static usage = Command11.Usage({
9409
+ static usage = Command10.Usage({
9503
9410
  category: "History",
9504
9411
  description: "Filter execution records. --json emits an array conforming to execution-record.schema.json.",
9505
9412
  details: `
@@ -9519,12 +9426,12 @@ var HistoryCommand = class extends SmCommand {
9519
9426
  ["Machine-readable, scoped to one node", "$0 history -n skills/foo.md --json"]
9520
9427
  ]
9521
9428
  });
9522
- node = Option11.String("-n", { required: false });
9523
- action = Option11.String("--action", { required: false });
9524
- status = Option11.String("--status", { required: false });
9525
- since = Option11.String("--since", { required: false });
9526
- until = Option11.String("--until", { required: false });
9527
- limit = Option11.String("--limit", { required: false });
9429
+ node = Option10.String("-n", { required: false });
9430
+ action = Option10.String("--action", { required: false });
9431
+ status = Option10.String("--status", { required: false });
9432
+ since = Option10.String("--since", { required: false });
9433
+ until = Option10.String("--until", { required: false });
9434
+ limit = Option10.String("--limit", { required: false });
9528
9435
  // CLI list verb: many optional filter flags (`--node`, `--action`,
9529
9436
  // `--status`, `--since`, `--until`, `--limit`, `--json`, `--quiet`)
9530
9437
  // each adding a guarded mutation to the filter or render path. Each
@@ -9572,7 +9479,7 @@ var HistoryCommand = class extends SmCommand {
9572
9479
  };
9573
9480
  var HistoryStatsCommand = class extends SmCommand {
9574
9481
  static paths = [["history", "stats"]];
9575
- static usage = Command11.Usage({
9482
+ static usage = Command10.Usage({
9576
9483
  category: "History",
9577
9484
  description: "Aggregate counts, tokens, periods, top nodes, and error rates over state_executions. --json conforms to history-stats.schema.json.",
9578
9485
  details: `
@@ -9590,10 +9497,10 @@ var HistoryStatsCommand = class extends SmCommand {
9590
9497
  ["Top 5 nodes, JSON", "$0 history stats --top 5 --json"]
9591
9498
  ]
9592
9499
  });
9593
- since = Option11.String("--since", { required: false });
9594
- until = Option11.String("--until", { required: false });
9595
- period = Option11.String("--period", { required: false });
9596
- top = Option11.String("--top", { required: false });
9500
+ since = Option10.String("--since", { required: false });
9501
+ until = Option10.String("--until", { required: false });
9502
+ period = Option10.String("--period", { required: false });
9503
+ top = Option10.String("--top", { required: false });
9597
9504
  // CLI stats verb: range parsing + window flags + period flag + JSON
9598
9505
  // branch + per-period iteration. Each branch is a single-purpose
9599
9506
  // gate; the data work lives in `aggregateHistoryStats`.
@@ -9774,11 +9681,11 @@ function formatRow(...cols) {
9774
9681
 
9775
9682
  // cli/commands/jobs.ts
9776
9683
  import { unlink } from "fs/promises";
9777
- import { Command as Command12, Option as Option12 } from "clipanion";
9684
+ import { Command as Command11, Option as Option11 } from "clipanion";
9778
9685
 
9779
9686
  // kernel/jobs/orphan-files.ts
9780
9687
  import { readdirSync as readdirSync6, statSync as statSync4 } from "fs";
9781
- import { join as join12, resolve as resolve16 } from "path";
9688
+ import { join as join11, resolve as resolve15 } from "path";
9782
9689
  function findOrphanJobFiles(jobsDir, referencedPaths) {
9783
9690
  let entries;
9784
9691
  try {
@@ -9793,7 +9700,7 @@ function findOrphanJobFiles(jobsDir, referencedPaths) {
9793
9700
  const orphans = [];
9794
9701
  for (const name of entries) {
9795
9702
  if (!name.endsWith(".md")) continue;
9796
- const abs = resolve16(join12(jobsDir, name));
9703
+ const abs = resolve15(join11(jobsDir, name));
9797
9704
  if (!referencedPaths.has(abs)) orphans.push(abs);
9798
9705
  }
9799
9706
  orphans.sort();
@@ -9822,7 +9729,7 @@ var JOBS_TEXTS = {
9822
9729
  // cli/commands/jobs.ts
9823
9730
  var JobPruneCommand = class extends SmCommand {
9824
9731
  static paths = [["job", "prune"]];
9825
- static usage = Command12.Usage({
9732
+ static usage = Command11.Usage({
9826
9733
  category: "Jobs",
9827
9734
  description: "Retention GC for completed / failed jobs (per config policy). --orphan-files removes MD files with no DB row.",
9828
9735
  details: `
@@ -9849,10 +9756,10 @@ var JobPruneCommand = class extends SmCommand {
9849
9756
  ["Preview without touching the DB", "$0 job prune --dry-run --json"]
9850
9757
  ]
9851
9758
  });
9852
- orphanFiles = Option12.Boolean("--orphan-files", false, {
9759
+ orphanFiles = Option11.Boolean("--orphan-files", false, {
9853
9760
  description: "Also remove MD files in .skill-map/jobs/ that have no matching state_jobs row."
9854
9761
  });
9855
- dryRun = Option12.Boolean("-n,--dry-run", false, {
9762
+ dryRun = Option11.Boolean("-n,--dry-run", false, {
9856
9763
  description: "Report what would be pruned without touching the DB or filesystem."
9857
9764
  });
9858
9765
  async run() {
@@ -9969,7 +9876,7 @@ function formatPolicy(seconds) {
9969
9876
  }
9970
9877
 
9971
9878
  // cli/commands/list.ts
9972
- import { Command as Command13, Option as Option13 } from "clipanion";
9879
+ import { Command as Command12, Option as Option12 } from "clipanion";
9973
9880
 
9974
9881
  // cli/i18n/list.texts.ts
9975
9882
  var LIST_TEXTS = {
@@ -9997,7 +9904,7 @@ var SORT_BY = {
9997
9904
  var PATH_COL_WIDTH = 50;
9998
9905
  var ListCommand = class extends SmCommand {
9999
9906
  static paths = [["list"]];
10000
- static usage = Command13.Usage({
9907
+ static usage = Command12.Usage({
10001
9908
  category: "Browse",
10002
9909
  description: "Tabular listing of nodes. --json emits an array conforming to node.schema.json.",
10003
9910
  details: `
@@ -10018,10 +9925,10 @@ var ListCommand = class extends SmCommand {
10018
9925
  ["Only nodes with issues, machine-readable", "$0 list --issue --json"]
10019
9926
  ]
10020
9927
  });
10021
- kind = Option13.String("--kind", { required: false });
10022
- issue = Option13.Boolean("--issue", false);
10023
- sortBy = Option13.String("--sort-by", { required: false });
10024
- limit = Option13.String("--limit", { required: false });
9928
+ kind = Option12.String("--kind", { required: false });
9929
+ issue = Option12.Boolean("--issue", false);
9930
+ sortBy = Option12.String("--sort-by", { required: false });
9931
+ limit = Option12.String("--limit", { required: false });
10025
9932
  async run() {
10026
9933
  let sortColumn = "path";
10027
9934
  let sortDirection = "asc";
@@ -10123,7 +10030,7 @@ function formatRow2(path, kind, out, inCount, ext, issues, bytes) {
10123
10030
  }
10124
10031
 
10125
10032
  // cli/commands/orphans.ts
10126
- import { Command as Command14, Option as Option14 } from "clipanion";
10033
+ import { Command as Command13, Option as Option13 } from "clipanion";
10127
10034
 
10128
10035
  // cli/i18n/orphans.texts.ts
10129
10036
  var ORPHANS_TEXTS = {
@@ -10178,7 +10085,7 @@ function isStringArray(v) {
10178
10085
  }
10179
10086
  var OrphansCommand = class extends SmCommand {
10180
10087
  static paths = [["orphans"]];
10181
- static usage = Command14.Usage({
10088
+ static usage = Command13.Usage({
10182
10089
  category: "Browse",
10183
10090
  description: "List orphan / auto-rename issues from the last scan. --json emits an array conforming to issue.schema.json.",
10184
10091
  details: `
@@ -10193,7 +10100,7 @@ var OrphansCommand = class extends SmCommand {
10193
10100
  ["Just the ambiguous ones, JSON", "$0 orphans --kind ambiguous --json"]
10194
10101
  ]
10195
10102
  });
10196
- kind = Option14.String("--kind", { required: false });
10103
+ kind = Option13.String("--kind", { required: false });
10197
10104
  async run() {
10198
10105
  let ruleFilter = null;
10199
10106
  if (this.kind !== void 0) {
@@ -10231,7 +10138,7 @@ var OrphansCommand = class extends SmCommand {
10231
10138
  };
10232
10139
  var OrphansReconcileCommand = class extends SmCommand {
10233
10140
  static paths = [["orphans", "reconcile"]];
10234
- static usage = Command14.Usage({
10141
+ static usage = Command13.Usage({
10235
10142
  category: "Browse",
10236
10143
  description: "Migrate state_* FKs from an orphan path to a live node, resolving the orphan issue.",
10237
10144
  details: `
@@ -10247,9 +10154,9 @@ var OrphansReconcileCommand = class extends SmCommand {
10247
10154
  ["Reattach orphan history", "$0 orphans reconcile skills/old.md --to skills/new.md"]
10248
10155
  ]
10249
10156
  });
10250
- orphanPath = Option14.String({ required: true });
10251
- to = Option14.String("--to", { required: true });
10252
- dryRun = Option14.Boolean("-n,--dry-run", false);
10157
+ orphanPath = Option13.String({ required: true });
10158
+ to = Option13.String("--to", { required: true });
10159
+ dryRun = Option13.Boolean("-n,--dry-run", false);
10253
10160
  async run() {
10254
10161
  const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
10255
10162
  if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
@@ -10319,7 +10226,7 @@ var OrphansReconcileCommand = class extends SmCommand {
10319
10226
  };
10320
10227
  var OrphansUndoRenameCommand = class extends SmCommand {
10321
10228
  static paths = [["orphans", "undo-rename"]];
10322
- static usage = Command14.Usage({
10229
+ static usage = Command13.Usage({
10323
10230
  category: "Browse",
10324
10231
  description: "Reverse a medium- or ambiguous-confidence auto-rename. Migrates state_* FKs back, emits a new orphan on the prior path.",
10325
10232
  details: `
@@ -10339,10 +10246,10 @@ var OrphansUndoRenameCommand = class extends SmCommand {
10339
10246
  ["Undo an ambiguous, picking a candidate", "$0 orphans undo-rename skills/new.md --from skills/old-a.md"]
10340
10247
  ]
10341
10248
  });
10342
- newPath = Option14.String({ required: true });
10343
- from = Option14.String("--from", { required: false });
10344
- force = Option14.Boolean("--force", false);
10345
- dryRun = Option14.Boolean("-n,--dry-run", false);
10249
+ newPath = Option13.String({ required: true });
10250
+ from = Option13.String("--from", { required: false });
10251
+ force = Option13.Boolean("--force", false);
10252
+ dryRun = Option13.Boolean("-n,--dry-run", false);
10346
10253
  async run() {
10347
10254
  const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
10348
10255
  if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
@@ -10506,9 +10413,9 @@ var ORPHANS_COMMANDS = [
10506
10413
  ];
10507
10414
 
10508
10415
  // cli/commands/plugins.ts
10509
- import { existsSync as existsSync14 } from "fs";
10510
- import { join as join13, resolve as resolve17 } from "path";
10511
- import { Command as Command15, Option as Option15 } from "clipanion";
10416
+ import { existsSync as existsSync13 } from "fs";
10417
+ import { join as join12, resolve as resolve16 } from "path";
10418
+ import { Command as Command14, Option as Option14 } from "clipanion";
10512
10419
 
10513
10420
  // cli/i18n/plugins.texts.ts
10514
10421
  var PLUGINS_TEXTS = {
@@ -10555,8 +10462,8 @@ var PLUGINS_TEXTS = {
10555
10462
  rowStatusOkPad: "ok ",
10556
10463
  rowStatusOffPad: "off ",
10557
10464
  builtInBundleHeader: "{{status}} {{id}}@built-in (granularity={{granularity}})",
10558
- builtInBundleKindsLine: " {{kinds}}",
10559
- builtInExtensionRow: " {{stat}} {{kind}}:{{qualifiedId}}@{{version}}",
10465
+ builtInBundleKindsLine: " {{kinds}}",
10466
+ builtInExtensionRow: "{{stat}} {{kind}}:{{qualifiedId}}@{{version}}",
10560
10467
  pluginRow: "{{statusIcon}} {{id}}@{{version}}{{granularitySuffix}}{{tail}}",
10561
10468
  pluginRowGranularitySuffix: " (granularity={{granularity}})",
10562
10469
  pluginRowTailEnabled: " \xB7 {{kinds}}",
@@ -10584,7 +10491,7 @@ var PLUGINS_TEXTS = {
10584
10491
 
10585
10492
  // cli/commands/plugins.ts
10586
10493
  function resolveSearchPaths2(opts, cwd, homedir3) {
10587
- if (opts.pluginDir) return [resolve17(opts.pluginDir)];
10494
+ if (opts.pluginDir) return [resolve16(opts.pluginDir)];
10588
10495
  const ctx = { cwd, homedir: homedir3 };
10589
10496
  const project = defaultProjectPluginsDir(ctx);
10590
10497
  const user = defaultUserPluginsDir(ctx);
@@ -10653,12 +10560,12 @@ function builtInRows(resolveEnabled) {
10653
10560
  }
10654
10561
  var PluginsListCommand = class extends SmCommand {
10655
10562
  static paths = [["plugins", "list"]];
10656
- static usage = Command15.Usage({
10563
+ static usage = Command14.Usage({
10657
10564
  category: "Plugins",
10658
10565
  description: "List discovered plugins and their load status.",
10659
10566
  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
10567
  });
10661
- pluginDir = Option15.String("--plugin-dir", { required: false });
10568
+ pluginDir = Option14.String("--plugin-dir", { required: false });
10662
10569
  async run() {
10663
10570
  const plugins = await loadAll({ global: this.global, pluginDir: this.pluginDir });
10664
10571
  const resolveEnabled = await buildResolver(this.global);
@@ -10688,13 +10595,15 @@ function renderBuiltInBundleRow(bundle) {
10688
10595
  })
10689
10596
  );
10690
10597
  if (bundle.granularity === "bundle") {
10691
- const kinds = bundle.extensions.map((e) => `${e.kind}:${qualifiedExtensionId(bundle.id, e.id)}`).join(", ");
10692
- lines.push(tx(PLUGINS_TEXTS.builtInBundleKindsLine, { kinds }));
10598
+ for (const ext of bundle.extensions) {
10599
+ const line = `${ext.kind}:${qualifiedExtensionId(bundle.id, ext.id)}@${ext.version}`;
10600
+ lines.push(tx(PLUGINS_TEXTS.builtInBundleKindsLine, { kinds: line }));
10601
+ }
10693
10602
  } else {
10694
10603
  for (const ext of bundle.extensions) {
10695
10604
  lines.push(
10696
10605
  tx(PLUGINS_TEXTS.builtInExtensionRow, {
10697
- stat: ext.enabled ? PLUGINS_TEXTS.rowStatusOkPad : PLUGINS_TEXTS.rowStatusOffPad,
10606
+ stat: ext.enabled ? PLUGINS_TEXTS.rowStatusOk : PLUGINS_TEXTS.rowStatusOff,
10698
10607
  kind: ext.kind,
10699
10608
  qualifiedId: qualifiedExtensionId(bundle.id, ext.id),
10700
10609
  version: ext.version
@@ -10720,12 +10629,12 @@ function renderPluginRow(p) {
10720
10629
  }
10721
10630
  var PluginsShowCommand = class extends SmCommand {
10722
10631
  static paths = [["plugins", "show"]];
10723
- static usage = Command15.Usage({
10632
+ static usage = Command14.Usage({
10724
10633
  category: "Plugins",
10725
10634
  description: "Show a single plugin's manifest + loaded extensions."
10726
10635
  });
10727
- id = Option15.String({ required: true });
10728
- pluginDir = Option15.String("--plugin-dir", { required: false });
10636
+ id = Option14.String({ required: true });
10637
+ pluginDir = Option14.String("--plugin-dir", { required: false });
10729
10638
  async run() {
10730
10639
  const plugins = await loadAll({ global: this.global, pluginDir: this.pluginDir });
10731
10640
  const resolveEnabled = await buildResolver(this.global);
@@ -10902,7 +10811,7 @@ function appendUnknownKindWarnings(out, extractorQualifiedId, applicableKinds, k
10902
10811
  }
10903
10812
  function expandHome(p, homedir3) {
10904
10813
  if (p === "~") return homedir3;
10905
- if (p.startsWith("~/")) return join13(homedir3, p.slice(2));
10814
+ if (p.startsWith("~/")) return join12(homedir3, p.slice(2));
10906
10815
  return p;
10907
10816
  }
10908
10817
  function collectExplorationDirWarnings(plugins, homedir3) {
@@ -10911,7 +10820,7 @@ function collectExplorationDirWarnings(plugins, homedir3) {
10911
10820
  const dir = instance["explorationDir"];
10912
10821
  if (typeof dir !== "string" || dir.length === 0) return;
10913
10822
  const resolved = expandHome(dir, homedir3);
10914
- if (!existsSync14(resolved)) {
10823
+ if (!existsSync13(resolved)) {
10915
10824
  out.push({
10916
10825
  providerQualifiedId: qualifiedExtensionId(pluginId, id),
10917
10826
  explorationDir: dir,
@@ -10923,12 +10832,12 @@ function collectExplorationDirWarnings(plugins, homedir3) {
10923
10832
  }
10924
10833
  var PluginsDoctorCommand = class extends SmCommand {
10925
10834
  static paths = [["plugins", "doctor"]];
10926
- static usage = Command15.Usage({
10835
+ static usage = Command14.Usage({
10927
10836
  category: "Plugins",
10928
10837
  description: "Run the full load pass and summarise by failure mode.",
10929
10838
  details: "Exit code 0 when every plugin loads or is intentionally disabled; 1 when any plugin is in an error / incompat state."
10930
10839
  });
10931
- pluginDir = Option15.String("--plugin-dir", { required: false });
10840
+ pluginDir = Option14.String("--plugin-dir", { required: false });
10932
10841
  // Doctor verb: counts by status + applicableKinds warnings +
10933
10842
  // explorationDir warnings + bad-plugins issues, each with its own
10934
10843
  // gated render. Branching is intrinsic to the multi-section diagnostic
@@ -11094,8 +11003,8 @@ function resolveToggleTarget(id, catalogue, verb) {
11094
11003
  return { key: bundle.id };
11095
11004
  }
11096
11005
  var TogglePluginsBase = class extends SmCommand {
11097
- all = Option15.Boolean("--all", false);
11098
- id = Option15.String({ required: false });
11006
+ all = Option14.Boolean("--all", false);
11007
+ id = Option14.String({ required: false });
11099
11008
  // eslint-disable-next-line complexity
11100
11009
  async toggle(enabled) {
11101
11010
  const verb = enabled ? "enable" : "disable";
@@ -11146,7 +11055,7 @@ var TogglePluginsBase = class extends SmCommand {
11146
11055
  };
11147
11056
  var PluginsEnableCommand = class extends TogglePluginsBase {
11148
11057
  static paths = [["plugins", "enable"]];
11149
- static usage = Command15.Usage({
11058
+ static usage = Command14.Usage({
11150
11059
  category: "Plugins",
11151
11060
  description: "Enable a plugin (or --all). Persists in config_plugins.",
11152
11061
  details: `
@@ -11168,7 +11077,7 @@ var PluginsEnableCommand = class extends TogglePluginsBase {
11168
11077
  };
11169
11078
  var PluginsDisableCommand = class extends TogglePluginsBase {
11170
11079
  static paths = [["plugins", "disable"]];
11171
- static usage = Command15.Usage({
11080
+ static usage = Command14.Usage({
11172
11081
  category: "Plugins",
11173
11082
  description: "Disable a plugin (or --all). Persists in config_plugins; does not delete files.",
11174
11083
  details: `
@@ -11204,8 +11113,8 @@ var PLUGIN_COMMANDS = [
11204
11113
 
11205
11114
  // cli/commands/refresh.ts
11206
11115
  import { readFile as readFile3 } from "fs/promises";
11207
- import { resolve as resolve19 } from "path";
11208
- import { Command as Command16, Option as Option16 } from "clipanion";
11116
+ import { resolve as resolve18 } from "path";
11117
+ import { Command as Command15, Option as Option15 } from "clipanion";
11209
11118
 
11210
11119
  // cli/i18n/refresh.texts.ts
11211
11120
  var REFRESH_TEXTS = {
@@ -11234,12 +11143,12 @@ var REFRESH_TEXTS = {
11234
11143
  };
11235
11144
 
11236
11145
  // cli/util/path-guard.ts
11237
- import { isAbsolute as isAbsolute3, resolve as resolve18, sep as sep3 } from "path";
11146
+ import { isAbsolute as isAbsolute3, resolve as resolve17, sep as sep3 } from "path";
11238
11147
  function assertContained2(cwd, rel) {
11239
11148
  if (isAbsolute3(rel)) {
11240
11149
  throw new Error(`node path is absolute, refusing to read: ${rel}`);
11241
11150
  }
11242
- const abs = resolve18(cwd, rel);
11151
+ const abs = resolve17(cwd, rel);
11243
11152
  if (abs !== cwd && !abs.startsWith(cwd + sep3)) {
11244
11153
  throw new Error(`node path escapes repo root: ${rel}`);
11245
11154
  }
@@ -11248,7 +11157,7 @@ function assertContained2(cwd, rel) {
11248
11157
  // cli/commands/refresh.ts
11249
11158
  var RefreshCommand = class extends SmCommand {
11250
11159
  static paths = [["refresh"]];
11251
- static usage = Command16.Usage({
11160
+ static usage = Command15.Usage({
11252
11161
  category: "Scan",
11253
11162
  description: "Refresh enrichment rows: granular (single node) or batch (every stale row).",
11254
11163
  details: `
@@ -11273,11 +11182,11 @@ var RefreshCommand = class extends SmCommand {
11273
11182
  ["Refresh every node with stale enrichments", "$0 refresh --stale"]
11274
11183
  ]
11275
11184
  });
11276
- nodePath = Option16.String({ name: "node", required: false });
11277
- stale = Option16.Boolean("--stale", false, {
11185
+ nodePath = Option15.String({ name: "node", required: false });
11186
+ stale = Option15.Boolean("--stale", false, {
11278
11187
  description: "Refresh every node whose probabilistic enrichment row is flagged stale=1."
11279
11188
  });
11280
- noPlugins = Option16.Boolean("--no-plugins", false, {
11189
+ noPlugins = Option15.Boolean("--no-plugins", false, {
11281
11190
  description: "Skip drop-in plugin discovery; use only the built-in extractor set."
11282
11191
  });
11283
11192
  // The remaining cyclomatic count comes from CLI ergonomics that don't
@@ -11413,7 +11322,7 @@ var RefreshCommand = class extends SmCommand {
11413
11322
  let body;
11414
11323
  try {
11415
11324
  assertContained2(cwd, node.path);
11416
- const raw = await readFile3(resolve19(cwd, node.path), "utf8");
11325
+ const raw = await readFile3(resolve18(cwd, node.path), "utf8");
11417
11326
  body = stripFrontmatterFence(raw);
11418
11327
  } catch (err) {
11419
11328
  this.context.stderr.write(
@@ -11462,7 +11371,7 @@ function stripFrontmatterFence(text) {
11462
11371
  var REFRESH_COMMANDS = [RefreshCommand];
11463
11372
 
11464
11373
  // cli/commands/scan.ts
11465
- import { Command as Command18, Option as Option18 } from "clipanion";
11374
+ import { Command as Command17, Option as Option17 } from "clipanion";
11466
11375
 
11467
11376
  // cli/i18n/scan.texts.ts
11468
11377
  var SCAN_TEXTS = {
@@ -11654,7 +11563,7 @@ async function runEphemeralPath(opts, dbPath, strict, loadPrior, runScanWith) {
11654
11563
  }
11655
11564
 
11656
11565
  // cli/commands/watch.ts
11657
- import { Command as Command17, Option as Option17 } from "clipanion";
11566
+ import { Command as Command16, Option as Option16 } from "clipanion";
11658
11567
 
11659
11568
  // cli/i18n/watch.texts.ts
11660
11569
  var WATCH_TEXTS = {
@@ -11833,7 +11742,7 @@ async function runWatchLoop(opts) {
11833
11742
  }
11834
11743
  var WatchCommand = class extends SmCommand {
11835
11744
  static paths = [["watch"]];
11836
- static usage = Command17.Usage({
11745
+ static usage = Command16.Usage({
11837
11746
  category: "Scan",
11838
11747
  description: "Watch roots and run an incremental scan after each debounced batch of filesystem events.",
11839
11748
  details: `
@@ -11857,17 +11766,17 @@ var WatchCommand = class extends SmCommand {
11857
11766
  ["Stream ScanResult per batch as ndjson", "$0 watch --json"]
11858
11767
  ]
11859
11768
  });
11860
- roots = Option17.Rest({ name: "roots" });
11861
- noTokens = Option17.Boolean("--no-tokens", false, {
11769
+ roots = Option16.Rest({ name: "roots" });
11770
+ noTokens = Option16.Boolean("--no-tokens", false, {
11862
11771
  description: "Skip per-node token counts (cl100k_base BPE)."
11863
11772
  });
11864
- strict = Option17.Boolean("--strict", false, {
11773
+ strict = Option16.Boolean("--strict", false, {
11865
11774
  description: "Promote frontmatter-validation findings from warn to error inside each batch. Does not change the watcher exit code."
11866
11775
  });
11867
- noPlugins = Option17.Boolean("--no-plugins", false, {
11776
+ noPlugins = Option16.Boolean("--no-plugins", false, {
11868
11777
  description: "Skip drop-in plugin discovery for the watcher session."
11869
11778
  });
11870
- maxConsecutiveFailures = Option17.String("--max-consecutive-failures", {
11779
+ maxConsecutiveFailures = Option16.String("--max-consecutive-failures", {
11871
11780
  required: false,
11872
11781
  description: "Shut down with exit 2 after N consecutive batch failures (default 5; 0 disables the breaker)."
11873
11782
  });
@@ -11905,7 +11814,7 @@ function parseBreakerLimit(raw, stderr) {
11905
11814
  // cli/commands/scan.ts
11906
11815
  var ScanCommand = class extends SmCommand {
11907
11816
  static paths = [["scan"]];
11908
- static usage = Command18.Usage({
11817
+ static usage = Command17.Usage({
11909
11818
  category: "Scan",
11910
11819
  description: "Scan roots for markdown nodes, run extractors and rules.",
11911
11820
  details: `
@@ -11934,29 +11843,29 @@ var ScanCommand = class extends SmCommand {
11934
11843
  ["What would the next incremental scan persist?", "$0 scan --changed -n --json"]
11935
11844
  ]
11936
11845
  });
11937
- roots = Option18.Rest({ name: "roots" });
11938
- noBuiltIns = Option18.Boolean("--no-built-ins", false, {
11846
+ roots = Option17.Rest({ name: "roots" });
11847
+ noBuiltIns = Option17.Boolean("--no-built-ins", false, {
11939
11848
  description: "Skip the built-in extension set. Yields a zero-filled ScanResult (kernel-empty-boot parity); skips DB persistence."
11940
11849
  });
11941
- noPlugins = Option18.Boolean("--no-plugins", false, {
11850
+ noPlugins = Option17.Boolean("--no-plugins", false, {
11942
11851
  description: "Skip drop-in plugin discovery. Only the built-in set runs. Combine with --no-built-ins for a fully empty pipeline."
11943
11852
  });
11944
- noTokens = Option18.Boolean("--no-tokens", false, {
11853
+ noTokens = Option17.Boolean("--no-tokens", false, {
11945
11854
  description: "Skip per-node token counts (cl100k_base BPE). Leaves node.tokens undefined; spec-valid since the field is optional."
11946
11855
  });
11947
- dryRun = Option18.Boolean("-n,--dry-run", false, {
11856
+ dryRun = Option17.Boolean("-n,--dry-run", false, {
11948
11857
  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
11858
  });
11950
- changed = Option18.Boolean("--changed", false, {
11859
+ changed = Option17.Boolean("--changed", false, {
11951
11860
  description: "Incremental scan: reuse unchanged nodes from the persisted prior snapshot. Degrades to a full scan if no prior snapshot exists."
11952
11861
  });
11953
- allowEmpty = Option18.Boolean("--allow-empty", false, {
11862
+ allowEmpty = Option17.Boolean("--allow-empty", false, {
11954
11863
  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
11864
  });
11956
- strict = Option18.Boolean("--strict", false, {
11865
+ strict = Option17.Boolean("--strict", false, {
11957
11866
  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
11867
  });
11959
- watch = Option18.Boolean("--watch", false, {
11868
+ watch = Option17.Boolean("--watch", false, {
11960
11869
  description: "Long-running mode: watch the roots and trigger an incremental scan after each debounced batch of filesystem events. Alias of `sm watch`."
11961
11870
  });
11962
11871
  async run() {
@@ -12054,11 +11963,11 @@ var ScanCommand = class extends SmCommand {
12054
11963
  };
12055
11964
 
12056
11965
  // cli/commands/scan-compare.ts
12057
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
12058
- import { Command as Command19, Option as Option19 } from "clipanion";
11966
+ import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
11967
+ import { Command as Command18, Option as Option18 } from "clipanion";
12059
11968
  var ScanCompareCommand = class extends SmCommand {
12060
11969
  static paths = [["scan", "compare-with"]];
12061
- static usage = Command19.Usage({
11970
+ static usage = Command18.Usage({
12062
11971
  category: "Scan",
12063
11972
  description: "Run a fresh scan in memory and emit a delta against the saved ScanResult dump at <dump>. Read-only.",
12064
11973
  details: `
@@ -12086,15 +11995,15 @@ var ScanCompareCommand = class extends SmCommand {
12086
11995
  ["JSON output for tooling", "$0 scan compare-with baseline.json --json"]
12087
11996
  ]
12088
11997
  });
12089
- dump = Option19.String({ required: true });
12090
- roots = Option19.Rest({ name: "roots" });
12091
- noTokens = Option19.Boolean("--no-tokens", false, {
11998
+ dump = Option18.String({ required: true });
11999
+ roots = Option18.Rest({ name: "roots" });
12000
+ noTokens = Option18.Boolean("--no-tokens", false, {
12092
12001
  description: "Skip per-node token counts during the fresh scan."
12093
12002
  });
12094
- strict = Option19.Boolean("--strict", false, {
12003
+ strict = Option18.Boolean("--strict", false, {
12095
12004
  description: "Promote layered-config warnings and frontmatter-validation findings from warn to error."
12096
12005
  });
12097
- noPlugins = Option19.Boolean("--no-plugins", false, {
12006
+ noPlugins = Option18.Boolean("--no-plugins", false, {
12098
12007
  description: "Skip drop-in plugin discovery."
12099
12008
  });
12100
12009
  // Cyclomatic count comes from CLI ergonomics: 3 distinct try/catch
@@ -12165,12 +12074,12 @@ var ScanCompareCommand = class extends SmCommand {
12165
12074
  }
12166
12075
  };
12167
12076
  function loadAndValidateDump(path) {
12168
- if (!existsSync15(path)) {
12077
+ if (!existsSync14(path)) {
12169
12078
  throw new Error(tx(SCAN_TEXTS.compareDumpNotFound, { path }));
12170
12079
  }
12171
12080
  let raw;
12172
12081
  try {
12173
- raw = readFileSync12(path, "utf8");
12082
+ raw = readFileSync11(path, "utf8");
12174
12083
  } catch (err) {
12175
12084
  const message = formatErrorMessage(err);
12176
12085
  throw new Error(tx(SCAN_TEXTS.compareDumpReadFailed, { path, message }), { cause: err });
@@ -12279,8 +12188,8 @@ function renderDeltaIssues(issues) {
12279
12188
 
12280
12189
  // cli/commands/serve.ts
12281
12190
  import { spawn } from "child_process";
12282
- import { existsSync as existsSync19 } from "fs";
12283
- import { Command as Command20, Option as Option20 } from "clipanion";
12191
+ import { existsSync as existsSync18 } from "fs";
12192
+ import { Command as Command19, Option as Option19 } from "clipanion";
12284
12193
 
12285
12194
  // server/index.ts
12286
12195
  import { serve } from "@hono/node-server";
@@ -12461,7 +12370,7 @@ function contentTypeFor(format) {
12461
12370
  }
12462
12371
 
12463
12372
  // server/health.ts
12464
- import { existsSync as existsSync16 } from "fs";
12373
+ import { existsSync as existsSync15 } from "fs";
12465
12374
  var FALLBACK_SCHEMA_VERSION = "1";
12466
12375
  function buildHealth(deps) {
12467
12376
  return {
@@ -12470,7 +12379,7 @@ function buildHealth(deps) {
12470
12379
  specVersion: deps.specVersion,
12471
12380
  implVersion: VERSION,
12472
12381
  scope: deps.scope,
12473
- db: existsSync16(deps.dbPath) ? "present" : "missing"
12382
+ db: existsSync15(deps.dbPath) ? "present" : "missing"
12474
12383
  };
12475
12384
  }
12476
12385
  async function resolveSpecVersion2() {
@@ -12910,9 +12819,9 @@ function emptyScanResult() {
12910
12819
  }
12911
12820
 
12912
12821
  // server/static.ts
12913
- import { existsSync as existsSync17 } from "fs";
12822
+ import { existsSync as existsSync16 } from "fs";
12914
12823
  import { readFile as readFile5 } from "fs/promises";
12915
- import { extname, join as join14 } from "path";
12824
+ import { extname, join as join13 } from "path";
12916
12825
  import { serveStatic } from "@hono/node-server/serve-static";
12917
12826
  var INDEX_HTML = "index.html";
12918
12827
  var PLACEHOLDER_HTML = `<!doctype html>
@@ -12943,8 +12852,8 @@ function createSpaFallback(uiDist) {
12943
12852
  return async (c, _next) => {
12944
12853
  if (c.req.method !== "GET" && c.req.method !== "HEAD") return c.notFound();
12945
12854
  if (uiDist === null) return htmlResponse(c, PLACEHOLDER_HTML);
12946
- const indexPath = join14(uiDist, INDEX_HTML);
12947
- if (!existsSync17(indexPath)) return htmlResponse(c, PLACEHOLDER_HTML);
12855
+ const indexPath = join13(uiDist, INDEX_HTML);
12856
+ if (!existsSync16(indexPath)) return htmlResponse(c, PLACEHOLDER_HTML);
12948
12857
  return fileResponse(c, indexPath);
12949
12858
  };
12950
12859
  }
@@ -13348,6 +13257,7 @@ function createWatcherService(opts) {
13348
13257
  if ("ready" in chokidarHandle && chokidarHandle.ready instanceof Promise) {
13349
13258
  await chokidarHandle.ready;
13350
13259
  }
13260
+ await runInitialBatch({ isStopped: () => stopped, runOneBatch });
13351
13261
  opts.broadcaster.broadcast(
13352
13262
  buildWatcherStartedEvent({ roots: [WATCH_ROOT], debounceMs })
13353
13263
  );
@@ -13430,6 +13340,19 @@ async function persistOutcome(dbPath, ran) {
13430
13340
  (writer) => writer.scans.persist(result, { renameOps, extractorRuns, enrichments })
13431
13341
  );
13432
13342
  }
13343
+ async function runInitialBatch(deps) {
13344
+ if (deps.isStopped()) return;
13345
+ try {
13346
+ await deps.runOneBatch();
13347
+ } catch (err) {
13348
+ const message = formatErrorMessage(err);
13349
+ log.warn(
13350
+ tx(SERVER_TEXTS.watcherBatchFailed, {
13351
+ message: sanitizeForTerminal(message)
13352
+ })
13353
+ );
13354
+ }
13355
+ }
13433
13356
 
13434
13357
  // server/options.ts
13435
13358
  var DEFAULT_PORT = 4242;
@@ -13534,10 +13457,10 @@ function validateWatcherDebounce(value) {
13534
13457
  }
13535
13458
 
13536
13459
  // server/paths.ts
13537
- import { existsSync as existsSync18, statSync as statSync5 } from "fs";
13538
- import { dirname as dirname10, isAbsolute as isAbsolute5, join as join15, resolve as resolve20 } from "path";
13539
- import { fileURLToPath as fileURLToPath6 } from "url";
13540
- var DEFAULT_UI_REL = join15("ui", "dist", "ui", "browser");
13460
+ import { existsSync as existsSync17, statSync as statSync5 } from "fs";
13461
+ import { dirname as dirname9, isAbsolute as isAbsolute5, join as join14, resolve as resolve19 } from "path";
13462
+ import { fileURLToPath as fileURLToPath5 } from "url";
13463
+ var DEFAULT_UI_REL = join14("ui", "dist", "ui", "browser");
13541
13464
  var PACKAGE_UI_REL = "ui";
13542
13465
  var INDEX_HTML2 = "index.html";
13543
13466
  function resolveDefaultUiDist(ctx) {
@@ -13546,13 +13469,13 @@ function resolveDefaultUiDist(ctx) {
13546
13469
  return walkUpForUi(ctx.cwd);
13547
13470
  }
13548
13471
  function resolveExplicitUiDist(ctx, raw) {
13549
- return isAbsolute5(raw) ? raw : resolve20(ctx.cwd, raw);
13472
+ return isAbsolute5(raw) ? raw : resolve19(ctx.cwd, raw);
13550
13473
  }
13551
13474
  function isUiBundleDir(path) {
13552
- if (!existsSync18(path)) return false;
13475
+ if (!existsSync17(path)) return false;
13553
13476
  try {
13554
13477
  if (!statSync5(path).isDirectory()) return false;
13555
- return existsSync18(join15(path, INDEX_HTML2));
13478
+ return existsSync17(join14(path, INDEX_HTML2));
13556
13479
  } catch {
13557
13480
  return false;
13558
13481
  }
@@ -13560,7 +13483,7 @@ function isUiBundleDir(path) {
13560
13483
  function resolvePackageBundledUi() {
13561
13484
  let here;
13562
13485
  try {
13563
- here = dirname10(fileURLToPath6(import.meta.url));
13486
+ here = dirname9(fileURLToPath5(import.meta.url));
13564
13487
  } catch {
13565
13488
  return null;
13566
13489
  }
@@ -13569,22 +13492,22 @@ function resolvePackageBundledUi() {
13569
13492
  function resolvePackageBundledUiFrom(here) {
13570
13493
  let current = here;
13571
13494
  for (let i = 0; i < 8; i++) {
13572
- const candidate = join15(current, PACKAGE_UI_REL);
13495
+ const candidate = join14(current, PACKAGE_UI_REL);
13573
13496
  if (isUiBundleDir(candidate)) return candidate;
13574
- const distHere = join15(current, "dist", PACKAGE_UI_REL);
13497
+ const distHere = join14(current, "dist", PACKAGE_UI_REL);
13575
13498
  if (isUiBundleDir(distHere)) return distHere;
13576
- const parent = dirname10(current);
13499
+ const parent = dirname9(current);
13577
13500
  if (parent === current) return null;
13578
13501
  current = parent;
13579
13502
  }
13580
13503
  return null;
13581
13504
  }
13582
13505
  function walkUpForUi(startDir) {
13583
- let current = resolve20(startDir);
13506
+ let current = resolve19(startDir);
13584
13507
  for (let i = 0; i < 64; i++) {
13585
- const candidate = join15(current, DEFAULT_UI_REL);
13508
+ const candidate = join14(current, DEFAULT_UI_REL);
13586
13509
  if (isUiBundleDir(candidate)) return candidate;
13587
- const parent = dirname10(current);
13510
+ const parent = dirname9(current);
13588
13511
  if (parent === current) return null;
13589
13512
  current = parent;
13590
13513
  }
@@ -13810,15 +13733,9 @@ function renderFiglet(input) {
13810
13733
  greenUnderline,
13811
13734
  greenUnderlineClose,
13812
13735
  violetOpen,
13813
- violetClose,
13814
- greenOpen,
13815
- greenClose
13736
+ violetClose
13816
13737
  } = resolveAnsi(input.colorEnabled);
13817
- const logoLines = LOGO_LINES.map((line, i) => {
13818
- const open = i < 3 ? violetOpen : greenOpen;
13819
- const close = i < 3 ? violetClose : greenClose;
13820
- return `${open}${line}${close}`;
13821
- });
13738
+ const logoLines = LOGO_LINES.map((line) => `${violetOpen}${line}${violetClose}`);
13822
13739
  const versionText = `v${input.version}`;
13823
13740
  const versionPad = Math.max(0, LOGO_WIDTH - versionText.length);
13824
13741
  const versionLine = `${" ".repeat(versionPad)}${dimOpen}${versionText}${dimClose}`;
@@ -13842,9 +13759,7 @@ var EMPTY_ANSI = {
13842
13759
  greenUnderline: "",
13843
13760
  greenUnderlineClose: "",
13844
13761
  violetOpen: "",
13845
- violetClose: "",
13846
- greenOpen: "",
13847
- greenClose: ""
13762
+ violetClose: ""
13848
13763
  };
13849
13764
  var ENABLED_ANSI = {
13850
13765
  dimOpen: ESC.dim,
@@ -13852,9 +13767,7 @@ var ENABLED_ANSI = {
13852
13767
  greenUnderline: `${ESC.green}${ESC.underline}`,
13853
13768
  greenUnderlineClose: ESC.reset,
13854
13769
  violetOpen: ESC.violet,
13855
- violetClose: ESC.reset,
13856
- greenOpen: ESC.green,
13857
- greenClose: ESC.reset
13770
+ violetClose: ESC.reset
13858
13771
  };
13859
13772
  function resolveAnsi(colorEnabled) {
13860
13773
  return colorEnabled ? ENABLED_ANSI : EMPTY_ANSI;
@@ -13880,7 +13793,7 @@ function formatCwdPath(cwd) {
13880
13793
  // cli/commands/serve.ts
13881
13794
  var ServeCommand = class extends SmCommand {
13882
13795
  static paths = [["serve"]];
13883
- static usage = Command20.Usage({
13796
+ static usage = Command19.Usage({
13884
13797
  category: "Setup",
13885
13798
  description: "Start the Hono BFF (single-port: REST + WebSocket + SPA bundle).",
13886
13799
  details: `
@@ -13905,22 +13818,22 @@ var ServeCommand = class extends SmCommand {
13905
13818
  ["Point at a pre-built UI bundle", "$0 serve --ui-dist ./ui/dist/browser"]
13906
13819
  ]
13907
13820
  });
13908
- port = Option20.String("--port", {
13821
+ port = Option19.String("--port", {
13909
13822
  required: false,
13910
13823
  description: "Listening port (default 4242). 0 = OS-assigned."
13911
13824
  });
13912
- host = Option20.String("--host", {
13825
+ host = Option19.String("--host", {
13913
13826
  required: false,
13914
13827
  description: "Listening host (default 127.0.0.1). Loopback-only enforced when --dev-cors is set."
13915
13828
  });
13916
- scope = Option20.String("--scope", {
13829
+ scope = Option19.String("--scope", {
13917
13830
  required: false,
13918
13831
  description: "project | global. Alias for -g/--global. Default: project."
13919
13832
  });
13920
- noBuiltIns = Option20.Boolean("--no-built-ins", false, {
13833
+ noBuiltIns = Option19.Boolean("--no-built-ins", false, {
13921
13834
  description: "Skip built-in plugin registration (parity with sm scan --no-built-ins)."
13922
13835
  });
13923
- noPlugins = Option20.Boolean("--no-plugins", false, {
13836
+ noPlugins = Option19.Boolean("--no-plugins", false, {
13924
13837
  description: "Skip drop-in plugin discovery."
13925
13838
  });
13926
13839
  // `Option.Boolean('--open', true)` — Clipanion's parser auto-derives
@@ -13930,24 +13843,24 @@ var ServeCommand = class extends SmCommand {
13930
13843
  // two registrations for the same flag and rejects the invocation
13931
13844
  // with "Ambiguous Syntax Error". Same convention shipped by every
13932
13845
  // other `--no-...` flag in the CLI tree.
13933
- open = Option20.Boolean("--open", true, {
13846
+ open = Option19.Boolean("--open", true, {
13934
13847
  description: "Auto-open the SPA in the user's default browser after listen. --no-open opts out."
13935
13848
  });
13936
- devCors = Option20.Boolean("--dev-cors", false, {
13849
+ devCors = Option19.Boolean("--dev-cors", false, {
13937
13850
  description: "Enable permissive CORS for the Angular dev-server proxy workflow."
13938
13851
  });
13939
13852
  // `--ui-dist` is intentionally undocumented in the Usage block above
13940
13853
  // (the demo build pipeline + tests rely on it; everyday users never
13941
13854
  // need it). Clipanion still exposes it on the parser; the Usage
13942
13855
  // omission is the "hidden" contract per the 14.1 brief.
13943
- uiDist = Option20.String("--ui-dist", { required: false, hidden: true });
13944
- noWatcher = Option20.Boolean("--no-watcher", false, {
13856
+ uiDist = Option19.String("--ui-dist", { required: false, hidden: true });
13857
+ noWatcher = Option19.Boolean("--no-watcher", false, {
13945
13858
  description: "Disable the chokidar-fed scan-and-broadcast loop. Use only for CI / read-only deployments."
13946
13859
  });
13947
13860
  // `--watcher-debounce-ms` is undocumented sugar for advanced users
13948
13861
  // who want to tighten / relax the watcher's batching window without
13949
13862
  // editing settings.json. Hidden flag — the Usage block omits it.
13950
- watcherDebounceMs = Option20.String("--watcher-debounce-ms", { required: false, hidden: true });
13863
+ watcherDebounceMs = Option19.String("--watcher-debounce-ms", { required: false, hidden: true });
13951
13864
  // Long-running daemon — `done in <…>` after a graceful shutdown is
13952
13865
  // noise. Mirrors `sm watch`'s opt-out.
13953
13866
  emitElapsed = false;
@@ -13975,7 +13888,7 @@ var ServeCommand = class extends SmCommand {
13975
13888
  return ExitCode.Error;
13976
13889
  }
13977
13890
  const dbPath = resolveDbPath({ global: this.global, db: this.db, ...runtimeCtx });
13978
- if (this.db !== void 0 && !existsSync19(dbPath)) {
13891
+ if (this.db !== void 0 && !existsSync18(dbPath)) {
13979
13892
  this.context.stderr.write(
13980
13893
  tx(SERVE_TEXTS.dbNotFound, { path: sanitizeForTerminal(dbPath) })
13981
13894
  );
@@ -14162,7 +14075,7 @@ function tryOpenBrowser(url, stderr) {
14162
14075
  }
14163
14076
 
14164
14077
  // cli/commands/show.ts
14165
- import { Command as Command21, Option as Option21 } from "clipanion";
14078
+ import { Command as Command20, Option as Option20 } from "clipanion";
14166
14079
 
14167
14080
  // cli/i18n/show.texts.ts
14168
14081
  var SHOW_TEXTS = {
@@ -14202,7 +14115,7 @@ var SHOW_TEXTS = {
14202
14115
  // cli/commands/show.ts
14203
14116
  var ShowCommand = class extends SmCommand {
14204
14117
  static paths = [["show"]];
14205
- static usage = Command21.Usage({
14118
+ static usage = Command20.Usage({
14206
14119
  category: "Browse",
14207
14120
  description: "Node detail: weight, frontmatter, links, issues.",
14208
14121
  details: `
@@ -14218,7 +14131,7 @@ var ShowCommand = class extends SmCommand {
14218
14131
  ["Machine-readable detail", "$0 show .claude/agents/architect.md --json"]
14219
14132
  ]
14220
14133
  });
14221
- nodePath = Option21.String({ required: true });
14134
+ nodePath = Option20.String({ required: true });
14222
14135
  async run() {
14223
14136
  const dbPath = resolveDbPath({ global: this.global, db: this.db, ...defaultRuntimeContext() });
14224
14137
  if (!assertDbExists(dbPath, this.context.stderr)) return ExitCode.NotFound;
@@ -14367,7 +14280,7 @@ function rankConfidenceForGrouping(c) {
14367
14280
  }
14368
14281
 
14369
14282
  // cli/commands/stubs.ts
14370
- import { Command as Command22, Option as Option22 } from "clipanion";
14283
+ import { Command as Command21, Option as Option21 } from "clipanion";
14371
14284
 
14372
14285
  // cli/i18n/stubs.texts.ts
14373
14286
  var STUBS_TEXTS = {
@@ -14382,9 +14295,9 @@ function notImplemented(cmd, verb) {
14382
14295
  cmd.context.stderr.write(tx(STUBS_TEXTS.notImplemented, { verb }));
14383
14296
  return ExitCode.Error;
14384
14297
  }
14385
- var DoctorCommand = class extends Command22 {
14298
+ var DoctorCommand = class extends Command21 {
14386
14299
  static paths = [["doctor"]];
14387
- static usage = Command22.Usage({
14300
+ static usage = Command21.Usage({
14388
14301
  category: "Setup",
14389
14302
  description: planned("Diagnostic report: DB integrity, pending migrations, orphan rows, plugin status, runner availability.")
14390
14303
  });
@@ -14392,23 +14305,23 @@ var DoctorCommand = class extends Command22 {
14392
14305
  return notImplemented(this, "doctor");
14393
14306
  }
14394
14307
  };
14395
- var FindingsCommand = class extends Command22 {
14308
+ var FindingsCommand = class extends Command21 {
14396
14309
  static paths = [["findings"]];
14397
- static usage = Command22.Usage({
14310
+ static usage = Command21.Usage({
14398
14311
  category: "Browse",
14399
14312
  description: planned("Probabilistic findings: injection, stale summaries, low confidence.")
14400
14313
  });
14401
- kind = Option22.String("--kind", { required: false });
14402
- since = Option22.String("--since", { required: false });
14403
- threshold = Option22.String("--threshold", { required: false });
14404
- json = Option22.Boolean("--json", false);
14314
+ kind = Option21.String("--kind", { required: false });
14315
+ since = Option21.String("--since", { required: false });
14316
+ threshold = Option21.String("--threshold", { required: false });
14317
+ json = Option21.Boolean("--json", false);
14405
14318
  async execute() {
14406
14319
  return notImplemented(this, "findings");
14407
14320
  }
14408
14321
  };
14409
- var ActionsListCommand = class extends Command22 {
14322
+ var ActionsListCommand = class extends Command21 {
14410
14323
  static paths = [["actions", "list"]];
14411
- static usage = Command22.Usage({
14324
+ static usage = Command21.Usage({
14412
14325
  category: "Jobs",
14413
14326
  description: planned("Registered action types (manifest view).")
14414
14327
  });
@@ -14416,121 +14329,121 @@ var ActionsListCommand = class extends Command22 {
14416
14329
  return notImplemented(this, "actions list");
14417
14330
  }
14418
14331
  };
14419
- var ActionsShowCommand = class extends Command22 {
14332
+ var ActionsShowCommand = class extends Command21 {
14420
14333
  static paths = [["actions", "show"]];
14421
- static usage = Command22.Usage({
14334
+ static usage = Command21.Usage({
14422
14335
  category: "Jobs",
14423
14336
  description: planned("Full action manifest, including preconditions and expected duration.")
14424
14337
  });
14425
- id = Option22.String({ required: true });
14338
+ id = Option21.String({ required: true });
14426
14339
  async execute() {
14427
14340
  return notImplemented(this, "actions show");
14428
14341
  }
14429
14342
  };
14430
- var JobSubmitCommand = class extends Command22 {
14343
+ var JobSubmitCommand = class extends Command21 {
14431
14344
  static paths = [["job", "submit"]];
14432
- static usage = Command22.Usage({
14345
+ static usage = Command21.Usage({
14433
14346
  category: "Jobs",
14434
14347
  description: planned("Enqueue a single job or fan out to every matching node (--all).")
14435
14348
  });
14436
- action = Option22.String({ required: true });
14437
- node = Option22.String("-n", { required: false });
14438
- all = Option22.Boolean("--all", false);
14439
- run = Option22.Boolean("--run", false);
14440
- force = Option22.Boolean("--force", false);
14441
- ttl = Option22.String("--ttl", { required: false });
14442
- priority = Option22.String("--priority", { required: false });
14349
+ action = Option21.String({ required: true });
14350
+ node = Option21.String("-n", { required: false });
14351
+ all = Option21.Boolean("--all", false);
14352
+ run = Option21.Boolean("--run", false);
14353
+ force = Option21.Boolean("--force", false);
14354
+ ttl = Option21.String("--ttl", { required: false });
14355
+ priority = Option21.String("--priority", { required: false });
14443
14356
  async execute() {
14444
14357
  return notImplemented(this, "job submit");
14445
14358
  }
14446
14359
  };
14447
- var JobListCommand = class extends Command22 {
14360
+ var JobListCommand = class extends Command21 {
14448
14361
  static paths = [["job", "list"]];
14449
- static usage = Command22.Usage({ category: "Jobs", description: planned("List jobs.") });
14450
- status = Option22.String("--status", { required: false });
14451
- action = Option22.String("--action", { required: false });
14452
- node = Option22.String("--node", { required: false });
14362
+ static usage = Command21.Usage({ category: "Jobs", description: planned("List jobs.") });
14363
+ status = Option21.String("--status", { required: false });
14364
+ action = Option21.String("--action", { required: false });
14365
+ node = Option21.String("--node", { required: false });
14453
14366
  async execute() {
14454
14367
  return notImplemented(this, "job list");
14455
14368
  }
14456
14369
  };
14457
- var JobShowCommand = class extends Command22 {
14370
+ var JobShowCommand = class extends Command21 {
14458
14371
  static paths = [["job", "show"]];
14459
- static usage = Command22.Usage({ category: "Jobs", description: planned("Job detail: state, claim time, TTL, runner, content hash.") });
14460
- id = Option22.String({ required: true });
14372
+ static usage = Command21.Usage({ category: "Jobs", description: planned("Job detail: state, claim time, TTL, runner, content hash.") });
14373
+ id = Option21.String({ required: true });
14461
14374
  async execute() {
14462
14375
  return notImplemented(this, "job show");
14463
14376
  }
14464
14377
  };
14465
- var JobPreviewCommand = class extends Command22 {
14378
+ var JobPreviewCommand = class extends Command21 {
14466
14379
  static paths = [["job", "preview"]];
14467
- static usage = Command22.Usage({ category: "Jobs", description: planned("Render the job MD file without executing.") });
14468
- id = Option22.String({ required: true });
14380
+ static usage = Command21.Usage({ category: "Jobs", description: planned("Render the job MD file without executing.") });
14381
+ id = Option21.String({ required: true });
14469
14382
  async execute() {
14470
14383
  return notImplemented(this, "job preview");
14471
14384
  }
14472
14385
  };
14473
- var JobClaimCommand = class extends Command22 {
14386
+ var JobClaimCommand = class extends Command21 {
14474
14387
  static paths = [["job", "claim"]];
14475
- static usage = Command22.Usage({
14388
+ static usage = Command21.Usage({
14476
14389
  category: "Jobs",
14477
14390
  description: planned("Atomic primitive: return next queued job id, mark it running.")
14478
14391
  });
14479
- filter = Option22.String("--filter", { required: false });
14392
+ filter = Option21.String("--filter", { required: false });
14480
14393
  async execute() {
14481
14394
  return notImplemented(this, "job claim");
14482
14395
  }
14483
14396
  };
14484
- var JobRunCommand = class extends Command22 {
14397
+ var JobRunCommand = class extends Command21 {
14485
14398
  static paths = [["job", "run"]];
14486
- static usage = Command22.Usage({
14399
+ static usage = Command21.Usage({
14487
14400
  category: "Jobs",
14488
14401
  description: planned("Full CLI-runner loop: claim + spawn + record.")
14489
14402
  });
14490
- all = Option22.Boolean("--all", false);
14491
- max = Option22.String("--max", { required: false });
14403
+ all = Option21.Boolean("--all", false);
14404
+ max = Option21.String("--max", { required: false });
14492
14405
  async execute() {
14493
14406
  return notImplemented(this, "job run");
14494
14407
  }
14495
14408
  };
14496
- var JobStatusCommand = class extends Command22 {
14409
+ var JobStatusCommand = class extends Command21 {
14497
14410
  static paths = [["job", "status"]];
14498
- static usage = Command22.Usage({
14411
+ static usage = Command21.Usage({
14499
14412
  category: "Jobs",
14500
14413
  description: planned("Counts (per status) or single-job status.")
14501
14414
  });
14502
- id = Option22.String({ required: false });
14415
+ id = Option21.String({ required: false });
14503
14416
  async execute() {
14504
14417
  return notImplemented(this, "job status");
14505
14418
  }
14506
14419
  };
14507
- var JobCancelCommand = class extends Command22 {
14420
+ var JobCancelCommand = class extends Command21 {
14508
14421
  static paths = [["job", "cancel"]];
14509
- static usage = Command22.Usage({
14422
+ static usage = Command21.Usage({
14510
14423
  category: "Jobs",
14511
14424
  description: planned("Force a running job to failed with reason user-cancelled.")
14512
14425
  });
14513
- id = Option22.String({ required: false });
14514
- all = Option22.Boolean("--all", false);
14426
+ id = Option21.String({ required: false });
14427
+ all = Option21.Boolean("--all", false);
14515
14428
  async execute() {
14516
14429
  return notImplemented(this, "job cancel");
14517
14430
  }
14518
14431
  };
14519
- var RecordCommand = class extends Command22 {
14432
+ var RecordCommand = class extends Command21 {
14520
14433
  static paths = [["record"]];
14521
- static usage = Command22.Usage({
14434
+ static usage = Command21.Usage({
14522
14435
  category: "Jobs",
14523
14436
  description: planned("Close a running job with success or failure. Nonce is the sole credential.")
14524
14437
  });
14525
- id = Option22.String("--id", { required: true });
14526
- nonce = Option22.String("--nonce", { required: true });
14527
- status = Option22.String("--status", { required: true });
14528
- report = Option22.String("--report", { required: false });
14529
- tokensIn = Option22.String("--tokens-in", { required: false });
14530
- tokensOut = Option22.String("--tokens-out", { required: false });
14531
- durationMs = Option22.String("--duration-ms", { required: false });
14532
- model = Option22.String("--model", { required: false });
14533
- error = Option22.String("--error", { required: false });
14438
+ id = Option21.String("--id", { required: true });
14439
+ nonce = Option21.String("--nonce", { required: true });
14440
+ status = Option21.String("--status", { required: true });
14441
+ report = Option21.String("--report", { required: false });
14442
+ tokensIn = Option21.String("--tokens-in", { required: false });
14443
+ tokensOut = Option21.String("--tokens-out", { required: false });
14444
+ durationMs = Option21.String("--duration-ms", { required: false });
14445
+ model = Option21.String("--model", { required: false });
14446
+ error = Option21.String("--error", { required: false });
14534
14447
  async execute() {
14535
14448
  return notImplemented(this, "record");
14536
14449
  }
@@ -14551,6 +14464,99 @@ var STUB_COMMANDS = [
14551
14464
  RecordCommand
14552
14465
  ];
14553
14466
 
14467
+ // cli/commands/tutorial.ts
14468
+ import { existsSync as existsSync19, readFileSync as readFileSync12 } from "fs";
14469
+ import { writeFile as writeFile2 } from "fs/promises";
14470
+ import { dirname as dirname10, join as join15, resolve as resolve20 } from "path";
14471
+ import { fileURLToPath as fileURLToPath6 } from "url";
14472
+ import { Command as Command22, Option as Option22 } from "clipanion";
14473
+
14474
+ // cli/i18n/tutorial.texts.ts
14475
+ var TUTORIAL_TEXTS = {
14476
+ // Success — written to stdout after `<cwd>/sm-tutorial.md` is created.
14477
+ 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',
14478
+ // Refusal — `sm-tutorial.md` already exists and `--force` was not set.
14479
+ // Goes to stderr, exit code 2 (operational error per spec § Exit codes).
14480
+ alreadyExists: "sm tutorial: sm-tutorial.md already exists at {{cwd}}. Pass `--force` to overwrite.\n",
14481
+ // I/O failure on write or on reading the bundled SKILL source.
14482
+ writeFailed: "sm tutorial: failed to write sm-tutorial.md: {{message}}\n",
14483
+ sourceMissing: "sm tutorial: could not read the bundled tutorial (SKILL.md) from the install. Reinstall @skill-map/cli or report the bug.\n"
14484
+ };
14485
+
14486
+ // cli/commands/tutorial.ts
14487
+ var SM_TUTORIAL_FILENAME = "sm-tutorial.md";
14488
+ var TutorialCommand = class extends SmCommand {
14489
+ static paths = [["tutorial"]];
14490
+ static usage = Command22.Usage({
14491
+ category: "Setup",
14492
+ description: "Materialize the interactive tester tutorial (sm-tutorial.md) in the current directory.",
14493
+ details: `
14494
+ Drops the canonical SKILL.md content as ./sm-tutorial.md so a tester
14495
+ can open Claude Code in the cwd and load the file as a skill by
14496
+ typing "ejecut\xE1 @sm-tutorial.md". Top-level only \u2014 no subdirectory
14497
+ is created.
14498
+
14499
+ Does NOT require an initialized .skill-map/ project. Refuses to
14500
+ overwrite an existing sm-tutorial.md unless --force is passed.
14501
+ `,
14502
+ examples: [
14503
+ ["Materialize the tutorial in the cwd", "$0 tutorial"],
14504
+ ["Overwrite an existing sm-tutorial.md", "$0 tutorial --force"]
14505
+ ]
14506
+ });
14507
+ force = Option22.Boolean("--force", false, {
14508
+ description: "Overwrite an existing sm-tutorial.md without prompting."
14509
+ });
14510
+ async run() {
14511
+ const ctx = defaultRuntimeContext();
14512
+ const target = join15(ctx.cwd, SM_TUTORIAL_FILENAME);
14513
+ if (await pathExists(target) && !this.force) {
14514
+ this.context.stderr.write(tx(TUTORIAL_TEXTS.alreadyExists, { cwd: ctx.cwd }));
14515
+ return ExitCode.Error;
14516
+ }
14517
+ let body;
14518
+ try {
14519
+ body = loadBundledTutorialText();
14520
+ } catch {
14521
+ this.context.stderr.write(TUTORIAL_TEXTS.sourceMissing);
14522
+ return ExitCode.Error;
14523
+ }
14524
+ try {
14525
+ await writeFile2(target, body);
14526
+ } catch (err) {
14527
+ this.context.stderr.write(
14528
+ tx(TUTORIAL_TEXTS.writeFailed, { message: formatErrorMessage(err) })
14529
+ );
14530
+ return ExitCode.Error;
14531
+ }
14532
+ this.context.stdout.write(tx(TUTORIAL_TEXTS.written, { cwd: ctx.cwd }));
14533
+ return ExitCode.Ok;
14534
+ }
14535
+ };
14536
+ var cachedTutorial = null;
14537
+ function loadBundledTutorialText() {
14538
+ if (cachedTutorial !== null) return cachedTutorial;
14539
+ cachedTutorial = readTutorialFromDisk();
14540
+ return cachedTutorial;
14541
+ }
14542
+ function readTutorialFromDisk() {
14543
+ const here = dirname10(fileURLToPath6(import.meta.url));
14544
+ const candidates = [
14545
+ // dev: src/cli/commands/ → repo-root .claude/skills/sm-tutorial/SKILL.md
14546
+ resolve20(here, "../../../.claude/skills/sm-tutorial/SKILL.md"),
14547
+ // bundled: dist/cli.js → dist/cli/tutorial/sm-tutorial.md (sibling)
14548
+ resolve20(here, "cli/tutorial/sm-tutorial.md"),
14549
+ // bundled fallback: any-depth → cli/tutorial/sm-tutorial.md
14550
+ resolve20(here, "../cli/tutorial/sm-tutorial.md")
14551
+ ];
14552
+ for (const candidate of candidates) {
14553
+ if (existsSync19(candidate)) {
14554
+ return readFileSync12(candidate, "utf8");
14555
+ }
14556
+ }
14557
+ throw new Error(`SKILL.md not found in any candidate location (last tried: ${candidates[candidates.length - 1]})`);
14558
+ }
14559
+
14554
14560
  // cli/commands/version.ts
14555
14561
  import { Command as Command23 } from "clipanion";
14556
14562
 
@@ -14634,7 +14640,7 @@ cli.register(Builtins.VersionCommand);
14634
14640
  cli.register(RootHelpCommand);
14635
14641
  cli.register(HelpCommand);
14636
14642
  cli.register(InitCommand);
14637
- cli.register(GuideCommand);
14643
+ cli.register(TutorialCommand);
14638
14644
  cli.register(ScanCommand);
14639
14645
  cli.register(ScanCompareCommand);
14640
14646
  cli.register(ServeCommand);