@skill-map/cli 0.25.0 → 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 +60 -19
- package/dist/cli/tutorial/sm-tutorial.md +152 -97
- package/dist/cli.js +194 -46
- 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-N5FAET6D.js → chunk-Q64EKSUB.js} +1 -1
- 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-QPX4WBVF.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) {
|
|
@@ -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);
|
|
@@ -22623,17 +22772,12 @@ var SIDECAR_TEXTS = {
|
|
|
22623
22772
|
annotateCreated: "{{glyph}} Created {{sidecarPath}}. Edit it, then run `sm bump {{nodePath}}` to commit the version.\n",
|
|
22624
22773
|
/** Trailing dim tag for sidecar prune dry-run (matches the orphans pattern). */
|
|
22625
22774
|
sidecarDryRunTag: " (no changes made)",
|
|
22626
|
-
annotateFailed: "{{glyph}} sm sidecar annotate: {{message}}\n"
|
|
22627
|
-
// --- .sm consent gate
|
|
22628
|
-
|
|
22629
|
-
|
|
22630
|
-
|
|
22631
|
-
|
|
22632
|
-
*/
|
|
22633
|
-
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?",
|
|
22634
|
-
consentAborted: "{{glyph}} sm sidecar: aborted by user. No .sm sidecar files were written.\n",
|
|
22635
|
-
consentRequiredNonTty: "{{glyph}} sm sidecar: consent required to write .sm sidecar files in this project.\n {{hint}}\n",
|
|
22636
|
-
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.
|
|
22637
22781
|
};
|
|
22638
22782
|
|
|
22639
22783
|
// cli/commands/sidecar.ts
|
|
@@ -22646,21 +22790,25 @@ async function runWithSidecarConsent(bag, ansi, dispatch) {
|
|
|
22646
22790
|
if (!isTTY || bag.yes) {
|
|
22647
22791
|
const errGlyph = ansi.red("\u2715");
|
|
22648
22792
|
bag.printError(
|
|
22649
|
-
tx(
|
|
22793
|
+
tx(CONSENT_TEXTS.consentRequiredNonTty, {
|
|
22650
22794
|
glyph: errGlyph,
|
|
22651
|
-
|
|
22795
|
+
verb: "sm sidecar",
|
|
22796
|
+
hint: ansi.dim(CONSENT_TEXTS.consentRequiredNonTtyHint)
|
|
22652
22797
|
})
|
|
22653
22798
|
);
|
|
22654
22799
|
return ExitCode.Error;
|
|
22655
22800
|
}
|
|
22656
22801
|
const ok = await confirm(
|
|
22657
|
-
|
|
22802
|
+
tx(CONSENT_TEXTS.consentPrompt, { glyph: ansi.cyan("\u2139") }),
|
|
22658
22803
|
{ stdin: bag.stdin, stderr: bag.stderr },
|
|
22659
22804
|
{ defaultAnswer: "yes" }
|
|
22660
22805
|
);
|
|
22661
22806
|
if (!ok) {
|
|
22662
22807
|
bag.printInfo(
|
|
22663
|
-
tx(
|
|
22808
|
+
tx(CONSENT_TEXTS.consentAborted, {
|
|
22809
|
+
glyph: ansi.cyan("\u2139"),
|
|
22810
|
+
verb: "sm sidecar"
|
|
22811
|
+
})
|
|
22664
22812
|
);
|
|
22665
22813
|
return ExitCode.Error;
|
|
22666
22814
|
}
|