@skill-map/cli 0.24.5 → 0.26.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/tutorial/sm-master.md +498 -0
- package/dist/cli/tutorial/sm-tutorial.md +407 -306
- package/dist/cli.js +290 -105
- package/dist/cli.js.map +1 -1
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.js +22 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/{chunk-BK4M46IZ.js → chunk-4GTCV7V4.js} +1 -1
- package/dist/ui/{chunk-533YMAY3.js → chunk-PY2R7LHN.js} +2 -2
- package/dist/ui/{chunk-5RHOYCWS.js → chunk-Q64EKSUB.js} +3 -3
- package/dist/ui/chunk-VH5GRUT7.js +255 -0
- package/dist/ui/{chunk-RR36XBDS.js → chunk-WOLLYGGL.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/ui/main-CYRAD3L6.js +2 -0
- package/dist/ui/{styles-DLFC3F2G.css → styles-EGXMA46P.css} +1 -1
- package/package.json +2 -2
- package/dist/ui/chunk-O546Z3K4.js +0 -251
- package/dist/ui/main-PNXPQAO6.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -748,19 +748,19 @@ var annotationsExtractor = {
|
|
|
748
748
|
pluginId: "core",
|
|
749
749
|
kind: "extractor",
|
|
750
750
|
version: "1.0.0",
|
|
751
|
-
description: "Turns the `supersedes
|
|
751
|
+
description: "Turns the `supersedes` and `supersededBy` entries you write in a node's `.sm` sidecar into the arrows (edges) shown between nodes in the graph.",
|
|
752
752
|
stability: "stable",
|
|
753
|
-
emitsLinkKinds: ["supersedes"
|
|
753
|
+
emitsLinkKinds: ["supersedes"],
|
|
754
754
|
defaultConfidence: "high",
|
|
755
755
|
scope: "frontmatter",
|
|
756
756
|
extract(ctx) {
|
|
757
757
|
const sourcePath = ctx.node.path;
|
|
758
758
|
const seen = /* @__PURE__ */ new Set();
|
|
759
|
-
function emit(source, target
|
|
760
|
-
const key = `${source} ${target}
|
|
759
|
+
function emit(source, target) {
|
|
760
|
+
const key = `${source} ${target}`;
|
|
761
761
|
if (seen.has(key)) return;
|
|
762
762
|
seen.add(key);
|
|
763
|
-
ctx.emitLink(link(source, target
|
|
763
|
+
ctx.emitLink(link(source, target));
|
|
764
764
|
}
|
|
765
765
|
const ann = pickAnnotations(ctx.node);
|
|
766
766
|
if (ann) processBlock(ann, sourcePath, emit);
|
|
@@ -768,20 +768,11 @@ var annotationsExtractor = {
|
|
|
768
768
|
};
|
|
769
769
|
function processBlock(block, sourcePath, emit) {
|
|
770
770
|
for (const target of stringArray(block["supersedes"])) {
|
|
771
|
-
emit(sourcePath, target
|
|
771
|
+
emit(sourcePath, target);
|
|
772
772
|
}
|
|
773
773
|
const supersededBy = block["supersededBy"];
|
|
774
774
|
if (typeof supersededBy === "string" && supersededBy.length > 0) {
|
|
775
|
-
emit(supersededBy, sourcePath
|
|
776
|
-
}
|
|
777
|
-
for (const target of stringArray(block["requires"])) {
|
|
778
|
-
emit(sourcePath, target, "references");
|
|
779
|
-
}
|
|
780
|
-
for (const target of stringArray(block["related"])) {
|
|
781
|
-
emit(sourcePath, target, "references");
|
|
782
|
-
}
|
|
783
|
-
for (const target of stringArray(block["conflictsWith"])) {
|
|
784
|
-
emit(sourcePath, target, "references");
|
|
775
|
+
emit(supersededBy, sourcePath);
|
|
785
776
|
}
|
|
786
777
|
}
|
|
787
778
|
function pickAnnotations(node) {
|
|
@@ -797,11 +788,11 @@ function stringArray(value) {
|
|
|
797
788
|
if (!Array.isArray(value)) return [];
|
|
798
789
|
return value.filter((v) => typeof v === "string" && v.length > 0);
|
|
799
790
|
}
|
|
800
|
-
function link(source, target
|
|
791
|
+
function link(source, target) {
|
|
801
792
|
return {
|
|
802
793
|
source,
|
|
803
794
|
target,
|
|
804
|
-
kind,
|
|
795
|
+
kind: "supersedes",
|
|
805
796
|
confidence: "high",
|
|
806
797
|
sources: [ID]
|
|
807
798
|
};
|
|
@@ -2318,7 +2309,13 @@ var VALIDATE_ALL_TEXTS = {
|
|
|
2318
2309
|
/** `Node <path> failed schema validation: <errors>` */
|
|
2319
2310
|
nodeFailure: "Node {{path}} failed schema validation: {{errors}}",
|
|
2320
2311
|
/** `Link <source> → <target> failed schema validation: <errors>` */
|
|
2321
|
-
linkFailure: "Link {{source}} \u2192 {{target}} failed schema validation: {{errors}}"
|
|
2312
|
+
linkFailure: "Link {{source}} \u2192 {{target}} failed schema validation: {{errors}}",
|
|
2313
|
+
/** `Node <path> is missing required frontmatter fields: <missing>` */
|
|
2314
|
+
frontmatterBaseFailure: "Node {{path}} is missing required frontmatter fields: {{missing}}.",
|
|
2315
|
+
/** Singular tooltip on the alert / chip when a node has exactly one validation failure. */
|
|
2316
|
+
alertTooltipSingle: "Frontmatter or schema validation failed.",
|
|
2317
|
+
/** Plural tooltip; `{{count}}` capped at 99 in the chip badge but the tooltip text shows the raw count. */
|
|
2318
|
+
alertTooltipMany: "{{count}} schema validation issues on this node."
|
|
2322
2319
|
};
|
|
2323
2320
|
|
|
2324
2321
|
// built-in-plugins/analyzers/validate-all/index.ts
|
|
@@ -2331,15 +2328,56 @@ var validateAllAnalyzer = {
|
|
|
2331
2328
|
description: "Detects and flags nodes or links violating the project schemas.",
|
|
2332
2329
|
stability: "stable",
|
|
2333
2330
|
mode: "deterministic",
|
|
2331
|
+
viewContributions: {
|
|
2332
|
+
// Corner badge on the graph card; surfaces when the node body /
|
|
2333
|
+
// frontmatter fails schema validation (parse error, missing
|
|
2334
|
+
// `name`/`description`, malformed YAML, etc.). Same visual
|
|
2335
|
+
// chassis as `core/broken-ref`, danger severity.
|
|
2336
|
+
alert: {
|
|
2337
|
+
slot: "graph.node.alert",
|
|
2338
|
+
icon: "fa-solid fa-triangle-exclamation",
|
|
2339
|
+
emitWhenEmpty: false
|
|
2340
|
+
},
|
|
2341
|
+
// Footer chip that mirrors the corner alert with the actual
|
|
2342
|
+
// count so the operator can scan the cards and prioritise.
|
|
2343
|
+
// Outlined (vs the filled corner alert) per the broken-ref
|
|
2344
|
+
// pattern: two beats of the same signal.
|
|
2345
|
+
chip: {
|
|
2346
|
+
slot: "card.footer.right",
|
|
2347
|
+
icon: "fa-regular fa-triangle-exclamation",
|
|
2348
|
+
emitWhenEmpty: false,
|
|
2349
|
+
priority: 35
|
|
2350
|
+
}
|
|
2351
|
+
},
|
|
2334
2352
|
evaluate(ctx) {
|
|
2335
2353
|
const validators = loadSchemaValidators();
|
|
2336
2354
|
const findings = [];
|
|
2355
|
+
const perNode = /* @__PURE__ */ new Map();
|
|
2337
2356
|
for (const node of ctx.nodes) {
|
|
2357
|
+
const before = findings.length;
|
|
2338
2358
|
collectNodeFindings(validators, node, findings);
|
|
2359
|
+
collectFrontmatterBaseFindings(node, findings);
|
|
2360
|
+
if (findings.length > before) {
|
|
2361
|
+
perNode.set(node.path, (perNode.get(node.path) ?? 0) + (findings.length - before));
|
|
2362
|
+
}
|
|
2339
2363
|
}
|
|
2340
2364
|
for (const link2 of ctx.links) {
|
|
2341
2365
|
collectLinkFindings(validators, link2, findings);
|
|
2342
2366
|
}
|
|
2367
|
+
for (const [nodePath, count] of perNode) {
|
|
2368
|
+
const tooltip = count === 1 ? VALIDATE_ALL_TEXTS.alertTooltipSingle : tx(VALIDATE_ALL_TEXTS.alertTooltipMany, { count });
|
|
2369
|
+
const capped = Math.min(count, 99);
|
|
2370
|
+
ctx.emitContribution(nodePath, "alert", {
|
|
2371
|
+
icon: "fa-solid fa-triangle-exclamation",
|
|
2372
|
+
severity: "danger",
|
|
2373
|
+
tooltip
|
|
2374
|
+
});
|
|
2375
|
+
ctx.emitContribution(nodePath, "chip", {
|
|
2376
|
+
value: capped,
|
|
2377
|
+
severity: "danger",
|
|
2378
|
+
tooltip
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2343
2381
|
return findings;
|
|
2344
2382
|
}
|
|
2345
2383
|
};
|
|
@@ -2357,6 +2395,33 @@ function collectNodeFindings(v, node, out) {
|
|
|
2357
2395
|
data: { target: "node", path: node.path }
|
|
2358
2396
|
});
|
|
2359
2397
|
}
|
|
2398
|
+
function collectFrontmatterBaseFindings(node, out) {
|
|
2399
|
+
if (node.provider === "markdown") return;
|
|
2400
|
+
if (node.bytes.frontmatter === 0) return;
|
|
2401
|
+
const fm = node.frontmatter ?? {};
|
|
2402
|
+
const missing = [];
|
|
2403
|
+
if (isMissingStringField(fm, "name")) missing.push("name");
|
|
2404
|
+
if (isMissingStringField(fm, "description")) missing.push("description");
|
|
2405
|
+
if (missing.length === 0) return;
|
|
2406
|
+
out.push({
|
|
2407
|
+
analyzerId: ID19,
|
|
2408
|
+
// `warn` (not `error`) so the default `sm scan` exit code stays
|
|
2409
|
+
// 0 even when nodes are missing frontmatter base fields. Strict
|
|
2410
|
+
// mode (`sm scan --strict`) still escalates to exit 1. Matches
|
|
2411
|
+
// the `frontmatter-invalid` severity policy of the orchestrator.
|
|
2412
|
+
severity: "warn",
|
|
2413
|
+
nodeIds: [node.path],
|
|
2414
|
+
message: tx(VALIDATE_ALL_TEXTS.frontmatterBaseFailure, {
|
|
2415
|
+
path: node.path,
|
|
2416
|
+
missing: missing.join(", ")
|
|
2417
|
+
}),
|
|
2418
|
+
data: { target: "frontmatter", path: node.path, missing }
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
function isMissingStringField(fm, field) {
|
|
2422
|
+
const v = fm[field];
|
|
2423
|
+
return typeof v !== "string" || v.length === 0;
|
|
2424
|
+
}
|
|
2360
2425
|
function collectLinkFindings(v, link2, out) {
|
|
2361
2426
|
const result = v.validate("link", toLinkForSchema(link2));
|
|
2362
2427
|
if (result.ok) return;
|
|
@@ -2401,6 +2466,54 @@ function toLinkForSchema(link2) {
|
|
|
2401
2466
|
};
|
|
2402
2467
|
}
|
|
2403
2468
|
|
|
2469
|
+
// kernel/util/trigger-resolve.ts
|
|
2470
|
+
function buildNameIndex(nodes) {
|
|
2471
|
+
const out = /* @__PURE__ */ new Map();
|
|
2472
|
+
indexByCanonicalName(nodes, out);
|
|
2473
|
+
fillIndexWithPathBasename(nodes, out);
|
|
2474
|
+
return out;
|
|
2475
|
+
}
|
|
2476
|
+
function indexByCanonicalName(nodes, out) {
|
|
2477
|
+
for (const node of nodes) {
|
|
2478
|
+
const raw = canonicalName(node);
|
|
2479
|
+
if (raw === null) continue;
|
|
2480
|
+
const key = normalizeTrigger(raw);
|
|
2481
|
+
if (!out.has(key)) out.set(key, node.path);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
function fillIndexWithPathBasename(nodes, out) {
|
|
2485
|
+
for (const node of nodes) {
|
|
2486
|
+
if (canonicalName(node) !== null) continue;
|
|
2487
|
+
const derived = pathBasenameForLink(node.path);
|
|
2488
|
+
if (derived.length === 0) continue;
|
|
2489
|
+
const key = normalizeTrigger(derived);
|
|
2490
|
+
if (!out.has(key)) out.set(key, node.path);
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
function canonicalName(node) {
|
|
2494
|
+
const raw = node.frontmatter?.["name"];
|
|
2495
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
2496
|
+
return raw;
|
|
2497
|
+
}
|
|
2498
|
+
function pathBasenameForLink(path) {
|
|
2499
|
+
const segments = path.split("/").filter((s) => s.length > 0);
|
|
2500
|
+
if (segments.length === 0) return path;
|
|
2501
|
+
const last = segments[segments.length - 1];
|
|
2502
|
+
if (last === "SKILL.md" && segments.length >= 2) {
|
|
2503
|
+
return segments[segments.length - 2];
|
|
2504
|
+
}
|
|
2505
|
+
return last.replace(/\.md$/, "");
|
|
2506
|
+
}
|
|
2507
|
+
function resolveLinkTargetToPath(link2, nameIndex) {
|
|
2508
|
+
const raw = link2.target;
|
|
2509
|
+
const sigil = raw.charAt(0);
|
|
2510
|
+
if (sigil !== "/" && sigil !== "@") return raw;
|
|
2511
|
+
const normalizedTrigger = link2.trigger?.normalizedTrigger;
|
|
2512
|
+
const normalized = typeof normalizedTrigger === "string" ? normalizedTrigger.replace(/^[/@]/, "").trim() : normalizeTrigger(raw.slice(1));
|
|
2513
|
+
const resolved = nameIndex.get(normalized);
|
|
2514
|
+
return resolved ?? raw;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2404
2517
|
// built-in-plugins/analyzers/link-counts/index.ts
|
|
2405
2518
|
var ID20 = "link-counts";
|
|
2406
2519
|
var linkCountsAnalyzer = {
|
|
@@ -2428,10 +2541,12 @@ var linkCountsAnalyzer = {
|
|
|
2428
2541
|
}
|
|
2429
2542
|
},
|
|
2430
2543
|
evaluate(ctx) {
|
|
2544
|
+
const nameIndex = buildNameIndex(ctx.nodes);
|
|
2431
2545
|
const perTarget = /* @__PURE__ */ new Map();
|
|
2432
2546
|
const perSource = /* @__PURE__ */ new Map();
|
|
2433
2547
|
for (const link2 of ctx.links) {
|
|
2434
|
-
|
|
2548
|
+
const resolvedTarget = resolveLinkTargetToPath(link2, nameIndex);
|
|
2549
|
+
bump(perTarget, resolvedTarget, link2.kind);
|
|
2435
2550
|
bump(perSource, link2.source, link2.kind);
|
|
2436
2551
|
}
|
|
2437
2552
|
for (const node of ctx.nodes) {
|
|
@@ -4614,8 +4729,8 @@ async function saveUpdateCheckCache(db, cache) {
|
|
|
4614
4729
|
var SORT_BY_COLUMNS = /* @__PURE__ */ new Set([
|
|
4615
4730
|
"path",
|
|
4616
4731
|
"kind",
|
|
4617
|
-
"
|
|
4618
|
-
"
|
|
4732
|
+
"tokens_total",
|
|
4733
|
+
"tokensTotal",
|
|
4619
4734
|
"links_out_count",
|
|
4620
4735
|
"linksOutCount",
|
|
4621
4736
|
"links_in_count",
|
|
@@ -4626,7 +4741,7 @@ var SORT_BY_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
4626
4741
|
var SORT_BY_DEFAULT_DIRECTION = {
|
|
4627
4742
|
path: "asc",
|
|
4628
4743
|
kind: "asc",
|
|
4629
|
-
|
|
4744
|
+
tokensTotal: "desc",
|
|
4630
4745
|
linksOutCount: "desc",
|
|
4631
4746
|
linksInCount: "desc",
|
|
4632
4747
|
externalRefsCount: "desc"
|
|
@@ -5747,7 +5862,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
5747
5862
|
// package.json
|
|
5748
5863
|
var package_default = {
|
|
5749
5864
|
name: "@skill-map/cli",
|
|
5750
|
-
version: "0.
|
|
5865
|
+
version: "0.26.0",
|
|
5751
5866
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
5752
5867
|
license: "MIT",
|
|
5753
5868
|
type: "module",
|
|
@@ -6705,16 +6820,25 @@ var BUMP_TEXTS = {
|
|
|
6705
6820
|
// --- failures -------------------------------------------------------------
|
|
6706
6821
|
bumpFailed: "{{glyph}} sm bump: {{message}}\n",
|
|
6707
6822
|
storeFailedDetail: "sidecar write failed for {{path}}: {{message}}",
|
|
6708
|
-
resolveAbsPathFailed: "cannot resolve absolute path for {{nodePath}}: {{message}}"
|
|
6823
|
+
resolveAbsPathFailed: "cannot resolve absolute path for {{nodePath}}: {{message}}"
|
|
6709
6824
|
// --- .sm consent gate ---------------------------------------------------
|
|
6825
|
+
// The shared strings live in `consent.texts.ts` (CONSENT_TEXTS); they
|
|
6826
|
+
// are used by every verb that writes a sidecar (`sm bump`,
|
|
6827
|
+
// `sm sidecar refresh`, `sm sidecar annotate`) with a `{{verb}}`
|
|
6828
|
+
// placeholder for the directed prefix.
|
|
6829
|
+
};
|
|
6830
|
+
|
|
6831
|
+
// cli/i18n/consent.texts.ts
|
|
6832
|
+
var CONSENT_TEXTS = {
|
|
6710
6833
|
/**
|
|
6711
6834
|
* Pre-prompt context shown before the interactive `confirm()` so the
|
|
6712
|
-
* operator sees what they are about to opt into.
|
|
6713
|
-
* is gitignored, the choice is saved
|
|
6835
|
+
* operator sees what they are about to opt into.
|
|
6836
|
+
* `.skill-map/settings.local.json` is gitignored, the choice is saved
|
|
6837
|
+
* per-checkout, never travels via the repo.
|
|
6714
6838
|
*/
|
|
6715
|
-
consentPrompt: "skill-map needs
|
|
6716
|
-
consentAborted: "{{glyph}}
|
|
6717
|
-
consentRequiredNonTty: "{{glyph}}
|
|
6839
|
+
consentPrompt: "{{glyph}} skill-map needs consent to create .sm sidecar files next to your\n .md sources. Your choice is saved to .skill-map/settings.local.json\n (gitignored) and this prompt will not appear again.\n\nAllow .sm sidecar writes in this project?",
|
|
6840
|
+
consentAborted: "{{glyph}} {{verb}}: aborted by user. No .sm sidecar files were written.\n",
|
|
6841
|
+
consentRequiredNonTty: "{{glyph}} {{verb}}: consent required to write .sm sidecar files in this project.\n {{hint}}\n",
|
|
6718
6842
|
consentRequiredNonTtyHint: "Pass --yes to grant (writes to .skill-map/settings.local.json, gitignored)."
|
|
6719
6843
|
};
|
|
6720
6844
|
|
|
@@ -7112,21 +7236,25 @@ var BumpCommand = class extends SmCommand {
|
|
|
7112
7236
|
const isTTY = stdin.isTTY === true;
|
|
7113
7237
|
if (!isTTY || this.yes) {
|
|
7114
7238
|
this.printer.error(
|
|
7115
|
-
tx(
|
|
7239
|
+
tx(CONSENT_TEXTS.consentRequiredNonTty, {
|
|
7116
7240
|
glyph: ansi.red("\u2715"),
|
|
7117
|
-
|
|
7241
|
+
verb: "sm bump",
|
|
7242
|
+
hint: ansi.dim(CONSENT_TEXTS.consentRequiredNonTtyHint)
|
|
7118
7243
|
})
|
|
7119
7244
|
);
|
|
7120
7245
|
return ExitCode.Error;
|
|
7121
7246
|
}
|
|
7122
7247
|
const ok = await confirm(
|
|
7123
|
-
|
|
7248
|
+
tx(CONSENT_TEXTS.consentPrompt, { glyph: ansi.cyan("\u2139") }),
|
|
7124
7249
|
{ stdin, stderr },
|
|
7125
7250
|
{ defaultAnswer: "yes" }
|
|
7126
7251
|
);
|
|
7127
7252
|
if (!ok) {
|
|
7128
7253
|
this.printer.info(
|
|
7129
|
-
tx(
|
|
7254
|
+
tx(CONSENT_TEXTS.consentAborted, {
|
|
7255
|
+
glyph: ansi.cyan("\u2139"),
|
|
7256
|
+
verb: "sm bump"
|
|
7257
|
+
})
|
|
7130
7258
|
);
|
|
7131
7259
|
return ExitCode.Error;
|
|
7132
7260
|
}
|
|
@@ -12502,6 +12630,26 @@ function validateLink(extractor, link2, emitter) {
|
|
|
12502
12630
|
const confidence = link2.confidence ?? extractor.defaultConfidence;
|
|
12503
12631
|
return { ...link2, confidence };
|
|
12504
12632
|
}
|
|
12633
|
+
function dedupeLinks(links) {
|
|
12634
|
+
const out = /* @__PURE__ */ new Map();
|
|
12635
|
+
for (const link2 of links) {
|
|
12636
|
+
const trigger = link2.trigger?.normalizedTrigger ?? "";
|
|
12637
|
+
const key = `${link2.source}\0${link2.target}\0${link2.kind}\0${trigger}`;
|
|
12638
|
+
const existing = out.get(key);
|
|
12639
|
+
if (existing) {
|
|
12640
|
+
const seen = new Set(existing.sources);
|
|
12641
|
+
for (const src of link2.sources) {
|
|
12642
|
+
if (!seen.has(src)) {
|
|
12643
|
+
seen.add(src);
|
|
12644
|
+
existing.sources = [...existing.sources, src];
|
|
12645
|
+
}
|
|
12646
|
+
}
|
|
12647
|
+
continue;
|
|
12648
|
+
}
|
|
12649
|
+
out.set(key, link2);
|
|
12650
|
+
}
|
|
12651
|
+
return [...out.values()];
|
|
12652
|
+
}
|
|
12505
12653
|
function recomputeLinkCounts(nodes, links) {
|
|
12506
12654
|
const byPath3 = /* @__PURE__ */ new Map();
|
|
12507
12655
|
for (const node of nodes) {
|
|
@@ -13492,6 +13640,7 @@ async function runScanInternal(_kernel, options) {
|
|
|
13492
13640
|
providerFrontmatter: setup.providerFrontmatter,
|
|
13493
13641
|
pluginStores: options.pluginStores
|
|
13494
13642
|
});
|
|
13643
|
+
walked.internalLinks = dedupeLinks(walked.internalLinks);
|
|
13495
13644
|
recomputeLinkCounts(walked.nodes, walked.internalLinks);
|
|
13496
13645
|
recomputeExternalRefsCount(walked.nodes, walked.externalLinks, walked.cachedPaths);
|
|
13497
13646
|
await dispatchExtractorCompleted(exts.extractors, emitter, hookDispatcher);
|
|
@@ -15209,7 +15358,7 @@ var LIST_TEXTS = {
|
|
|
15209
15358
|
tableHeaderIn: "IN",
|
|
15210
15359
|
tableHeaderExt: "EXT",
|
|
15211
15360
|
tableHeaderIssues: "ISSUES",
|
|
15212
|
-
|
|
15361
|
+
tableHeaderTokens: "TOKENS",
|
|
15213
15362
|
/** Footer line: count of rendered nodes (`3 nodes` / `1 node`). */
|
|
15214
15363
|
tableFooterCount: "{{count}} {{noun}}\n",
|
|
15215
15364
|
tableFooterNounSingular: "node",
|
|
@@ -15222,7 +15371,7 @@ var LIST_TEXTS = {
|
|
|
15222
15371
|
var SORT_BY = {
|
|
15223
15372
|
path: { column: "path", direction: "asc" },
|
|
15224
15373
|
kind: { column: "kind", direction: "asc" },
|
|
15225
|
-
|
|
15374
|
+
tokens_total: { column: "tokensTotal", direction: "desc" },
|
|
15226
15375
|
links_out_count: { column: "linksOutCount", direction: "desc" },
|
|
15227
15376
|
links_in_count: { column: "linksInCount", direction: "desc" },
|
|
15228
15377
|
external_refs_count: { column: "externalRefsCount", direction: "desc" }
|
|
@@ -15241,7 +15390,7 @@ var ListCommand = class extends SmCommand {
|
|
|
15241
15390
|
and sidecar.annotations.tags by default; --tag-source author|user
|
|
15242
15391
|
narrows to one side).
|
|
15243
15392
|
|
|
15244
|
-
--sort-by accepts: path, kind,
|
|
15393
|
+
--sort-by accepts: path, kind, tokens_total, links_out_count,
|
|
15245
15394
|
links_in_count, external_refs_count. Default: path. --limit N caps
|
|
15246
15395
|
the result; default is no limit.
|
|
15247
15396
|
|
|
@@ -15250,7 +15399,7 @@ var ListCommand = class extends SmCommand {
|
|
|
15250
15399
|
examples: [
|
|
15251
15400
|
["List every node", "$0 list"],
|
|
15252
15401
|
["List only agents", "$0 list --kind agent"],
|
|
15253
|
-
["Top 5 by total
|
|
15402
|
+
["Top 5 by total tokens", "$0 list --sort-by tokens_total --limit 5"],
|
|
15254
15403
|
["Only nodes with issues, machine-readable", "$0 list --issue --json"],
|
|
15255
15404
|
["Filter by tag (author or user surfaces)", "$0 list --tag urgent"],
|
|
15256
15405
|
["Filter by user-only tag", "$0 list --tag wip --tag-source user"]
|
|
@@ -15393,7 +15542,7 @@ function renderTable2(nodes, issuesByNode, ansi) {
|
|
|
15393
15542
|
in: n.linksInCount,
|
|
15394
15543
|
ext: n.externalRefsCount,
|
|
15395
15544
|
issues: issuesByNode.get(n.path) ?? 0,
|
|
15396
|
-
|
|
15545
|
+
tokens: n.tokens?.total ?? null
|
|
15397
15546
|
}));
|
|
15398
15547
|
const widths = computeWidths(rows);
|
|
15399
15548
|
const lines = [];
|
|
@@ -15421,9 +15570,12 @@ function computeWidths(rows) {
|
|
|
15421
15570
|
in: Math.max(headerLen(LIST_TEXTS.tableHeaderIn), ...rows.map((r) => String(r.in).length)),
|
|
15422
15571
|
ext: Math.max(headerLen(LIST_TEXTS.tableHeaderExt), ...rows.map((r) => String(r.ext).length)),
|
|
15423
15572
|
issues: Math.max(headerLen(LIST_TEXTS.tableHeaderIssues), ...rows.map((r) => String(r.issues).length)),
|
|
15424
|
-
|
|
15573
|
+
tokens: Math.max(headerLen(LIST_TEXTS.tableHeaderTokens), ...rows.map((r) => formatTokens(r.tokens).length))
|
|
15425
15574
|
};
|
|
15426
15575
|
}
|
|
15576
|
+
function formatTokens(value) {
|
|
15577
|
+
return value === null ? "-" : String(value);
|
|
15578
|
+
}
|
|
15427
15579
|
function clampMax(value, max) {
|
|
15428
15580
|
return value > max ? max : value;
|
|
15429
15581
|
}
|
|
@@ -15436,7 +15588,7 @@ function formatHeaderRow(w, ansi) {
|
|
|
15436
15588
|
ansi.dim(LIST_TEXTS.tableHeaderIn.padStart(w.in)),
|
|
15437
15589
|
ansi.dim(LIST_TEXTS.tableHeaderExt.padStart(w.ext)),
|
|
15438
15590
|
ansi.dim(LIST_TEXTS.tableHeaderIssues.padStart(w.issues)),
|
|
15439
|
-
ansi.dim(LIST_TEXTS.
|
|
15591
|
+
ansi.dim(LIST_TEXTS.tableHeaderTokens.padStart(w.tokens))
|
|
15440
15592
|
].join(" ");
|
|
15441
15593
|
}
|
|
15442
15594
|
function formatDataRow(r, w, ansi) {
|
|
@@ -15449,7 +15601,7 @@ function formatDataRow(r, w, ansi) {
|
|
|
15449
15601
|
String(r.in).padStart(w.in),
|
|
15450
15602
|
String(r.ext).padStart(w.ext),
|
|
15451
15603
|
issuesCol,
|
|
15452
|
-
|
|
15604
|
+
formatTokens(r.tokens).padStart(w.tokens)
|
|
15453
15605
|
].join(" ");
|
|
15454
15606
|
}
|
|
15455
15607
|
|
|
@@ -22308,7 +22460,7 @@ var SHOW_TEXTS = {
|
|
|
22308
22460
|
/** Tail appended to `nodeHeader` when provider differs from kind. */
|
|
22309
22461
|
providerSuffix: " {{label}}",
|
|
22310
22462
|
providerSuffixLabel: "provider: {{provider}}",
|
|
22311
|
-
// --- field block (Title / Description /
|
|
22463
|
+
// --- field block (Title / Description / Tokens / …) -----------------
|
|
22312
22464
|
/** Field row, label padded by the renderer to align values. */
|
|
22313
22465
|
fieldRow: " {{label}} {{value}}\n",
|
|
22314
22466
|
/** Continuation indent for multi-line values (description, etc.). */
|
|
@@ -22317,7 +22469,6 @@ var SHOW_TEXTS = {
|
|
|
22317
22469
|
fieldLabelDescription: "Description",
|
|
22318
22470
|
fieldLabelStability: "Stability",
|
|
22319
22471
|
fieldLabelVersion: "Version",
|
|
22320
|
-
fieldLabelBytes: "Bytes",
|
|
22321
22472
|
fieldLabelTokens: "Tokens",
|
|
22322
22473
|
fieldLabelExternalRefs: "External refs",
|
|
22323
22474
|
/** `{{total}} total · {{frontmatter}} frontmatter · {{body}} body`. */
|
|
@@ -22431,23 +22582,13 @@ function collectNodeFields(node) {
|
|
|
22431
22582
|
fields.push({ label: SHOW_TEXTS.fieldLabelVersion, value: sanitizeForTerminal(String(projected.version)) });
|
|
22432
22583
|
}
|
|
22433
22584
|
fields.push({
|
|
22434
|
-
label: SHOW_TEXTS.
|
|
22435
|
-
value: tx(SHOW_TEXTS.weightSplit, {
|
|
22436
|
-
total: node.
|
|
22437
|
-
frontmatter: node.
|
|
22438
|
-
body: node.
|
|
22439
|
-
})
|
|
22585
|
+
label: SHOW_TEXTS.fieldLabelTokens,
|
|
22586
|
+
value: node.tokens ? tx(SHOW_TEXTS.weightSplit, {
|
|
22587
|
+
total: node.tokens.total,
|
|
22588
|
+
frontmatter: node.tokens.frontmatter,
|
|
22589
|
+
body: node.tokens.body
|
|
22590
|
+
}) : "-"
|
|
22440
22591
|
});
|
|
22441
|
-
if (node.tokens) {
|
|
22442
|
-
fields.push({
|
|
22443
|
-
label: SHOW_TEXTS.fieldLabelTokens,
|
|
22444
|
-
value: tx(SHOW_TEXTS.weightSplit, {
|
|
22445
|
-
total: node.tokens.total,
|
|
22446
|
-
frontmatter: node.tokens.frontmatter,
|
|
22447
|
-
body: node.tokens.body
|
|
22448
|
-
})
|
|
22449
|
-
});
|
|
22450
|
-
}
|
|
22451
22592
|
fields.push({ label: SHOW_TEXTS.fieldLabelExternalRefs, value: String(node.externalRefsCount) });
|
|
22452
22593
|
return fields;
|
|
22453
22594
|
}
|
|
@@ -22631,17 +22772,12 @@ var SIDECAR_TEXTS = {
|
|
|
22631
22772
|
annotateCreated: "{{glyph}} Created {{sidecarPath}}. Edit it, then run `sm bump {{nodePath}}` to commit the version.\n",
|
|
22632
22773
|
/** Trailing dim tag for sidecar prune dry-run (matches the orphans pattern). */
|
|
22633
22774
|
sidecarDryRunTag: " (no changes made)",
|
|
22634
|
-
annotateFailed: "{{glyph}} sm sidecar annotate: {{message}}\n"
|
|
22635
|
-
// --- .sm consent gate
|
|
22636
|
-
|
|
22637
|
-
|
|
22638
|
-
|
|
22639
|
-
|
|
22640
|
-
*/
|
|
22641
|
-
consentPrompt: "skill-map needs your consent to create .sm sidecar files next to your\nsource files in this project. The choice is saved to\n.skill-map/settings.local.json (gitignored, per-checkout) so this prompt\nnever appears again. Decline to abort without persisting the rejection.\n\nAllow .sm sidecar writes in this project?",
|
|
22642
|
-
consentAborted: "{{glyph}} sm sidecar: aborted by user. No .sm sidecar files were written.\n",
|
|
22643
|
-
consentRequiredNonTty: "{{glyph}} sm sidecar: consent required to write .sm sidecar files in this project.\n {{hint}}\n",
|
|
22644
|
-
consentRequiredNonTtyHint: "Pass --yes to grant (writes to .skill-map/settings.local.json, gitignored)."
|
|
22775
|
+
annotateFailed: "{{glyph}} sm sidecar annotate: {{message}}\n"
|
|
22776
|
+
// --- .sm consent gate ---------------------------------------------------
|
|
22777
|
+
// The shared strings live in `consent.texts.ts` (CONSENT_TEXTS); they
|
|
22778
|
+
// are used by every verb that writes a sidecar (`sm bump`,
|
|
22779
|
+
// `sm sidecar refresh`, `sm sidecar annotate`) with a `{{verb}}`
|
|
22780
|
+
// placeholder for the directed prefix.
|
|
22645
22781
|
};
|
|
22646
22782
|
|
|
22647
22783
|
// cli/commands/sidecar.ts
|
|
@@ -22654,21 +22790,25 @@ async function runWithSidecarConsent(bag, ansi, dispatch) {
|
|
|
22654
22790
|
if (!isTTY || bag.yes) {
|
|
22655
22791
|
const errGlyph = ansi.red("\u2715");
|
|
22656
22792
|
bag.printError(
|
|
22657
|
-
tx(
|
|
22793
|
+
tx(CONSENT_TEXTS.consentRequiredNonTty, {
|
|
22658
22794
|
glyph: errGlyph,
|
|
22659
|
-
|
|
22795
|
+
verb: "sm sidecar",
|
|
22796
|
+
hint: ansi.dim(CONSENT_TEXTS.consentRequiredNonTtyHint)
|
|
22660
22797
|
})
|
|
22661
22798
|
);
|
|
22662
22799
|
return ExitCode.Error;
|
|
22663
22800
|
}
|
|
22664
22801
|
const ok = await confirm(
|
|
22665
|
-
|
|
22802
|
+
tx(CONSENT_TEXTS.consentPrompt, { glyph: ansi.cyan("\u2139") }),
|
|
22666
22803
|
{ stdin: bag.stdin, stderr: bag.stderr },
|
|
22667
22804
|
{ defaultAnswer: "yes" }
|
|
22668
22805
|
);
|
|
22669
22806
|
if (!ok) {
|
|
22670
22807
|
bag.printInfo(
|
|
22671
|
-
tx(
|
|
22808
|
+
tx(CONSENT_TEXTS.consentAborted, {
|
|
22809
|
+
glyph: ansi.cyan("\u2139"),
|
|
22810
|
+
verb: "sm sidecar"
|
|
22811
|
+
})
|
|
22672
22812
|
);
|
|
22673
22813
|
return ExitCode.Error;
|
|
22674
22814
|
}
|
|
@@ -23291,7 +23431,7 @@ import { Command as Command37, Option as Option35 } from "clipanion";
|
|
|
23291
23431
|
|
|
23292
23432
|
// cli/i18n/tutorial.texts.ts
|
|
23293
23433
|
var TUTORIAL_TEXTS = {
|
|
23294
|
-
// Success, written to stdout after `<cwd>/
|
|
23434
|
+
// Success, written to stdout after `<cwd>/{{filename}}` is created.
|
|
23295
23435
|
// Multi-line layout: the two trigger phrases (English / Spanish) are
|
|
23296
23436
|
// indented and labelled so they're the most visible part of the
|
|
23297
23437
|
// output. The reminder above them surfaces the SKILL's language
|
|
@@ -23303,55 +23443,91 @@ var TUTORIAL_TEXTS = {
|
|
|
23303
23443
|
* `English` / `Español` labels print dim, the eye lands on the
|
|
23304
23444
|
* trigger phrases the user is going to copy / paste.
|
|
23305
23445
|
*/
|
|
23306
|
-
written: " {{glyph}}
|
|
23446
|
+
written: " {{glyph}} {{filename}} created at {{cwd}}\n\n Open Claude Code in this directory. Your first message sets\n the tutorial language for the rest of the session:\n\n {{enLabel}} run @{{filename}}\n {{esLabel}} ejecut\xE1 @{{filename}}\n",
|
|
23307
23447
|
writtenLabelEn: "English",
|
|
23308
23448
|
writtenLabelEs: "Espa\xF1ol",
|
|
23309
|
-
// Refusal, `
|
|
23449
|
+
// Refusal, `{{filename}}` already exists and `--force` was not set.
|
|
23310
23450
|
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
23311
23451
|
// Mirrors the success body shape: glyph + headline, then a dim hint
|
|
23312
23452
|
// line spelling the fix.
|
|
23313
|
-
alreadyExists: "{{glyph}}
|
|
23453
|
+
alreadyExists: "{{glyph}} {{filename}} already exists at {{cwd}}\n {{hint}}\n",
|
|
23314
23454
|
alreadyExistsHint: "Pass `--force` to overwrite.",
|
|
23455
|
+
// Invalid `variant` positional argument. Goes to stderr, exit code 2.
|
|
23456
|
+
// Mirrors `alreadyExists`: glyph + headline + dim hint enumerating the
|
|
23457
|
+
// valid values.
|
|
23458
|
+
invalidVariant: "{{glyph}} sm tutorial: unknown variant '{{variant}}'\n {{hint}}\n",
|
|
23459
|
+
invalidVariantHint: "Valid values: tutorial (default), master.",
|
|
23315
23460
|
// I/O failure on write or on reading the bundled SKILL source.
|
|
23316
|
-
writeFailed: "{{glyph}} sm tutorial: failed to write
|
|
23317
|
-
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled tutorial (
|
|
23461
|
+
writeFailed: "{{glyph}} sm tutorial: failed to write {{filename}}: {{message}}\n",
|
|
23462
|
+
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled tutorial ({{filename}}) from the install.\n {{hint}}\n",
|
|
23318
23463
|
sourceMissingHint: "Reinstall @skill-map/cli or report the bug."
|
|
23319
23464
|
};
|
|
23320
23465
|
|
|
23321
23466
|
// cli/commands/tutorial.ts
|
|
23322
|
-
var
|
|
23467
|
+
var VALID_VARIANTS = ["tutorial", "master"];
|
|
23468
|
+
var DEFAULT_VARIANT = "tutorial";
|
|
23469
|
+
var VARIANT_SPECS = {
|
|
23470
|
+
tutorial: {
|
|
23471
|
+
filename: "sm-tutorial.md",
|
|
23472
|
+
sourcePath: ".claude/skills/sm-tutorial/SKILL.md",
|
|
23473
|
+
bundledName: "sm-tutorial.md"
|
|
23474
|
+
},
|
|
23475
|
+
master: {
|
|
23476
|
+
filename: "sm-master.md",
|
|
23477
|
+
sourcePath: ".claude/skills/sm-master/SKILL.md",
|
|
23478
|
+
bundledName: "sm-master.md"
|
|
23479
|
+
}
|
|
23480
|
+
};
|
|
23323
23481
|
var TutorialCommand = class extends SmCommand {
|
|
23324
23482
|
static paths = [["tutorial"]];
|
|
23325
23483
|
static usage = Command37.Usage({
|
|
23326
23484
|
category: "Setup",
|
|
23327
|
-
description: "Materialize
|
|
23485
|
+
description: "Materialize an interactive tester tutorial (sm-tutorial.md or sm-master.md) in the current directory.",
|
|
23328
23486
|
details: `
|
|
23329
|
-
Drops the canonical SKILL.md content as ./sm-tutorial.md
|
|
23330
|
-
|
|
23331
|
-
|
|
23332
|
-
|
|
23487
|
+
Drops the canonical SKILL.md content as ./sm-tutorial.md (default)
|
|
23488
|
+
or ./sm-master.md (when invoked as \`sm tutorial master\`) so a
|
|
23489
|
+
tester can open Claude Code in the cwd and load the file as a
|
|
23490
|
+
skill by typing "ejecut\xE1 @sm-tutorial.md" (or "@sm-master.md").
|
|
23491
|
+
Top-level only; no subdirectory is created.
|
|
23333
23492
|
|
|
23334
23493
|
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
23335
|
-
overwrite
|
|
23494
|
+
overwrite the target file unless --force is passed. Valid values
|
|
23495
|
+
for the positional argument are: tutorial (default), master.
|
|
23336
23496
|
`,
|
|
23337
23497
|
examples: [
|
|
23338
|
-
["Materialize the tutorial in the cwd", "$0 tutorial"],
|
|
23339
|
-
["
|
|
23498
|
+
["Materialize the basic tutorial in the cwd", "$0 tutorial"],
|
|
23499
|
+
["Materialize the advanced tutorial in the cwd", "$0 tutorial master"],
|
|
23500
|
+
["Overwrite an existing target file", "$0 tutorial --force"]
|
|
23340
23501
|
]
|
|
23341
23502
|
});
|
|
23503
|
+
variant = Option35.String({ required: false });
|
|
23342
23504
|
force = Option35.Boolean("--force", false, {
|
|
23343
|
-
description: "Overwrite an existing
|
|
23505
|
+
description: "Overwrite an existing target file without prompting."
|
|
23344
23506
|
});
|
|
23345
23507
|
async run() {
|
|
23346
23508
|
const ctx = defaultRuntimeContext();
|
|
23347
|
-
const target = join17(ctx.cwd, SM_TUTORIAL_FILENAME);
|
|
23348
23509
|
const stderr = this.context.stderr;
|
|
23349
23510
|
const stderrAnsi = this.ansiFor("stderr");
|
|
23350
23511
|
const errGlyph = stderrAnsi.red("\u2715");
|
|
23512
|
+
const rawVariant = this.variant;
|
|
23513
|
+
if (rawVariant !== void 0 && !isTutorialVariant(rawVariant)) {
|
|
23514
|
+
this.printer.error(
|
|
23515
|
+
tx(TUTORIAL_TEXTS.invalidVariant, {
|
|
23516
|
+
glyph: errGlyph,
|
|
23517
|
+
variant: rawVariant,
|
|
23518
|
+
hint: stderrAnsi.dim(TUTORIAL_TEXTS.invalidVariantHint)
|
|
23519
|
+
})
|
|
23520
|
+
);
|
|
23521
|
+
return ExitCode.Error;
|
|
23522
|
+
}
|
|
23523
|
+
const variant = rawVariant ?? DEFAULT_VARIANT;
|
|
23524
|
+
const spec = VARIANT_SPECS[variant];
|
|
23525
|
+
const target = join17(ctx.cwd, spec.filename);
|
|
23351
23526
|
if (await pathExists(target) && !this.force) {
|
|
23352
23527
|
this.printer.error(
|
|
23353
23528
|
tx(TUTORIAL_TEXTS.alreadyExists, {
|
|
23354
23529
|
glyph: errGlyph,
|
|
23530
|
+
filename: spec.filename,
|
|
23355
23531
|
cwd: stderrAnsi.dim(displayCwd(ctx.cwd)),
|
|
23356
23532
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.alreadyExistsHint)
|
|
23357
23533
|
})
|
|
@@ -23360,11 +23536,12 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23360
23536
|
}
|
|
23361
23537
|
let body;
|
|
23362
23538
|
try {
|
|
23363
|
-
body = loadBundledTutorialText();
|
|
23539
|
+
body = loadBundledTutorialText(variant);
|
|
23364
23540
|
} catch {
|
|
23365
23541
|
this.printer.error(
|
|
23366
23542
|
tx(TUTORIAL_TEXTS.sourceMissing, {
|
|
23367
23543
|
glyph: errGlyph,
|
|
23544
|
+
filename: spec.filename,
|
|
23368
23545
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.sourceMissingHint)
|
|
23369
23546
|
})
|
|
23370
23547
|
);
|
|
@@ -23376,6 +23553,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23376
23553
|
this.printer.error(
|
|
23377
23554
|
tx(TUTORIAL_TEXTS.writeFailed, {
|
|
23378
23555
|
glyph: errGlyph,
|
|
23556
|
+
filename: spec.filename,
|
|
23379
23557
|
message: formatErrorMessage(err)
|
|
23380
23558
|
})
|
|
23381
23559
|
);
|
|
@@ -23391,6 +23569,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23391
23569
|
this.printer.data(
|
|
23392
23570
|
tx(TUTORIAL_TEXTS.written, {
|
|
23393
23571
|
glyph: ansi.green("\u2713"),
|
|
23572
|
+
filename: spec.filename,
|
|
23394
23573
|
cwd: ansi.dim(displayCwd(ctx.cwd)),
|
|
23395
23574
|
enLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEn),
|
|
23396
23575
|
esLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEs)
|
|
@@ -23399,26 +23578,32 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23399
23578
|
return ExitCode.Ok;
|
|
23400
23579
|
}
|
|
23401
23580
|
};
|
|
23581
|
+
function isTutorialVariant(value) {
|
|
23582
|
+
return VALID_VARIANTS.includes(value);
|
|
23583
|
+
}
|
|
23402
23584
|
function displayCwd(cwd) {
|
|
23403
23585
|
const segments = cwd.split("/").filter((s) => s.length > 0);
|
|
23404
23586
|
if (segments.length === 0) return "./";
|
|
23405
23587
|
return `./${segments[segments.length - 1]}/`;
|
|
23406
23588
|
}
|
|
23407
|
-
var
|
|
23408
|
-
function loadBundledTutorialText() {
|
|
23409
|
-
|
|
23410
|
-
|
|
23411
|
-
|
|
23589
|
+
var cachedTutorials = /* @__PURE__ */ new Map();
|
|
23590
|
+
function loadBundledTutorialText(variant) {
|
|
23591
|
+
const cached = cachedTutorials.get(variant);
|
|
23592
|
+
if (cached !== void 0) return cached;
|
|
23593
|
+
const body = readTutorialFromDisk(variant);
|
|
23594
|
+
cachedTutorials.set(variant, body);
|
|
23595
|
+
return body;
|
|
23412
23596
|
}
|
|
23413
|
-
function readTutorialFromDisk() {
|
|
23597
|
+
function readTutorialFromDisk(variant) {
|
|
23598
|
+
const spec = VARIANT_SPECS[variant];
|
|
23414
23599
|
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
23415
23600
|
const candidates = [
|
|
23416
|
-
// dev: src/cli/commands/ → repo-root .claude/skills
|
|
23417
|
-
resolve36(here, "
|
|
23418
|
-
// bundled: dist/cli.js → dist/cli/tutorial
|
|
23419
|
-
resolve36(here, "cli/tutorial
|
|
23420
|
-
// bundled fallback: any-depth → cli/tutorial
|
|
23421
|
-
resolve36(here, "../cli/tutorial
|
|
23601
|
+
// dev: src/cli/commands/ → repo-root .claude/skills/<slug>/SKILL.md
|
|
23602
|
+
resolve36(here, "../../..", spec.sourcePath),
|
|
23603
|
+
// bundled: dist/cli.js → dist/cli/tutorial/<filename> (sibling)
|
|
23604
|
+
resolve36(here, "cli/tutorial", spec.bundledName),
|
|
23605
|
+
// bundled fallback: any-depth → cli/tutorial/<filename>
|
|
23606
|
+
resolve36(here, "../cli/tutorial", spec.bundledName)
|
|
23422
23607
|
];
|
|
23423
23608
|
for (const candidate of candidates) {
|
|
23424
23609
|
if (existsSync28(candidate)) {
|