@skill-map/cli 0.68.1 → 0.70.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-tutorial/SKILL.md +8 -3
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/agents-hub/providers/codex/en/agents-hub.md +2 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/agents-hub/providers/codex/es/agents-hub.md +2 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/en/todo-bullet-agent.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/en/todo-bullet-command.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/en/todo-bullet-skill.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/es/todo-bullet-agent.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/es/todo-bullet-command.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/codex/es/todo-bullet-skill.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/codex/en/__PROVIDER__/skills/publish/SKILL.md +2 -2
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/codex/es/__PROVIDER__/skills/publish/SKILL.md +2 -2
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/codex/en/.codex/agents/master-agent.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/codex/es/.codex/agents/master-agent.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/codex/en/.codex/agents/content-editor.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/codex/es/.codex/agents/content-editor.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/en/.codex/agents/demo-agent.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/es/.codex/agents/demo-agent.toml +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/_core.md +57 -29
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.json +70 -70
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +38 -38
- package/dist/cli/tutorial/sm-tutorial/references/fixtures.md +3 -3
- package/dist/cli/tutorial/sm-tutorial/references/part-authoring.md +25 -8
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-daily.md +91 -38
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-fundamentals.md +7 -8
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-kickoff.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-cli.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-daily-loop.md +173 -56
- package/dist/cli/tutorial/sm-tutorial/references/part-fundamentals.md +14 -13
- package/dist/cli/tutorial/sm-tutorial/references/part-plugins.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +14 -12
- package/dist/cli/tutorial/sm-tutorial/references/part-settings.md +2 -2
- package/dist/cli/tutorial/sm-tutorial/scripts/lib/paths.js +6 -5
- package/dist/cli.js +963 -451
- package/dist/conformance/index.js +3 -3
- package/dist/index.js +17 -14
- package/dist/kernel/index.d.ts +54 -17
- package/dist/kernel/index.js +17 -14
- package/dist/migrations/001_initial.sql +7 -3
- package/dist/ui/{chunk-22EQLC23.js → chunk-EVNCL7FV.js} +21 -21
- package/dist/ui/chunk-GUGB4JY5.js +1 -0
- package/dist/ui/chunk-RJUHQQOF.js +3 -0
- package/dist/ui/{chunk-KMHXNOFZ.js → chunk-RSPEJBPT.js} +1 -1
- package/dist/ui/chunk-SQCXHF3J.js +2 -0
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-K4O6LCIJ.js +4 -0
- package/migrations/001_initial.sql +7 -3
- package/package.json +2 -2
- package/dist/ui/chunk-K3ZRQNN5.js +0 -2
- package/dist/ui/chunk-PU5OP5RN.js +0 -1
- package/dist/ui/chunk-TLMV4LOQ.js +0 -3
- package/dist/ui/main-R7BIU4HU.js +0 -4
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// cli/entry.ts
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ca8113af-a7ac-5cd7-b45c-03a5974bca86")}catch(e){}}();
|
|
4
4
|
import { existsSync as existsSync34 } from "fs";
|
|
5
5
|
import { Builtins, Cli as Cli2 } from "clipanion";
|
|
6
6
|
|
|
@@ -250,7 +250,7 @@ function bucketByKind(kind, instance, bag) {
|
|
|
250
250
|
// package.json
|
|
251
251
|
var package_default = {
|
|
252
252
|
name: "@skill-map/cli",
|
|
253
|
-
version: "0.
|
|
253
|
+
version: "0.70.0",
|
|
254
254
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
255
255
|
license: "MIT",
|
|
256
256
|
type: "module",
|
|
@@ -633,7 +633,10 @@ var claudeProvider = {
|
|
|
633
633
|
presentation: {
|
|
634
634
|
label: "Anthropic's Claude",
|
|
635
635
|
color: "#cc785c",
|
|
636
|
-
colorDark: "#e89270"
|
|
636
|
+
colorDark: "#e89270",
|
|
637
|
+
// Claude Code invokes both commands and skills with `/`; the palette
|
|
638
|
+
// paints this as the `invokes` edge glyph under the claude lens.
|
|
639
|
+
invocationSigil: "/"
|
|
637
640
|
},
|
|
638
641
|
// Auto-detect marker: a `.claude/` directory under the scope root marks
|
|
639
642
|
// a Claude Code project. Provider-owned (replaces the old central
|
|
@@ -913,13 +916,11 @@ var atDirectiveExtractor = {
|
|
|
913
916
|
kind: "extractor",
|
|
914
917
|
description: "Detects `@<token>` directives in a node's body using Claude Code rules, choosing the link kind by token shape. Example: a bare handle `@team` becomes a `mentions` link, while a file-flavoured token `@docs/api.md` becomes a `references` link.",
|
|
915
918
|
scope: "body",
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
//
|
|
919
|
-
//
|
|
920
|
-
|
|
921
|
-
// the project's markdown surface just as it does under `claude`.
|
|
922
|
-
precondition: { provider: ["claude", "codex"] },
|
|
919
|
+
// Claude-only. This is Claude's `@<name>` grammar, where a bare handle is
|
|
920
|
+
// an agent / entity MENTION. OpenAI Codex's `@` is a file-path picker, not
|
|
921
|
+
// a mention grammar, so codex is NOT gated here; the codex-owned `at-file`
|
|
922
|
+
// extractor covers `@`-as-file-reference under the codex lens.
|
|
923
|
+
precondition: { provider: ["claude"] },
|
|
923
924
|
// eslint-disable-next-line complexity
|
|
924
925
|
extract(ctx) {
|
|
925
926
|
const seenMentions = /* @__PURE__ */ new Set();
|
|
@@ -1007,16 +1008,15 @@ var slashCommandExtractor = {
|
|
|
1007
1008
|
kind: "extractor",
|
|
1008
1009
|
description: "Turns `/command` invocations in a node's body into arrows that point at the resolved slash command or skill, using Claude Code routing rules. Example: `/deploy` in the body draws an arrow to the `deploy` command.",
|
|
1009
1010
|
scope: "body",
|
|
1010
|
-
// Also authorised under the
|
|
1011
|
-
//
|
|
1012
|
-
//
|
|
1013
|
-
//
|
|
1014
|
-
//
|
|
1015
|
-
//
|
|
1016
|
-
//
|
|
1017
|
-
//
|
|
1018
|
-
|
|
1019
|
-
precondition: { provider: ["claude", "codex", "antigravity"] },
|
|
1011
|
+
// Also authorised under the antigravity lens, which shares the `/command`
|
|
1012
|
+
// grammar: a workflow / skill / AGENTS.md body's `/name` tokens resolve to
|
|
1013
|
+
// BOTH skills and workflows (`invokes: ['skill', 'workflow']`), since
|
|
1014
|
+
// Antigravity invokes either by the same slash. NOT gated under codex:
|
|
1015
|
+
// OpenAI Codex reserves `/` for its OWN built-in commands (`/model`,
|
|
1016
|
+
// `/init`, ...) and invokes user skills with `$` instead (parsed by the
|
|
1017
|
+
// codex `dollar-skill` extractor). A lens that declares no `invokes`
|
|
1018
|
+
// resolution leaves the signals unresolved (no spurious edges).
|
|
1019
|
+
precondition: { provider: ["claude", "antigravity"] },
|
|
1020
1020
|
extract(ctx) {
|
|
1021
1021
|
const seen = /* @__PURE__ */ new Set();
|
|
1022
1022
|
const body = stripCodeAndHtml(ctx.body);
|
|
@@ -1241,26 +1241,32 @@ var agentSkillsProvider = {
|
|
|
1241
1241
|
stability: "stable",
|
|
1242
1242
|
// Auto-detect marker: a `.agents/` directory marks an open-standard
|
|
1243
1243
|
// project. This is also the marker a Google/Antigravity project carries
|
|
1244
|
-
// (Antigravity adopted the open standard)
|
|
1245
|
-
//
|
|
1246
|
-
//
|
|
1247
|
-
|
|
1244
|
+
// (Antigravity adopted the open standard) and the shared skill home a
|
|
1245
|
+
// Codex project populates under `.agents/skills/`. `fallback: true` makes
|
|
1246
|
+
// this candidate yield to any vendor marker present alongside `.agents/`:
|
|
1247
|
+
// a `.codex/` + `.agents/` project resolves `codex` outright, never an
|
|
1248
|
+
// ambiguous `codex` vs `agent-skills` prompt. The `.agents/` marker only
|
|
1249
|
+
// wins when no vendor marker is present. Provider-owned.
|
|
1250
|
+
detect: { markers: [".agents"], fallback: true },
|
|
1248
1251
|
// Authoring target for `sm tutorial`: the open standard discovers skills
|
|
1249
1252
|
// under `.agents/skills/<name>/SKILL.md`. `aka` lists Antigravity, which
|
|
1250
1253
|
// shares this territory AND the BASIC tutorial track (skill + markdown,
|
|
1251
1254
|
// references), so a tester on Antigravity scaffolds here. OpenAI Codex
|
|
1252
1255
|
// also reads `.agents/skills/`, but Codex is a RICH-track lens (it has the
|
|
1253
|
-
// `agent` kind,
|
|
1256
|
+
// `agent` kind, plus `$`-skill invocation and `@`-file references), so
|
|
1257
|
+
// advertising it under this basic row
|
|
1254
1258
|
// would hand it the wrong book; Codex is surfaced once a Codex rich
|
|
1255
1259
|
// scaffold target lands. `aka` is display-only, `--for` matches the id.
|
|
1256
1260
|
scaffold: { skillDir: ".agents/skills", aka: ["Google's Antigravity"] },
|
|
1257
1261
|
read: COMMONS_READ,
|
|
1258
1262
|
kinds: COMMONS_KINDS,
|
|
1259
1263
|
resolution: COMMONS_RESOLUTION,
|
|
1260
|
-
//
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
|
|
1264
|
+
// NO `reservedNames`: the neutral open standard has no `/`-invocation, a
|
|
1265
|
+
// skill activates by its `description` and connects via markdown links, so
|
|
1266
|
+
// a skill name cannot shadow a built-in `/` command. The shared
|
|
1267
|
+
// `COMMONS_RESERVED_NAMES` export above is for `/`-invoking vendors
|
|
1268
|
+
// (Antigravity) to spread, NOT applied here. See spec/architecture.md
|
|
1269
|
+
// §Provider · reservedNames.
|
|
1264
1270
|
classify: classifyCommonsPath
|
|
1265
1271
|
};
|
|
1266
1272
|
|
|
@@ -1308,7 +1314,10 @@ var antigravityProvider = {
|
|
|
1308
1314
|
presentation: {
|
|
1309
1315
|
label: "Google's Antigravity",
|
|
1310
1316
|
color: "#7c3aed",
|
|
1311
|
-
colorDark: "#a78bfa"
|
|
1317
|
+
colorDark: "#a78bfa",
|
|
1318
|
+
// Antigravity bolts `/`-invocation onto the open standard (skills and
|
|
1319
|
+
// workflows are `/<name>`), so the `invokes` edge glyph is the slash.
|
|
1320
|
+
invocationSigil: "/"
|
|
1312
1321
|
},
|
|
1313
1322
|
// Auto-detect marker: Antigravity's workflows live under `.agent/workflows/`
|
|
1314
1323
|
// (SINGULAR `.agent`), its one vendor-specific on-disk territory. Skills
|
|
@@ -1461,7 +1470,11 @@ var codexProvider = {
|
|
|
1461
1470
|
presentation: {
|
|
1462
1471
|
label: "OpenAI's Codex",
|
|
1463
1472
|
color: "#22c55e",
|
|
1464
|
-
colorDark: "#4ade80"
|
|
1473
|
+
colorDark: "#4ade80",
|
|
1474
|
+
// Codex invokes skills with `$` (`$publish`); `/` is reserved for its
|
|
1475
|
+
// own built-in commands (`/model`, `/init`), so the `invokes` edge glyph
|
|
1476
|
+
// under the codex lens is the dollar, not the slash.
|
|
1477
|
+
invocationSigil: "$"
|
|
1465
1478
|
},
|
|
1466
1479
|
// Auto-detect marker: a `.codex/` directory marks a Codex CLI project.
|
|
1467
1480
|
// `AGENTS.md` is intentionally NOT a marker: it is the open agents.md
|
|
@@ -1527,19 +1540,21 @@ var codexProvider = {
|
|
|
1527
1540
|
// `frontmatter.name`.
|
|
1528
1541
|
...COMMONS_KINDS
|
|
1529
1542
|
},
|
|
1530
|
-
//
|
|
1531
|
-
//
|
|
1532
|
-
//
|
|
1533
|
-
//
|
|
1543
|
+
// Skill invocations resolve to skills (`invokes: ['skill']`, inherited
|
|
1544
|
+
// from the open standard): a `$skill-name` in an agent's prompt (parsed by
|
|
1545
|
+
// the codex `dollar-skill` extractor) links to its `.agents/skills/` skill.
|
|
1546
|
+
// NO `mentions` entry: Codex's `@` is a file picker, parsed by the
|
|
1547
|
+
// codex-owned `at-file` extractor as a path-resolved `references` link, not
|
|
1548
|
+
// an agent-mention grammar.
|
|
1534
1549
|
resolution: {
|
|
1535
|
-
mentions: ["agent"],
|
|
1536
1550
|
...COMMONS_RESOLUTION
|
|
1537
1551
|
},
|
|
1538
|
-
//
|
|
1539
|
-
//
|
|
1540
|
-
//
|
|
1541
|
-
//
|
|
1542
|
-
|
|
1552
|
+
// NO `reservedNames`: Codex invokes skills via `$` (the `dollar-skill`
|
|
1553
|
+
// extractor), a namespace disjoint from its built-in `/` commands, so a
|
|
1554
|
+
// `$`-skill named `model` does NOT collide with `/model`. Reserved-skill
|
|
1555
|
+
// names only apply to lenses that invoke skills through the `/` command
|
|
1556
|
+
// channel (claude, antigravity). See spec/architecture.md §Provider ·
|
|
1557
|
+
// reservedNames.
|
|
1543
1558
|
classify(path) {
|
|
1544
1559
|
const lower = path.toLowerCase();
|
|
1545
1560
|
if (lower.startsWith(".codex/agents/") && lower.endsWith(".toml")) return "agent";
|
|
@@ -1547,6 +1562,123 @@ var codexProvider = {
|
|
|
1547
1562
|
}
|
|
1548
1563
|
};
|
|
1549
1564
|
|
|
1565
|
+
// plugins/codex/extractors/at-file/index.ts
|
|
1566
|
+
import { posix as pathPosix2 } from "path";
|
|
1567
|
+
var ID4 = "at-file";
|
|
1568
|
+
var AT_RE2 = /(?:^|[^A-Za-z0-9_@])(@(?:\.{1,2}\/|\/)?[a-z0-9](?:[a-z0-9_\-./]*[a-z0-9_])?(?::[a-z0-9][a-z0-9_-]*)?)/gi;
|
|
1569
|
+
var FILE_EXT_RE2 = /\.(md|mdx|js|jsx|ts|tsx|json|yml|yaml|toml|txt|html|css|scss|less|py|rb|go|rs|java|c|cpp|h|hpp|sh|sql|svg|png|jpg|jpeg|gif|webp|pdf)$/i;
|
|
1570
|
+
var atFileExtractor = {
|
|
1571
|
+
id: ID4,
|
|
1572
|
+
pluginId: OPENAI_PLUGIN_ID,
|
|
1573
|
+
kind: "extractor",
|
|
1574
|
+
description: "Detects `@<file>` references in a node's body under the OpenAI Codex lens, where `@` is a file picker. A path- or extension-shaped token becomes a `references` link to that file; a bare `@handle` forms no edge. Example: `@builder.toml` in an agent's prompt draws an arrow to the `builder` agent file.",
|
|
1575
|
+
scope: "body",
|
|
1576
|
+
// Codex-only: under the codex lens `@` is a file-path picker, so only
|
|
1577
|
+
// file-shaped tokens form references. The claude `at-directive` (bare
|
|
1578
|
+
// `@handle` → agent mention) is NOT gated under codex.
|
|
1579
|
+
precondition: { provider: ["codex"] },
|
|
1580
|
+
extract(ctx) {
|
|
1581
|
+
const seenReferences = /* @__PURE__ */ new Set();
|
|
1582
|
+
const body = stripCodeAndHtml(ctx.body);
|
|
1583
|
+
const lineStarts = computeLineStarts(body);
|
|
1584
|
+
const sourceDir = pathPosix2.dirname(ctx.node.path);
|
|
1585
|
+
for (const match of body.matchAll(AT_RE2)) {
|
|
1586
|
+
const original = match[1];
|
|
1587
|
+
const bare = original.slice(1);
|
|
1588
|
+
const rationale = classifyAtToken(bare);
|
|
1589
|
+
if (rationale === null) continue;
|
|
1590
|
+
const target = resolveSourceRelative2(sourceDir, bare);
|
|
1591
|
+
const dedupKey = target.toLowerCase();
|
|
1592
|
+
if (seenReferences.has(dedupKey)) continue;
|
|
1593
|
+
seenReferences.add(dedupKey);
|
|
1594
|
+
const captureOffset = (match.index ?? 0) + match[0].indexOf(original);
|
|
1595
|
+
const line = lineFor(lineStarts, captureOffset);
|
|
1596
|
+
ctx.emitSignal({
|
|
1597
|
+
source: ctx.node.path,
|
|
1598
|
+
scope: "body",
|
|
1599
|
+
range: { start: captureOffset, end: captureOffset + original.length, line },
|
|
1600
|
+
raw: original,
|
|
1601
|
+
candidates: [
|
|
1602
|
+
{
|
|
1603
|
+
extractorId: ID4,
|
|
1604
|
+
kind: "references",
|
|
1605
|
+
target,
|
|
1606
|
+
// 0.85: strong file signal (path prefix or known extension),
|
|
1607
|
+
// one degree of inference (the runtime resolves the path).
|
|
1608
|
+
confidence: 0.85,
|
|
1609
|
+
rationale,
|
|
1610
|
+
trigger: {
|
|
1611
|
+
originalTrigger: original,
|
|
1612
|
+
normalizedTrigger: target
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
]
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
function classifyAtToken(bare) {
|
|
1621
|
+
if (bare.startsWith("/")) return null;
|
|
1622
|
+
if (bare.startsWith("./") || bare.startsWith("../")) return "relative path prefix";
|
|
1623
|
+
if (FILE_EXT_RE2.test(bare)) return "known file extension";
|
|
1624
|
+
return null;
|
|
1625
|
+
}
|
|
1626
|
+
function resolveSourceRelative2(sourceDir, bare) {
|
|
1627
|
+
const joined = sourceDir === "." ? bare : `${sourceDir}/${bare}`;
|
|
1628
|
+
return pathPosix2.normalize(joined);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// plugins/codex/extractors/dollar-skill/index.ts
|
|
1632
|
+
var ID5 = "dollar-skill";
|
|
1633
|
+
var DOLLAR_RE = /(?<![A-Za-z0-9_$])(\$[a-z][a-z0-9_-]*)/g;
|
|
1634
|
+
var dollarSkillExtractor = {
|
|
1635
|
+
id: ID5,
|
|
1636
|
+
pluginId: OPENAI_PLUGIN_ID,
|
|
1637
|
+
kind: "extractor",
|
|
1638
|
+
description: "Turns `$skill` invocations in a node's body into arrows that point at the resolved Codex skill, using OpenAI Codex routing rules. Example: `$check-links` in the body draws an arrow to the `check-links` skill.",
|
|
1639
|
+
scope: "body",
|
|
1640
|
+
// Codex-only: `$skill` is OpenAI Codex's explicit skill-invocation
|
|
1641
|
+
// grammar. The codex provider resolves it to its open-standard skills
|
|
1642
|
+
// (`invokes: ['skill']`). Other lenses do not parse `$`.
|
|
1643
|
+
precondition: { provider: ["codex"] },
|
|
1644
|
+
extract(ctx) {
|
|
1645
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1646
|
+
const body = stripCodeAndHtml(ctx.body);
|
|
1647
|
+
const lineStarts = computeLineStarts(body);
|
|
1648
|
+
for (const match of body.matchAll(DOLLAR_RE)) {
|
|
1649
|
+
const original = match[1];
|
|
1650
|
+
const normalized = normalizeTrigger(original);
|
|
1651
|
+
if (seen.has(normalized)) continue;
|
|
1652
|
+
seen.add(normalized);
|
|
1653
|
+
const captureOffset = (match.index ?? 0) + match[0].indexOf(original);
|
|
1654
|
+
const line = lineFor(lineStarts, captureOffset);
|
|
1655
|
+
ctx.emitSignal({
|
|
1656
|
+
source: ctx.node.path,
|
|
1657
|
+
scope: "body",
|
|
1658
|
+
range: { start: captureOffset, end: captureOffset + original.length, line },
|
|
1659
|
+
raw: original,
|
|
1660
|
+
candidates: [
|
|
1661
|
+
{
|
|
1662
|
+
extractorId: ID5,
|
|
1663
|
+
kind: "invokes",
|
|
1664
|
+
target: original,
|
|
1665
|
+
// 0.8: clean `$skill` match after code-block strip. The
|
|
1666
|
+
// lowercase-letter guard filters currency / env-var noise, so a
|
|
1667
|
+
// hit is unambiguous syntax. Resolution against the live skill
|
|
1668
|
+
// catalog happens downstream.
|
|
1669
|
+
confidence: 0.8,
|
|
1670
|
+
rationale: "unambiguous $skill syntax post code-block strip",
|
|
1671
|
+
trigger: {
|
|
1672
|
+
originalTrigger: original,
|
|
1673
|
+
normalizedTrigger: normalized
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
]
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
|
|
1550
1682
|
// plugins/core/providers/core-markdown/schemas/markdown.schema.json
|
|
1551
1683
|
var markdown_schema_default = {
|
|
1552
1684
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1634,11 +1766,11 @@ var coreMarkdownProvider = {
|
|
|
1634
1766
|
};
|
|
1635
1767
|
|
|
1636
1768
|
// plugins/core/extractors/backtick-path/index.ts
|
|
1637
|
-
import { posix as
|
|
1638
|
-
var
|
|
1769
|
+
import { posix as pathPosix3 } from "path";
|
|
1770
|
+
var ID6 = "backtick-path";
|
|
1639
1771
|
var PATH_RE = /(?<![\w/:.-])(?:\.{1,2}\/)?[\w][\w.-]*(?:\/[\w.-]+)*\.md\b(?![\w/])/g;
|
|
1640
1772
|
var backtickPathExtractor = {
|
|
1641
|
-
id:
|
|
1773
|
+
id: ID6,
|
|
1642
1774
|
pluginId: CORE_PLUGIN_ID,
|
|
1643
1775
|
kind: "extractor",
|
|
1644
1776
|
description: "Turns relative .md paths written inside code spans and fenced blocks into arrows between nodes in the graph. Example: a backticked `references/rules.md` path draws an arrow to that file.",
|
|
@@ -1647,7 +1779,7 @@ var backtickPathExtractor = {
|
|
|
1647
1779
|
const seen = /* @__PURE__ */ new Set();
|
|
1648
1780
|
const body = extractCodeRegions(ctx.body);
|
|
1649
1781
|
const lineStarts = computeLineStarts(body);
|
|
1650
|
-
const sourceDir =
|
|
1782
|
+
const sourceDir = pathPosix3.dirname(ctx.node.path);
|
|
1651
1783
|
for (const match of body.matchAll(PATH_RE)) {
|
|
1652
1784
|
const original = match[0];
|
|
1653
1785
|
const resolved = resolveTarget(sourceDir, original);
|
|
@@ -1663,7 +1795,7 @@ var backtickPathExtractor = {
|
|
|
1663
1795
|
raw: original,
|
|
1664
1796
|
candidates: [
|
|
1665
1797
|
{
|
|
1666
|
-
extractorId:
|
|
1798
|
+
extractorId: ID6,
|
|
1667
1799
|
kind: "points",
|
|
1668
1800
|
target: resolved,
|
|
1669
1801
|
// 0.85: a strong file signal with one degree of inference,
|
|
@@ -1688,11 +1820,11 @@ function resolveTarget(sourceDir, raw) {
|
|
|
1688
1820
|
if (trimmed.length === 0) return null;
|
|
1689
1821
|
if (trimmed.startsWith("/")) return null;
|
|
1690
1822
|
const joined = sourceDir === "." ? trimmed : `${sourceDir}/${trimmed}`;
|
|
1691
|
-
return
|
|
1823
|
+
return pathPosix3.normalize(joined);
|
|
1692
1824
|
}
|
|
1693
1825
|
|
|
1694
1826
|
// plugins/core/extractors/external-url-counter/index.ts
|
|
1695
|
-
var
|
|
1827
|
+
var ID7 = "external-url-counter";
|
|
1696
1828
|
var count2 = {
|
|
1697
1829
|
slot: "card.footer.left",
|
|
1698
1830
|
icon: "pi-link",
|
|
@@ -1712,7 +1844,7 @@ var settings = {
|
|
|
1712
1844
|
var URL_RE = /https?:\/\/[^\s<>"'`)\]]+/g;
|
|
1713
1845
|
var TRAILING_PUNCT = /[.,;:!?]+$/;
|
|
1714
1846
|
var externalUrlCounterExtractor = {
|
|
1715
|
-
id:
|
|
1847
|
+
id: ID7,
|
|
1716
1848
|
pluginId: CORE_PLUGIN_ID,
|
|
1717
1849
|
kind: "extractor",
|
|
1718
1850
|
description: "Counts the distinct external URLs in a node's body and shows the count on the card. Example: a body linking `https://example.com` and `https://docs.rs` shows a count of 2.",
|
|
@@ -1764,7 +1896,7 @@ var externalUrlCounterExtractor = {
|
|
|
1764
1896
|
raw: original,
|
|
1765
1897
|
candidates: [
|
|
1766
1898
|
{
|
|
1767
|
-
extractorId:
|
|
1899
|
+
extractorId: ID7,
|
|
1768
1900
|
kind: "references",
|
|
1769
1901
|
target: normalized.href,
|
|
1770
1902
|
confidence: 0.3,
|
|
@@ -1805,12 +1937,12 @@ function normalizeUrl(raw) {
|
|
|
1805
1937
|
}
|
|
1806
1938
|
|
|
1807
1939
|
// plugins/core/extractors/markdown-link/index.ts
|
|
1808
|
-
import { posix as
|
|
1809
|
-
var
|
|
1940
|
+
import { posix as pathPosix4 } from "path";
|
|
1941
|
+
var ID8 = "markdown-link";
|
|
1810
1942
|
var LINK_RE = /(?<!!)\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
|
|
1811
1943
|
var URL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
1812
1944
|
var markdownLinkExtractor = {
|
|
1813
|
-
id:
|
|
1945
|
+
id: ID8,
|
|
1814
1946
|
pluginId: CORE_PLUGIN_ID,
|
|
1815
1947
|
kind: "extractor",
|
|
1816
1948
|
description: "Turns markdown links (`[text](path)`) in a node's body into arrows between nodes in the graph. Example: `[the guide](docs/guide.md)` draws an arrow to `docs/guide.md`.",
|
|
@@ -1819,7 +1951,7 @@ var markdownLinkExtractor = {
|
|
|
1819
1951
|
const seen = /* @__PURE__ */ new Set();
|
|
1820
1952
|
const body = stripCodeAndHtml(ctx.body);
|
|
1821
1953
|
const lineStarts = computeLineStarts(body);
|
|
1822
|
-
const sourceDir =
|
|
1954
|
+
const sourceDir = pathPosix4.dirname(ctx.node.path);
|
|
1823
1955
|
for (const match of body.matchAll(LINK_RE)) {
|
|
1824
1956
|
const original = match[2];
|
|
1825
1957
|
const resolved = resolveTarget2(sourceDir, original);
|
|
@@ -1835,7 +1967,7 @@ var markdownLinkExtractor = {
|
|
|
1835
1967
|
raw: match[0],
|
|
1836
1968
|
candidates: [
|
|
1837
1969
|
{
|
|
1838
|
-
extractorId:
|
|
1970
|
+
extractorId: ID8,
|
|
1839
1971
|
kind: "references",
|
|
1840
1972
|
target: resolved,
|
|
1841
1973
|
// 0.95: the `[text](path)` syntax is unambiguous (the spec's
|
|
@@ -1866,14 +1998,14 @@ function resolveTarget2(sourceDir, raw) {
|
|
|
1866
1998
|
if (URL_SCHEME_RE.test(trimmed)) return null;
|
|
1867
1999
|
if (trimmed.startsWith("/")) return null;
|
|
1868
2000
|
const joined = sourceDir === "." ? trimmed : `${sourceDir}/${trimmed}`;
|
|
1869
|
-
return
|
|
2001
|
+
return pathPosix4.normalize(joined);
|
|
1870
2002
|
}
|
|
1871
2003
|
|
|
1872
2004
|
// plugins/core/extractors/mcp-tools/index.ts
|
|
1873
|
-
var
|
|
2005
|
+
var ID9 = "mcp-tools";
|
|
1874
2006
|
var MCP_PATTERN = /^mcp__([a-z0-9][a-z0-9_-]*)__[a-z0-9_-]+$/i;
|
|
1875
2007
|
var mcpToolsExtractor = {
|
|
1876
|
-
id:
|
|
2008
|
+
id: ID9,
|
|
1877
2009
|
pluginId: CORE_PLUGIN_ID,
|
|
1878
2010
|
kind: "extractor",
|
|
1879
2011
|
description: "Turns `tools: [mcp__<server>__<tool>]` entries in a node's frontmatter into an MCP node per unique server and an arrow from the source to each one. Example: `tools: [mcp__github__create_pr]` adds an `mcp://github` node and an arrow to it.",
|
|
@@ -1904,7 +2036,7 @@ var mcpToolsExtractor = {
|
|
|
1904
2036
|
raw: `mcp__${server}__*`,
|
|
1905
2037
|
candidates: [
|
|
1906
2038
|
{
|
|
1907
|
-
extractorId:
|
|
2039
|
+
extractorId: ID9,
|
|
1908
2040
|
kind: "references",
|
|
1909
2041
|
target: mcpPath,
|
|
1910
2042
|
confidence: 0.85,
|
|
@@ -1973,10 +2105,10 @@ var ANNOTATION_FIELD_UNKNOWN_TEXTS = {
|
|
|
1973
2105
|
};
|
|
1974
2106
|
|
|
1975
2107
|
// plugins/core/analyzers/annotation-field-unknown/index.ts
|
|
1976
|
-
var
|
|
2108
|
+
var ID10 = "annotation-field-unknown";
|
|
1977
2109
|
var RESERVED_ROOT_BLOCKS = /* @__PURE__ */ new Set(["identity", "annotations", "settings", "audit"]);
|
|
1978
2110
|
var annotationFieldUnknownAnalyzer = {
|
|
1979
|
-
id:
|
|
2111
|
+
id: ID10,
|
|
1980
2112
|
pluginId: CORE_PLUGIN_ID,
|
|
1981
2113
|
kind: "analyzer",
|
|
1982
2114
|
description: "Flags typos or unrecognized keys in sidecars (`.sm`).",
|
|
@@ -2011,7 +2143,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
2011
2143
|
for (const key of Object.keys(annotations)) {
|
|
2012
2144
|
if (!knownAnnotationKeys.has(key)) {
|
|
2013
2145
|
issues.push({
|
|
2014
|
-
analyzerId:
|
|
2146
|
+
analyzerId: ID10,
|
|
2015
2147
|
severity: "warn",
|
|
2016
2148
|
nodeIds: [node.path],
|
|
2017
2149
|
message: formatFinding({
|
|
@@ -2037,7 +2169,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
2037
2169
|
if (validator(value)) continue;
|
|
2038
2170
|
const errors = (validator.errors ?? []).map((e) => `${e.instancePath || "(root)"} ${e.message ?? e.keyword}`).join("; ");
|
|
2039
2171
|
issues.push({
|
|
2040
|
-
analyzerId:
|
|
2172
|
+
analyzerId: ID10,
|
|
2041
2173
|
severity: "warn",
|
|
2042
2174
|
nodeIds: [node.path],
|
|
2043
2175
|
message: formatFinding({
|
|
@@ -2052,7 +2184,7 @@ var annotationFieldUnknownAnalyzer = {
|
|
|
2052
2184
|
continue;
|
|
2053
2185
|
}
|
|
2054
2186
|
issues.push({
|
|
2055
|
-
analyzerId:
|
|
2187
|
+
analyzerId: ID10,
|
|
2056
2188
|
severity: "warn",
|
|
2057
2189
|
nodeIds: [node.path],
|
|
2058
2190
|
message: formatFinding({
|
|
@@ -2124,9 +2256,9 @@ var ANNOTATION_ORPHAN_TEXTS = {
|
|
|
2124
2256
|
};
|
|
2125
2257
|
|
|
2126
2258
|
// plugins/core/analyzers/annotation-orphan/index.ts
|
|
2127
|
-
var
|
|
2259
|
+
var ID11 = "annotation-orphan";
|
|
2128
2260
|
var annotationOrphanAnalyzer = {
|
|
2129
|
-
id:
|
|
2261
|
+
id: ID11,
|
|
2130
2262
|
pluginId: CORE_PLUGIN_ID,
|
|
2131
2263
|
kind: "analyzer",
|
|
2132
2264
|
description: "Flags sidecars (`.sm`) whose `.md` file no longer exists.",
|
|
@@ -2138,7 +2270,7 @@ var annotationOrphanAnalyzer = {
|
|
|
2138
2270
|
for (const orphan of orphans) {
|
|
2139
2271
|
const expectedMdRelative = orphan.relativePath.endsWith(".sm") ? `${orphan.relativePath.slice(0, -".sm".length)}.md` : `${orphan.relativePath}.md`;
|
|
2140
2272
|
issues.push({
|
|
2141
|
-
analyzerId:
|
|
2273
|
+
analyzerId: ID11,
|
|
2142
2274
|
severity: "warn",
|
|
2143
2275
|
nodeIds: [expectedMdRelative],
|
|
2144
2276
|
message: formatFinding({
|
|
@@ -2181,7 +2313,7 @@ var ANNOTATION_STALE_TEXTS = {
|
|
|
2181
2313
|
};
|
|
2182
2314
|
|
|
2183
2315
|
// plugins/core/analyzers/annotation-stale/index.ts
|
|
2184
|
-
var
|
|
2316
|
+
var ID12 = "annotation-stale";
|
|
2185
2317
|
var staleIcon = {
|
|
2186
2318
|
slot: "card.footer.right",
|
|
2187
2319
|
icon: "pi-clock",
|
|
@@ -2194,7 +2326,7 @@ var staleBadge = {
|
|
|
2194
2326
|
priority: 20
|
|
2195
2327
|
};
|
|
2196
2328
|
var annotationStaleAnalyzer = {
|
|
2197
|
-
id:
|
|
2329
|
+
id: ID12,
|
|
2198
2330
|
pluginId: CORE_PLUGIN_ID,
|
|
2199
2331
|
kind: "analyzer",
|
|
2200
2332
|
description: "Marks sidecars (`.sm`) that are out of date with their `.md`.",
|
|
@@ -2214,7 +2346,7 @@ var annotationStaleAnalyzer = {
|
|
|
2214
2346
|
const status = staleStatus(node.sidecar);
|
|
2215
2347
|
if (status === null) continue;
|
|
2216
2348
|
issues.push({
|
|
2217
|
-
analyzerId:
|
|
2349
|
+
analyzerId: ID12,
|
|
2218
2350
|
severity: "info",
|
|
2219
2351
|
nodeIds: [node.path],
|
|
2220
2352
|
message: formatFinding({ body: messageFor(status) }),
|
|
@@ -2260,9 +2392,9 @@ function tooltipFor(status) {
|
|
|
2260
2392
|
}
|
|
2261
2393
|
|
|
2262
2394
|
// plugins/core/analyzers/contribution-orphan/index.ts
|
|
2263
|
-
var
|
|
2395
|
+
var ID13 = "contribution-orphan";
|
|
2264
2396
|
var contributionOrphanAnalyzer = {
|
|
2265
|
-
id:
|
|
2397
|
+
id: ID13,
|
|
2266
2398
|
pluginId: CORE_PLUGIN_ID,
|
|
2267
2399
|
kind: "analyzer",
|
|
2268
2400
|
description: "Warns about plugin data referencing nodes renamed or deleted in the latest scan.",
|
|
@@ -2294,12 +2426,12 @@ var EXTRACTOR_COLLISION_TEXTS = {
|
|
|
2294
2426
|
};
|
|
2295
2427
|
|
|
2296
2428
|
// plugins/core/analyzers/extractor-collision/index.ts
|
|
2297
|
-
var
|
|
2429
|
+
var ID14 = "extractor-collision";
|
|
2298
2430
|
function signalLines(signal) {
|
|
2299
2431
|
return signal.range && typeof signal.range.line === "number" ? [signal.range.line] : void 0;
|
|
2300
2432
|
}
|
|
2301
2433
|
var extractorCollisionAnalyzer = {
|
|
2302
|
-
id:
|
|
2434
|
+
id: ID14,
|
|
2303
2435
|
pluginId: CORE_PLUGIN_ID,
|
|
2304
2436
|
kind: "analyzer",
|
|
2305
2437
|
description: "Reports when two extractors detect something at the same span of body text and the resolver drops one.",
|
|
@@ -2323,7 +2455,7 @@ function makeIssue(signal) {
|
|
|
2323
2455
|
const loserRange = signal.range ? `${signal.range.start}-${signal.range.end}` : "unknown";
|
|
2324
2456
|
const winnerRange = `${winner.range.start}-${winner.range.end}`;
|
|
2325
2457
|
return {
|
|
2326
|
-
analyzerId:
|
|
2458
|
+
analyzerId: ID14,
|
|
2327
2459
|
severity: "warn",
|
|
2328
2460
|
nodeIds: [signal.source],
|
|
2329
2461
|
message: formatFinding({
|
|
@@ -2367,7 +2499,7 @@ var ISSUE_COUNTER_TEXTS = {
|
|
|
2367
2499
|
};
|
|
2368
2500
|
|
|
2369
2501
|
// plugins/core/analyzers/issue-counter/index.ts
|
|
2370
|
-
var
|
|
2502
|
+
var ID15 = "issue-counter";
|
|
2371
2503
|
var warnCount = {
|
|
2372
2504
|
slot: "card.footer.right",
|
|
2373
2505
|
icon: "pi-exclamation-triangle",
|
|
@@ -2403,7 +2535,7 @@ function emitTierChips(ctx, ref, severity, counts, singleTooltip, manyTooltip) {
|
|
|
2403
2535
|
}
|
|
2404
2536
|
}
|
|
2405
2537
|
var issueCounterAnalyzer = {
|
|
2406
|
-
id:
|
|
2538
|
+
id: ID15,
|
|
2407
2539
|
pluginId: CORE_PLUGIN_ID,
|
|
2408
2540
|
kind: "analyzer",
|
|
2409
2541
|
description: "Emits one aggregate severity chip per node (error + warn counts) from the live issue accumulator.",
|
|
@@ -2466,7 +2598,7 @@ var LINK_COUNTER_TEXTS = {
|
|
|
2466
2598
|
};
|
|
2467
2599
|
|
|
2468
2600
|
// plugins/core/analyzers/link-counter/index.ts
|
|
2469
|
-
var
|
|
2601
|
+
var ID16 = "link-counter";
|
|
2470
2602
|
var linksIn = {
|
|
2471
2603
|
slot: "card.footer.left",
|
|
2472
2604
|
icon: "pi-download",
|
|
@@ -2482,7 +2614,7 @@ var linksOut = {
|
|
|
2482
2614
|
priority: 20
|
|
2483
2615
|
};
|
|
2484
2616
|
var linkCounterAnalyzer = {
|
|
2485
|
-
id:
|
|
2617
|
+
id: ID16,
|
|
2486
2618
|
pluginId: CORE_PLUGIN_ID,
|
|
2487
2619
|
kind: "analyzer",
|
|
2488
2620
|
description: "Counts incoming and outgoing links per node.",
|
|
@@ -2547,10 +2679,10 @@ var LINK_KIND_CONFLICT_TEXTS = {
|
|
|
2547
2679
|
};
|
|
2548
2680
|
|
|
2549
2681
|
// plugins/core/analyzers/link-kind-conflict/index.ts
|
|
2550
|
-
var
|
|
2682
|
+
var ID17 = "link-kind-conflict";
|
|
2551
2683
|
var NON_CONFLICTING_KINDS = /* @__PURE__ */ new Set(["points"]);
|
|
2552
2684
|
var linkKindConflictAnalyzer = {
|
|
2553
|
-
id:
|
|
2685
|
+
id: ID17,
|
|
2554
2686
|
pluginId: CORE_PLUGIN_ID,
|
|
2555
2687
|
kind: "analyzer",
|
|
2556
2688
|
description: "Flags conflicting arrow meanings between extractors (e.g. `references` vs `invokes`).",
|
|
@@ -2598,7 +2730,7 @@ var linkKindConflictAnalyzer = {
|
|
|
2598
2730
|
const [source, target] = key.split("\0");
|
|
2599
2731
|
const kindList = variants.map((v) => v.kind).join(" / ");
|
|
2600
2732
|
issues.push({
|
|
2601
|
-
analyzerId:
|
|
2733
|
+
analyzerId: ID17,
|
|
2602
2734
|
severity: "warn",
|
|
2603
2735
|
nodeIds: [source, target],
|
|
2604
2736
|
message: formatFinding({
|
|
@@ -2637,9 +2769,9 @@ var LINK_SELF_LOOP_TEXTS = {
|
|
|
2637
2769
|
};
|
|
2638
2770
|
|
|
2639
2771
|
// plugins/core/analyzers/link-self-loop/index.ts
|
|
2640
|
-
var
|
|
2772
|
+
var ID18 = "link-self-loop";
|
|
2641
2773
|
var linkSelfLoopAnalyzer = {
|
|
2642
|
-
id:
|
|
2774
|
+
id: ID18,
|
|
2643
2775
|
pluginId: CORE_PLUGIN_ID,
|
|
2644
2776
|
kind: "analyzer",
|
|
2645
2777
|
description: "Flags links whose source is also their own resolved target (e.g. a body heading like `# /deploy` inside the file that defines `/deploy`).",
|
|
@@ -2649,7 +2781,7 @@ var linkSelfLoopAnalyzer = {
|
|
|
2649
2781
|
for (const link of ctx.links) {
|
|
2650
2782
|
if (!isSelfLoop(link)) continue;
|
|
2651
2783
|
issues.push({
|
|
2652
|
-
analyzerId:
|
|
2784
|
+
analyzerId: ID18,
|
|
2653
2785
|
severity: "warn",
|
|
2654
2786
|
nodeIds: [link.source],
|
|
2655
2787
|
message: formatFinding({
|
|
@@ -2681,9 +2813,9 @@ var NAME_COLLISION_TEXTS = {
|
|
|
2681
2813
|
};
|
|
2682
2814
|
|
|
2683
2815
|
// plugins/core/analyzers/name-collision/index.ts
|
|
2684
|
-
var
|
|
2816
|
+
var ID19 = "name-collision";
|
|
2685
2817
|
var nameCollisionAnalyzer = {
|
|
2686
|
-
id:
|
|
2818
|
+
id: ID19,
|
|
2687
2819
|
pluginId: CORE_PLUGIN_ID,
|
|
2688
2820
|
kind: "analyzer",
|
|
2689
2821
|
mode: "deterministic",
|
|
@@ -2697,7 +2829,7 @@ var nameCollisionAnalyzer = {
|
|
|
2697
2829
|
for (const [name, claims] of collisions) {
|
|
2698
2830
|
const paths = claims.map((c) => c.path);
|
|
2699
2831
|
issues.push({
|
|
2700
|
-
analyzerId:
|
|
2832
|
+
analyzerId: ID19,
|
|
2701
2833
|
severity: "error",
|
|
2702
2834
|
nodeIds: paths,
|
|
2703
2835
|
message: formatFinding({
|
|
@@ -2747,9 +2879,9 @@ var NAME_RESERVED_TEXTS = {
|
|
|
2747
2879
|
};
|
|
2748
2880
|
|
|
2749
2881
|
// plugins/core/analyzers/name-reserved/index.ts
|
|
2750
|
-
var
|
|
2882
|
+
var ID20 = "name-reserved";
|
|
2751
2883
|
var nameReservedAnalyzer = {
|
|
2752
|
-
id:
|
|
2884
|
+
id: ID20,
|
|
2753
2885
|
pluginId: CORE_PLUGIN_ID,
|
|
2754
2886
|
kind: "analyzer",
|
|
2755
2887
|
description: "Flags two kinds of reserved-name collision: a file whose name shadows a built-in command of the active runtime, and a link that resolves to one of those reserved names.",
|
|
@@ -2767,7 +2899,7 @@ var nameReservedAnalyzer = {
|
|
|
2767
2899
|
const node = byPath3.get(path);
|
|
2768
2900
|
if (!node) continue;
|
|
2769
2901
|
issues.push({
|
|
2770
|
-
analyzerId:
|
|
2902
|
+
analyzerId: ID20,
|
|
2771
2903
|
severity: "warn",
|
|
2772
2904
|
nodeIds: [node.path],
|
|
2773
2905
|
message: formatFinding({
|
|
@@ -2789,7 +2921,7 @@ var nameReservedAnalyzer = {
|
|
|
2789
2921
|
adjust(link, { kind: "delta", value: -RESERVED_PENALTY });
|
|
2790
2922
|
}
|
|
2791
2923
|
issues.push({
|
|
2792
|
-
analyzerId:
|
|
2924
|
+
analyzerId: ID20,
|
|
2793
2925
|
severity: "warn",
|
|
2794
2926
|
nodeIds: [link.source],
|
|
2795
2927
|
message: formatFinding({
|
|
@@ -2841,7 +2973,7 @@ var NODE_STABILITY_TEXTS = {
|
|
|
2841
2973
|
};
|
|
2842
2974
|
|
|
2843
2975
|
// plugins/core/analyzers/node-stability/index.ts
|
|
2844
|
-
var
|
|
2976
|
+
var ID21 = "node-stability";
|
|
2845
2977
|
var EXPERIMENTAL_TOOLTIP = "Experimental: API may change";
|
|
2846
2978
|
var DEPRECATED_TOOLTIP = "Deprecated: avoid in new code";
|
|
2847
2979
|
var experimental = {
|
|
@@ -2859,7 +2991,7 @@ var deprecated = {
|
|
|
2859
2991
|
priority: 10
|
|
2860
2992
|
};
|
|
2861
2993
|
var nodeStabilityAnalyzer = {
|
|
2862
|
-
id:
|
|
2994
|
+
id: ID21,
|
|
2863
2995
|
pluginId: CORE_PLUGIN_ID,
|
|
2864
2996
|
kind: "analyzer",
|
|
2865
2997
|
description: "Surfaces a node's stability stage on the card: `deprecated` as a chip plus a finding, `experimental` as a chip only; `stable` and unset stay silent.",
|
|
@@ -2881,7 +3013,7 @@ var nodeStabilityAnalyzer = {
|
|
|
2881
3013
|
severity: "warn"
|
|
2882
3014
|
});
|
|
2883
3015
|
issues.push({
|
|
2884
|
-
analyzerId:
|
|
3016
|
+
analyzerId: ID21,
|
|
2885
3017
|
severity: "warn",
|
|
2886
3018
|
nodeIds: [node.path],
|
|
2887
3019
|
message: formatFinding({ body: tx(NODE_STABILITY_TEXTS.deprecated) }),
|
|
@@ -2933,9 +3065,9 @@ var REFERENCE_BROKEN_TEXTS = {
|
|
|
2933
3065
|
};
|
|
2934
3066
|
|
|
2935
3067
|
// plugins/core/analyzers/reference-broken/index.ts
|
|
2936
|
-
var
|
|
3068
|
+
var ID22 = "reference-broken";
|
|
2937
3069
|
var referenceBrokenAnalyzer = {
|
|
2938
|
-
id:
|
|
3070
|
+
id: ID22,
|
|
2939
3071
|
pluginId: CORE_PLUGIN_ID,
|
|
2940
3072
|
kind: "analyzer",
|
|
2941
3073
|
description: "Flags arrows pointing at a node not part of the current scan.",
|
|
@@ -2978,7 +3110,7 @@ function penalizeBrokenConfidence(adjust, link) {
|
|
|
2978
3110
|
}
|
|
2979
3111
|
function buildIssue(link) {
|
|
2980
3112
|
return {
|
|
2981
|
-
analyzerId:
|
|
3113
|
+
analyzerId: ID22,
|
|
2982
3114
|
// `error`, not `warn`: a link whose target is not in the scan is a
|
|
2983
3115
|
// structural defect the operator must notice, and the card chip
|
|
2984
3116
|
// paints `danger` (red) to match. Per the chip-vs-issue policy in
|
|
@@ -3042,9 +3174,9 @@ var REFERENCE_REDUNDANT_TEXTS = {
|
|
|
3042
3174
|
};
|
|
3043
3175
|
|
|
3044
3176
|
// plugins/core/analyzers/reference-redundant/index.ts
|
|
3045
|
-
var
|
|
3177
|
+
var ID23 = "reference-redundant";
|
|
3046
3178
|
var referenceRedundantAnalyzer = {
|
|
3047
|
-
id:
|
|
3179
|
+
id: ID23,
|
|
3048
3180
|
pluginId: CORE_PLUGIN_ID,
|
|
3049
3181
|
kind: "analyzer",
|
|
3050
3182
|
description: "Flags when one node references the same target through two or more different links (e.g. a markdown link plus a `references:` entry).",
|
|
@@ -3067,7 +3199,7 @@ var referenceRedundantAnalyzer = {
|
|
|
3067
3199
|
const [source, resolvedTarget] = key.split("\0");
|
|
3068
3200
|
const flat = flattenOccurrences(links);
|
|
3069
3201
|
issues.push({
|
|
3070
|
-
analyzerId:
|
|
3202
|
+
analyzerId: ID23,
|
|
3071
3203
|
severity: "info",
|
|
3072
3204
|
nodeIds: [source],
|
|
3073
3205
|
message: formatFinding({
|
|
@@ -3403,9 +3535,9 @@ var SCHEMA_VIOLATION_TEXTS = {
|
|
|
3403
3535
|
};
|
|
3404
3536
|
|
|
3405
3537
|
// plugins/core/analyzers/schema-violation/index.ts
|
|
3406
|
-
var
|
|
3538
|
+
var ID24 = "schema-violation";
|
|
3407
3539
|
var schemaViolationAnalyzer = {
|
|
3408
|
-
id:
|
|
3540
|
+
id: ID24,
|
|
3409
3541
|
pluginId: CORE_PLUGIN_ID,
|
|
3410
3542
|
kind: "analyzer",
|
|
3411
3543
|
description: "Flags nodes or links that violate the project schemas.",
|
|
@@ -3455,7 +3587,7 @@ function collectNodeFindings(v, node, out) {
|
|
|
3455
3587
|
const result = v.validate("node", toNodeForSchema(node));
|
|
3456
3588
|
if (result.ok) return;
|
|
3457
3589
|
out.push({
|
|
3458
|
-
analyzerId:
|
|
3590
|
+
analyzerId: ID24,
|
|
3459
3591
|
severity: "error",
|
|
3460
3592
|
nodeIds: [node.path],
|
|
3461
3593
|
message: formatFinding({
|
|
@@ -3470,7 +3602,7 @@ function collectLinkFindings(v, link, out) {
|
|
|
3470
3602
|
const result = v.validate("link", toLinkForSchema(link));
|
|
3471
3603
|
if (result.ok) return;
|
|
3472
3604
|
out.push({
|
|
3473
|
-
analyzerId:
|
|
3605
|
+
analyzerId: ID24,
|
|
3474
3606
|
severity: "error",
|
|
3475
3607
|
nodeIds: [link.source],
|
|
3476
3608
|
message: formatFinding({
|
|
@@ -3539,13 +3671,13 @@ var ASCII_FORMATTER_TEXTS = {
|
|
|
3539
3671
|
};
|
|
3540
3672
|
|
|
3541
3673
|
// plugins/core/formatters/ascii/index.ts
|
|
3542
|
-
var
|
|
3674
|
+
var ID25 = "ascii";
|
|
3543
3675
|
var KIND_ORDER = ["agent", "command", "skill", "markdown"];
|
|
3544
3676
|
var asciiFormatter = {
|
|
3545
|
-
id:
|
|
3677
|
+
id: ID25,
|
|
3546
3678
|
pluginId: CORE_PLUGIN_ID,
|
|
3547
3679
|
kind: "formatter",
|
|
3548
|
-
formatId:
|
|
3680
|
+
formatId: ID25,
|
|
3549
3681
|
description: "Renders the scan as plain text in three sections: nodes (grouped by kind), arrows, and issues. Used by `sm scan --format ascii`.",
|
|
3550
3682
|
// ASCII tree formatter, header + per-kind sections + per-issue
|
|
3551
3683
|
// section. Each section iterates and renders; splitting per section
|
|
@@ -3639,13 +3771,13 @@ function renderSection(out, kind, group) {
|
|
|
3639
3771
|
}
|
|
3640
3772
|
|
|
3641
3773
|
// plugins/core/formatters/json/index.ts
|
|
3642
|
-
var
|
|
3774
|
+
var ID26 = "json";
|
|
3643
3775
|
var jsonFormatter = {
|
|
3644
|
-
id:
|
|
3776
|
+
id: ID26,
|
|
3645
3777
|
pluginId: CORE_PLUGIN_ID,
|
|
3646
3778
|
kind: "formatter",
|
|
3647
3779
|
description: "Renders the persisted scan as JSON (conforms to `scan-result.schema.json`). Used by `sm graph --format json` and `GET /api/graph?format=json`.",
|
|
3648
|
-
formatId:
|
|
3780
|
+
formatId: ID26,
|
|
3649
3781
|
format(ctx) {
|
|
3650
3782
|
if (ctx.scanResult !== void 0) {
|
|
3651
3783
|
return JSON.stringify(ctx.scanResult);
|
|
@@ -3792,13 +3924,13 @@ var BUMP_TEXTS = {
|
|
|
3792
3924
|
};
|
|
3793
3925
|
|
|
3794
3926
|
// plugins/core/actions/node-bump/index.ts
|
|
3795
|
-
var
|
|
3927
|
+
var ID27 = "node-bump";
|
|
3796
3928
|
var bumpButton = {
|
|
3797
3929
|
slot: "inspector.action.button",
|
|
3798
3930
|
priority: 10
|
|
3799
3931
|
};
|
|
3800
3932
|
var nodeBumpAction = {
|
|
3801
|
-
id:
|
|
3933
|
+
id: ID27,
|
|
3802
3934
|
pluginId: CORE_PLUGIN_ID,
|
|
3803
3935
|
kind: "action",
|
|
3804
3936
|
description: "Marks a node as updated: bumps `annotations.version`, refreshes sidecar hashes, and records the timestamp.",
|
|
@@ -3901,13 +4033,13 @@ var NODE_SET_STABILITY_TEXTS = {
|
|
|
3901
4033
|
};
|
|
3902
4034
|
|
|
3903
4035
|
// plugins/core/actions/node-set-stability/index.ts
|
|
3904
|
-
var
|
|
4036
|
+
var ID28 = "node-set-stability";
|
|
3905
4037
|
var setStabilityButton = {
|
|
3906
4038
|
slot: "inspector.action.button",
|
|
3907
4039
|
priority: 15
|
|
3908
4040
|
};
|
|
3909
4041
|
var nodeSetStabilityAction = {
|
|
3910
|
-
id:
|
|
4042
|
+
id: ID28,
|
|
3911
4043
|
pluginId: CORE_PLUGIN_ID,
|
|
3912
4044
|
kind: "action",
|
|
3913
4045
|
description: "Sets the lifecycle stage of the current node (writes `stability` to the sidecar).",
|
|
@@ -3979,9 +4111,9 @@ function invokeSetStability(input, ctx) {
|
|
|
3979
4111
|
}
|
|
3980
4112
|
|
|
3981
4113
|
// plugins/core/actions/node-set-tags/index.ts
|
|
3982
|
-
var
|
|
4114
|
+
var ID29 = "node-set-tags";
|
|
3983
4115
|
var nodeSetTagsAction = {
|
|
3984
|
-
id:
|
|
4116
|
+
id: ID29,
|
|
3985
4117
|
pluginId: CORE_PLUGIN_ID,
|
|
3986
4118
|
kind: "action",
|
|
3987
4119
|
description: "Sets the taxonomy tags of the current node (writes `tags` to the sidecar; whole-array replace).",
|
|
@@ -4523,6 +4655,8 @@ var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", ver
|
|
|
4523
4655
|
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "claude", version: VERSION };
|
|
4524
4656
|
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: VERSION };
|
|
4525
4657
|
var codexProvider2 = { ...codexProvider, pluginId: "codex", version: VERSION };
|
|
4658
|
+
var atFileExtractor2 = { ...atFileExtractor, pluginId: "codex", version: VERSION };
|
|
4659
|
+
var dollarSkillExtractor2 = { ...dollarSkillExtractor, pluginId: "codex", version: VERSION };
|
|
4526
4660
|
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: VERSION };
|
|
4527
4661
|
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: VERSION };
|
|
4528
4662
|
var backtickPathExtractor2 = { ...backtickPathExtractor, pluginId: "core", version: VERSION };
|
|
@@ -4572,7 +4706,9 @@ var builtInPlugins = [
|
|
|
4572
4706
|
id: "codex",
|
|
4573
4707
|
description: "OpenAI Codex CLI platform integration. Classifies TOML sub-agent definitions under `.codex/agents/*.toml`.",
|
|
4574
4708
|
extensions: [
|
|
4575
|
-
codexProvider2
|
|
4709
|
+
codexProvider2,
|
|
4710
|
+
atFileExtractor2,
|
|
4711
|
+
dollarSkillExtractor2
|
|
4576
4712
|
]
|
|
4577
4713
|
},
|
|
4578
4714
|
{
|
|
@@ -5551,7 +5687,8 @@ var defaults_default = {
|
|
|
5551
5687
|
// kernel/config/loader.ts
|
|
5552
5688
|
var PROJECT_LOCAL_ONLY_KEYS = /* @__PURE__ */ new Set([
|
|
5553
5689
|
"allowEditSmFiles",
|
|
5554
|
-
"scan.referencePaths"
|
|
5690
|
+
"scan.referencePaths",
|
|
5691
|
+
"pluginTrust.projectEnabled"
|
|
5555
5692
|
]);
|
|
5556
5693
|
var DEFAULTS = defaults_default;
|
|
5557
5694
|
function loadConfig(opts) {
|
|
@@ -5832,7 +5969,8 @@ function enumerateConfigPaths(obj, prefix = "") {
|
|
|
5832
5969
|
|
|
5833
5970
|
// core/config/helper.ts
|
|
5834
5971
|
var PRIVACY_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
5835
|
-
"scan.referencePaths"
|
|
5972
|
+
"scan.referencePaths",
|
|
5973
|
+
"pluginTrust.projectEnabled"
|
|
5836
5974
|
]);
|
|
5837
5975
|
var ProjectLocalOnlyKeyError = class extends Error {
|
|
5838
5976
|
constructor(key) {
|
|
@@ -5919,6 +6057,14 @@ function projectPathExposure(inputs) {
|
|
|
5919
6057
|
if (exposed.length === 0) return empty;
|
|
5920
6058
|
return { expandsSurface: true, exposedPaths: exposed };
|
|
5921
6059
|
}
|
|
6060
|
+
function projectTrustExposure(inputs) {
|
|
6061
|
+
if (inputs.value !== true) return { expandsSurface: false };
|
|
6062
|
+
const before = readConfigValue("pluginTrust.projectEnabled", {
|
|
6063
|
+
cwd: inputs.cwd,
|
|
6064
|
+
default: false
|
|
6065
|
+
}) ?? false;
|
|
6066
|
+
return { expandsSurface: before !== true };
|
|
6067
|
+
}
|
|
5922
6068
|
function resolveScanPathForExposure(raw, cwd) {
|
|
5923
6069
|
if (raw.startsWith("~/")) return resolve7(join4(osHomedir(), raw.slice(2)));
|
|
5924
6070
|
if (raw === "~") return resolve7(osHomedir());
|
|
@@ -7567,40 +7713,38 @@ function formatMigrationName(m) {
|
|
|
7567
7713
|
}
|
|
7568
7714
|
|
|
7569
7715
|
// kernel/adapters/sqlite/plugins.ts
|
|
7570
|
-
async function
|
|
7716
|
+
async function setPluginTrusted(db, pluginId, trusted, now = Date.now()) {
|
|
7571
7717
|
await db.insertInto("config_plugins").values({
|
|
7572
7718
|
pluginId,
|
|
7573
|
-
|
|
7574
|
-
configJson: null,
|
|
7719
|
+
trusted: trusted ? 1 : 0,
|
|
7575
7720
|
updatedAt: now
|
|
7576
7721
|
}).onConflict(
|
|
7577
7722
|
(oc) => oc.column("pluginId").doUpdateSet({
|
|
7578
|
-
|
|
7723
|
+
trusted: trusted ? 1 : 0,
|
|
7579
7724
|
updatedAt: now
|
|
7580
7725
|
})
|
|
7581
7726
|
).execute();
|
|
7582
7727
|
}
|
|
7583
|
-
async function
|
|
7584
|
-
const row = await db.selectFrom("config_plugins").select(["
|
|
7728
|
+
async function getPluginTrusted(db, pluginId) {
|
|
7729
|
+
const row = await db.selectFrom("config_plugins").select(["trusted"]).where("pluginId", "=", pluginId).executeTakeFirst();
|
|
7585
7730
|
if (!row) return void 0;
|
|
7586
|
-
return row.
|
|
7731
|
+
return row.trusted === 1;
|
|
7587
7732
|
}
|
|
7588
|
-
async function
|
|
7589
|
-
const rows = await db.selectFrom("config_plugins").select(["pluginId", "
|
|
7733
|
+
async function listPluginTrust(db) {
|
|
7734
|
+
const rows = await db.selectFrom("config_plugins").select(["pluginId", "trusted", "updatedAt"]).orderBy("pluginId", "asc").execute();
|
|
7590
7735
|
return rows.map((r) => ({
|
|
7591
7736
|
pluginId: r.pluginId,
|
|
7592
|
-
|
|
7593
|
-
configJson: r.configJson,
|
|
7737
|
+
trusted: r.trusted === 1,
|
|
7594
7738
|
updatedAt: r.updatedAt
|
|
7595
7739
|
}));
|
|
7596
7740
|
}
|
|
7597
|
-
async function
|
|
7741
|
+
async function deletePluginTrust(db, pluginId) {
|
|
7598
7742
|
await db.deleteFrom("config_plugins").where("pluginId", "=", pluginId).execute();
|
|
7599
7743
|
}
|
|
7600
|
-
async function
|
|
7601
|
-
const rows = await
|
|
7744
|
+
async function loadPluginTrustMap(db) {
|
|
7745
|
+
const rows = await listPluginTrust(db);
|
|
7602
7746
|
const out = /* @__PURE__ */ new Map();
|
|
7603
|
-
for (const row of rows) out.set(row.pluginId, row.
|
|
7747
|
+
for (const row of rows) out.set(row.pluginId, row.trusted);
|
|
7604
7748
|
return out;
|
|
7605
7749
|
}
|
|
7606
7750
|
|
|
@@ -8755,7 +8899,7 @@ var SqliteStorageAdapter = class {
|
|
|
8755
8899
|
jobs;
|
|
8756
8900
|
favorites;
|
|
8757
8901
|
preferences;
|
|
8758
|
-
|
|
8902
|
+
trust;
|
|
8759
8903
|
migrations;
|
|
8760
8904
|
pluginMigrations;
|
|
8761
8905
|
constructor(options) {
|
|
@@ -8872,12 +9016,12 @@ var SqliteStorageAdapter = class {
|
|
|
8872
9016
|
loadUpdateCheckCache: () => loadUpdateCheckCache(this.db),
|
|
8873
9017
|
saveUpdateCheckCache: (cache) => saveUpdateCheckCache(this.db, cache)
|
|
8874
9018
|
};
|
|
8875
|
-
this.
|
|
8876
|
-
set: (pluginId,
|
|
8877
|
-
get: (pluginId) =>
|
|
8878
|
-
list: () =>
|
|
8879
|
-
delete: (pluginId) =>
|
|
8880
|
-
|
|
9019
|
+
this.trust = {
|
|
9020
|
+
set: (pluginId, trusted) => setPluginTrusted(this.db, pluginId, trusted),
|
|
9021
|
+
get: (pluginId) => getPluginTrusted(this.db, pluginId),
|
|
9022
|
+
list: () => listPluginTrust(this.db),
|
|
9023
|
+
delete: (pluginId) => deletePluginTrust(this.db, pluginId),
|
|
9024
|
+
loadTrustMap: () => loadPluginTrustMap(this.db)
|
|
8881
9025
|
};
|
|
8882
9026
|
const path = this.#options.databasePath;
|
|
8883
9027
|
this.migrations = {
|
|
@@ -10064,21 +10208,22 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
10064
10208
|
// schema. Both are GitHub blob URLs.
|
|
10065
10209
|
invalidManifestExtensionShape: "{{relEntry}}: {{errors}}. See {{docUrl}}.",
|
|
10066
10210
|
importExceededTimeout: "import exceeded {{timeoutMs}}ms; likely a top-level side effect (network call, infinite loop, large blocking work). Move side effects into the runtime methods (`detect` / `evaluate` / `render` / etc.).",
|
|
10067
|
-
disabledByConfig: "disabled by
|
|
10211
|
+
disabledByConfig: "disabled by settings.json (plugins.<id>.enabled)",
|
|
10068
10212
|
/**
|
|
10069
10213
|
* Reason stamped on a project-local disk plugin discovered but not
|
|
10070
|
-
* imported because the operator never granted local trust.
|
|
10071
|
-
* from `disabledByConfig` (an explicit toggle-off
|
|
10072
|
-
*
|
|
10073
|
-
* `
|
|
10214
|
+
* imported because the operator never granted local import trust.
|
|
10215
|
+
* Distinct from `disabledByConfig` (an explicit operational toggle-off
|
|
10216
|
+
* in the config layers): this id is enabled but carries no
|
|
10217
|
+
* `config_plugins` trust grant, so its code stays unexecuted until
|
|
10218
|
+
* `sm plugins trust` records local consent.
|
|
10074
10219
|
*/
|
|
10075
|
-
untrustedNotLoaded: "not loaded: project-local plugin is
|
|
10220
|
+
untrustedNotLoaded: "not loaded: project-local plugin is enabled but not trusted on this machine. Run `sm plugins trust {{pluginId}}` to load it.",
|
|
10076
10221
|
/**
|
|
10077
10222
|
* One-time aggregate notice the runtime emits when project-local
|
|
10078
10223
|
* plugins were found on disk but left unloaded for lack of trust. The
|
|
10079
10224
|
* `{{count}}` plugins ride the scan without executing any code.
|
|
10080
10225
|
*/
|
|
10081
|
-
untrustedPluginsFoundNotice: "{{count}} project-local plugin(s) found in .skill-map/plugins/ but not loaded (untrusted). Their code did NOT run. Review with `sm plugins list`, then
|
|
10226
|
+
untrustedPluginsFoundNotice: "{{count}} project-local plugin(s) found in .skill-map/plugins/ but not loaded (untrusted). Their code did NOT run. Review with `sm plugins list`, then trust any you vetted with `sm plugins trust <id>`.",
|
|
10082
10227
|
invalidManifestDirMismatch: "directory name '{{dirName}}' does not match manifest id '{{manifestId}}'. Rename the directory to match the id, or update the manifest id to match the directory.",
|
|
10083
10228
|
idCollision: "Plugin '{{id}}' at {{pathA}} collides with the plugin at {{pathB}}. Rename one and rerun.",
|
|
10084
10229
|
loadErrorPluginIdMismatch: "{{relEntry}}: extension declares pluginId '{{declared}}' but its plugin.json declares id '{{manifestId}}'. Remove the explicit pluginId from the extension; the loader injects it from plugin.json#/id.",
|
|
@@ -11031,26 +11176,33 @@ var SHIPS_DISABLED = /* @__PURE__ */ new Set([
|
|
|
11031
11176
|
function installedDefaultEnabled(stability) {
|
|
11032
11177
|
return stability === void 0 || !SHIPS_DISABLED.has(stability);
|
|
11033
11178
|
}
|
|
11034
|
-
function resolvePluginEnabled(pluginId, cfg,
|
|
11179
|
+
function resolvePluginEnabled(pluginId, cfg, installedDefault = true) {
|
|
11035
11180
|
if (isPluginLocked(pluginId)) return true;
|
|
11036
|
-
|
|
11181
|
+
const slash = pluginId.indexOf("/");
|
|
11182
|
+
if (slash >= 0) {
|
|
11183
|
+
return resolveQualifiedEnabled(
|
|
11184
|
+
pluginId.slice(0, slash),
|
|
11185
|
+
pluginId.slice(slash + 1),
|
|
11186
|
+
cfg,
|
|
11187
|
+
installedDefault
|
|
11188
|
+
);
|
|
11189
|
+
}
|
|
11037
11190
|
const settingsEntry = cfg.plugins[pluginId];
|
|
11038
11191
|
if (settingsEntry?.enabled !== void 0) return settingsEntry.enabled;
|
|
11039
11192
|
return installedDefault;
|
|
11040
11193
|
}
|
|
11041
|
-
function
|
|
11042
|
-
|
|
11194
|
+
function resolveQualifiedEnabled(plugin, ext, cfg, installedDefault) {
|
|
11195
|
+
const pluginEntry = cfg.plugins[plugin];
|
|
11196
|
+
const perExt = pluginEntry?.extensions?.[ext]?.enabled;
|
|
11197
|
+
if (perExt !== void 0) return perExt;
|
|
11198
|
+
if (pluginEntry?.enabled !== void 0) return pluginEntry.enabled;
|
|
11199
|
+
return installedDefault;
|
|
11043
11200
|
}
|
|
11044
|
-
function
|
|
11045
|
-
return (pluginId) =>
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
if (!enabled) continue;
|
|
11050
|
-
if (key === pluginId || key.startsWith(prefix)) return true;
|
|
11051
|
-
}
|
|
11052
|
-
return false;
|
|
11053
|
-
};
|
|
11201
|
+
function makeEnabledResolver(cfg) {
|
|
11202
|
+
return (pluginId, installedDefault) => resolvePluginEnabled(pluginId, cfg, installedDefault);
|
|
11203
|
+
}
|
|
11204
|
+
function makeTrustResolver(trustMap, trustProjectEnabled) {
|
|
11205
|
+
return (pluginId) => isPluginLocked(pluginId) || trustMap.get(pluginId) === true || trustProjectEnabled;
|
|
11054
11206
|
}
|
|
11055
11207
|
|
|
11056
11208
|
// core/runtime/plugin-runtime/resolver.ts
|
|
@@ -11075,11 +11227,15 @@ async function buildResolverInputs(ctx) {
|
|
|
11075
11227
|
db: void 0,
|
|
11076
11228
|
...ctx
|
|
11077
11229
|
});
|
|
11078
|
-
const
|
|
11230
|
+
const trustMap = await tryWithSqlite(
|
|
11079
11231
|
{ databasePath: dbPath, autoBackup: false },
|
|
11080
|
-
(adapter) => adapter.
|
|
11232
|
+
(adapter) => adapter.trust.loadTrustMap()
|
|
11081
11233
|
) ?? /* @__PURE__ */ new Map();
|
|
11082
|
-
return {
|
|
11234
|
+
return {
|
|
11235
|
+
resolveEnabled: makeEnabledResolver(cfg),
|
|
11236
|
+
trustMap,
|
|
11237
|
+
trustProjectEnabled: cfg.pluginTrust?.projectEnabled ?? false
|
|
11238
|
+
};
|
|
11083
11239
|
}
|
|
11084
11240
|
|
|
11085
11241
|
// kernel/scan/walk-content.ts
|
|
@@ -11616,11 +11772,13 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11616
11772
|
const searchPaths = resolveSearchPaths(opts, ctx);
|
|
11617
11773
|
const validators = loadSchemaValidators();
|
|
11618
11774
|
let resolveEnabled;
|
|
11619
|
-
let
|
|
11775
|
+
let trustMap;
|
|
11776
|
+
let trustProjectEnabled;
|
|
11620
11777
|
try {
|
|
11621
11778
|
const inputs = await buildResolverInputs(ctx);
|
|
11622
11779
|
resolveEnabled = inputs.resolveEnabled;
|
|
11623
|
-
|
|
11780
|
+
trustMap = inputs.trustMap;
|
|
11781
|
+
trustProjectEnabled = inputs.trustProjectEnabled;
|
|
11624
11782
|
} catch {
|
|
11625
11783
|
}
|
|
11626
11784
|
const loaderOpts = {
|
|
@@ -11630,7 +11788,10 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11630
11788
|
};
|
|
11631
11789
|
if (resolveEnabled) loaderOpts.resolveEnabled = resolveEnabled;
|
|
11632
11790
|
if (!opts.pluginDir) {
|
|
11633
|
-
loaderOpts.resolveImportTrust =
|
|
11791
|
+
loaderOpts.resolveImportTrust = makeTrustResolver(
|
|
11792
|
+
trustMap ?? /* @__PURE__ */ new Map(),
|
|
11793
|
+
trustProjectEnabled ?? false
|
|
11794
|
+
);
|
|
11634
11795
|
}
|
|
11635
11796
|
const loader = createPluginLoader(loaderOpts);
|
|
11636
11797
|
const discovered = await loader.discoverAndLoadAll();
|
|
@@ -12151,14 +12312,16 @@ import { existsSync as existsSync16 } from "fs";
|
|
|
12151
12312
|
import { join as join10 } from "path";
|
|
12152
12313
|
function detectProvidersFromFilesystem(cwd, providers) {
|
|
12153
12314
|
const seen = /* @__PURE__ */ new Set();
|
|
12154
|
-
const
|
|
12315
|
+
const matched = [];
|
|
12155
12316
|
for (const provider of providers) {
|
|
12156
12317
|
if (seen.has(provider.id)) continue;
|
|
12157
12318
|
if (!isDetectableUnderCwd(cwd, provider)) continue;
|
|
12158
12319
|
seen.add(provider.id);
|
|
12159
|
-
|
|
12320
|
+
matched.push(provider);
|
|
12160
12321
|
}
|
|
12161
|
-
|
|
12322
|
+
const hasVendor = matched.some((p) => p.detect?.fallback !== true);
|
|
12323
|
+
const kept = hasVendor ? matched.filter((p) => p.detect?.fallback !== true) : matched;
|
|
12324
|
+
return kept.map((p) => p.id);
|
|
12162
12325
|
}
|
|
12163
12326
|
function isDetectableUnderCwd(cwd, provider) {
|
|
12164
12327
|
if (!installedDefaultEnabled(provider.stability)) return false;
|
|
@@ -12269,6 +12432,18 @@ var CONFIG_TEXTS = {
|
|
|
12269
12432
|
* screen what they just opted into.
|
|
12270
12433
|
*/
|
|
12271
12434
|
privacyGateConfirmed: '{{glyph}} Opening disk access for "{{key}}":\n{{paths}}\n',
|
|
12435
|
+
/**
|
|
12436
|
+
* Surfaced when `sm config set pluginTrust.projectEnabled true` is run
|
|
12437
|
+
* without `--yes`. Turning the opt-in on expands the LOCAL
|
|
12438
|
+
* code-execution surface (every plugin the project enables becomes
|
|
12439
|
+
* trusted), so the verb refuses without confirmation.
|
|
12440
|
+
*/
|
|
12441
|
+
trustGateRequired: '{{glyph}} sm config: setting "pluginTrust.projectEnabled" to true trusts every plugin this project enables.\n Their code may then import and run on this machine without a per-plugin trust grant.\n {{hint}}\n',
|
|
12442
|
+
trustGateRequiredHint: "Rerun with --yes to confirm. Turning it off needs no flag. Prefer per-plugin `sm plugins trust <id>` for narrower consent.",
|
|
12443
|
+
/**
|
|
12444
|
+
* Receipt printed when the trust gate has been confirmed via `--yes`.
|
|
12445
|
+
*/
|
|
12446
|
+
trustGateConfirmed: "{{glyph}} Local plugin trust opt-in enabled: every plugin this project enables is now trusted on this machine.\n",
|
|
12272
12447
|
/**
|
|
12273
12448
|
* Confirmation printed after `sm config set activeProvider <id>`
|
|
12274
12449
|
* succeeds. The lens change atomically drops the scan_* zone (per
|
|
@@ -12665,7 +12840,7 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
12665
12840
|
key = Option4.String({ required: true });
|
|
12666
12841
|
value = Option4.String({ required: true });
|
|
12667
12842
|
yes = Option4.Boolean("--yes", false, {
|
|
12668
|
-
description: "Confirm a
|
|
12843
|
+
description: "Confirm a surface-expanding write: disk access outside the project (scan.referencePaths) or blanket local plugin trust (pluginTrust.projectEnabled)."
|
|
12669
12844
|
});
|
|
12670
12845
|
// CLI orchestrator: each branch is one validation gate (forbidden
|
|
12671
12846
|
// segment / privacy guard / schema violation) or output dispatch.
|
|
@@ -12678,32 +12853,12 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
12678
12853
|
const stderrAnsi = this.ansiFor("stderr");
|
|
12679
12854
|
const errGlyph = stderrAnsi.red("\u2715");
|
|
12680
12855
|
const value = parseCliValue(this.value);
|
|
12681
|
-
if (
|
|
12682
|
-
const
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
if (exposure.expandsSurface && !this.yes) {
|
|
12688
|
-
this.printer.info(
|
|
12689
|
-
tx(CONFIG_TEXTS.privacyGateRequired, {
|
|
12690
|
-
glyph: errGlyph,
|
|
12691
|
-
key: this.key,
|
|
12692
|
-
paths: exposure.exposedPaths.map((p) => ` - ${p}`).join("\n"),
|
|
12693
|
-
hint: stderrAnsi.dim(CONFIG_TEXTS.privacyGateRequiredHint)
|
|
12694
|
-
})
|
|
12695
|
-
);
|
|
12696
|
-
return ExitCode.Error;
|
|
12697
|
-
}
|
|
12698
|
-
if (exposure.expandsSurface) {
|
|
12699
|
-
this.printer.info(
|
|
12700
|
-
tx(CONFIG_TEXTS.privacyGateConfirmed, {
|
|
12701
|
-
glyph: stderrAnsi.dim("\u24D8"),
|
|
12702
|
-
key: this.key,
|
|
12703
|
-
paths: exposure.exposedPaths.map((p) => ` - ${p}`).join("\n")
|
|
12704
|
-
})
|
|
12705
|
-
);
|
|
12706
|
-
}
|
|
12856
|
+
if (this.key === "pluginTrust.projectEnabled") {
|
|
12857
|
+
const trustGate = this.#applyTrustGate(value, ctx.cwd, errGlyph, stderrAnsi);
|
|
12858
|
+
if (trustGate !== null) return trustGate;
|
|
12859
|
+
} else if (PRIVACY_SENSITIVE_KEYS.has(this.key)) {
|
|
12860
|
+
const pathGate = this.#applyPathGate(value, ctx.cwd, errGlyph, stderrAnsi);
|
|
12861
|
+
if (pathGate !== null) return pathGate;
|
|
12707
12862
|
}
|
|
12708
12863
|
if (this.key === "activeProvider" && typeof value === "string") {
|
|
12709
12864
|
const known = new Set(builtIns().providers.map((p) => p.id));
|
|
@@ -12781,6 +12936,58 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
12781
12936
|
}
|
|
12782
12937
|
return ExitCode.Ok;
|
|
12783
12938
|
}
|
|
12939
|
+
/**
|
|
12940
|
+
* Disk-access privacy gate for `scan.referencePaths`-style keys.
|
|
12941
|
+
* Returns an exit code to bail with (gate refused) or `null` to
|
|
12942
|
+
* proceed. On a confirmed (`--yes`) expansion it prints the receipt
|
|
12943
|
+
* and returns `null`.
|
|
12944
|
+
*/
|
|
12945
|
+
#applyPathGate(value, cwd, errGlyph, stderrAnsi) {
|
|
12946
|
+
const exposure = projectPathExposure({ key: this.key, value, cwd });
|
|
12947
|
+
if (!exposure.expandsSurface) return null;
|
|
12948
|
+
if (!this.yes) {
|
|
12949
|
+
this.printer.info(
|
|
12950
|
+
tx(CONFIG_TEXTS.privacyGateRequired, {
|
|
12951
|
+
glyph: errGlyph,
|
|
12952
|
+
key: this.key,
|
|
12953
|
+
paths: exposure.exposedPaths.map((p) => ` - ${p}`).join("\n"),
|
|
12954
|
+
hint: stderrAnsi.dim(CONFIG_TEXTS.privacyGateRequiredHint)
|
|
12955
|
+
})
|
|
12956
|
+
);
|
|
12957
|
+
return ExitCode.Error;
|
|
12958
|
+
}
|
|
12959
|
+
this.printer.info(
|
|
12960
|
+
tx(CONFIG_TEXTS.privacyGateConfirmed, {
|
|
12961
|
+
glyph: stderrAnsi.dim("\u24D8"),
|
|
12962
|
+
key: this.key,
|
|
12963
|
+
paths: exposure.exposedPaths.map((p) => ` - ${p}`).join("\n")
|
|
12964
|
+
})
|
|
12965
|
+
);
|
|
12966
|
+
return null;
|
|
12967
|
+
}
|
|
12968
|
+
/**
|
|
12969
|
+
* Code-execution-surface gate for `pluginTrust.projectEnabled`.
|
|
12970
|
+
* Turning the local opt-in ON trusts every plugin the project enables,
|
|
12971
|
+
* so it requires `--yes`. Returns an exit code to bail with, or `null`
|
|
12972
|
+
* to proceed (on a confirmed expansion it prints the receipt).
|
|
12973
|
+
*/
|
|
12974
|
+
#applyTrustGate(value, cwd, errGlyph, stderrAnsi) {
|
|
12975
|
+
const exposure = projectTrustExposure({ value, cwd });
|
|
12976
|
+
if (!exposure.expandsSurface) return null;
|
|
12977
|
+
if (!this.yes) {
|
|
12978
|
+
this.printer.info(
|
|
12979
|
+
tx(CONFIG_TEXTS.trustGateRequired, {
|
|
12980
|
+
glyph: errGlyph,
|
|
12981
|
+
hint: stderrAnsi.dim(CONFIG_TEXTS.trustGateRequiredHint)
|
|
12982
|
+
})
|
|
12983
|
+
);
|
|
12984
|
+
return ExitCode.Error;
|
|
12985
|
+
}
|
|
12986
|
+
this.printer.info(
|
|
12987
|
+
tx(CONFIG_TEXTS.trustGateConfirmed, { glyph: stderrAnsi.dim("\u24D8") })
|
|
12988
|
+
);
|
|
12989
|
+
return null;
|
|
12990
|
+
}
|
|
12784
12991
|
/**
|
|
12785
12992
|
* Side effect of `sm config set activeProvider <id>`, atomically
|
|
12786
12993
|
* drops the `scan_*` zone so the persisted graph never reflects the
|
|
@@ -13101,7 +13308,7 @@ function grantFixturePluginTrust(scope, binary, env) {
|
|
|
13101
13308
|
const db = new DatabaseSync7(dbPath);
|
|
13102
13309
|
try {
|
|
13103
13310
|
const stmt = db.prepare(
|
|
13104
|
-
"INSERT INTO config_plugins (plugin_id,
|
|
13311
|
+
"INSERT INTO config_plugins (plugin_id, trusted, updated_at) VALUES (?, 1, 0) ON CONFLICT(plugin_id) DO UPDATE SET trusted = 1"
|
|
13105
13312
|
);
|
|
13106
13313
|
for (const id of ids) stmt.run(id);
|
|
13107
13314
|
} finally {
|
|
@@ -17185,7 +17392,7 @@ function classifyLinkSource(source, shortIdToQualified, cachedQualifiedIds, appl
|
|
|
17185
17392
|
}
|
|
17186
17393
|
|
|
17187
17394
|
// kernel/orchestrator/node-identifiers.ts
|
|
17188
|
-
import { posix as
|
|
17395
|
+
import { posix as pathPosix5 } from "path";
|
|
17189
17396
|
function deriveNodeIdentifiers(node, kindDescriptor) {
|
|
17190
17397
|
const sources = kindDescriptor?.identifiers;
|
|
17191
17398
|
if (!sources || sources.length === 0) return [];
|
|
@@ -17209,16 +17416,16 @@ function readFrontmatterName(node) {
|
|
|
17209
17416
|
return raw.length > 0 ? raw : null;
|
|
17210
17417
|
}
|
|
17211
17418
|
function readFilenameBasename(node) {
|
|
17212
|
-
const base =
|
|
17419
|
+
const base = pathPosix5.basename(node.path);
|
|
17213
17420
|
if (!base) return null;
|
|
17214
|
-
const ext =
|
|
17421
|
+
const ext = pathPosix5.extname(base);
|
|
17215
17422
|
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
17216
17423
|
return stem.length > 0 ? stem : null;
|
|
17217
17424
|
}
|
|
17218
17425
|
function readDirname(node) {
|
|
17219
|
-
const dir =
|
|
17426
|
+
const dir = pathPosix5.dirname(node.path);
|
|
17220
17427
|
if (!dir || dir === "." || dir === "/") return null;
|
|
17221
|
-
const base =
|
|
17428
|
+
const base = pathPosix5.basename(dir);
|
|
17222
17429
|
return base.length > 0 ? base : null;
|
|
17223
17430
|
}
|
|
17224
17431
|
function collectNameCollisions(nodes, kindRegistry) {
|
|
@@ -17315,7 +17522,7 @@ function lookupAllowedKinds(link, _indexes, ctx) {
|
|
|
17315
17522
|
}
|
|
17316
17523
|
function stripTriggerSigil(normalized) {
|
|
17317
17524
|
if (!normalized) return null;
|
|
17318
|
-
const trimmed = normalized.replace(/^[
|
|
17525
|
+
const trimmed = normalized.replace(/^[/@$]/, "").trim();
|
|
17319
17526
|
return trimmed.length === 0 ? null : trimmed;
|
|
17320
17527
|
}
|
|
17321
17528
|
function indexNode(node, ctx, byName) {
|
|
@@ -21780,6 +21987,23 @@ var PLUGINS_TEXTS = {
|
|
|
21780
21987
|
toggleAppliedSingle: "{{verbPast}}: {{id}}\n",
|
|
21781
21988
|
toggleAppliedManyHeader: "{{verbPast}}: {{count}} extension(s)\n",
|
|
21782
21989
|
toggleAppliedManyRow: " - {{id}}\n",
|
|
21990
|
+
// --- trust / untrust -------------------------------------------------
|
|
21991
|
+
/**
|
|
21992
|
+
* Receipt printed after `sm plugins trust|untrust`. `verbPast` is
|
|
21993
|
+
* `trusted` / `untrusted`. Trust is per-plugin (bare id), so the rows
|
|
21994
|
+
* carry plugin ids, not qualified extension ids.
|
|
21995
|
+
*/
|
|
21996
|
+
trustAppliedSingle: "{{verbPast}}: {{id}}\n",
|
|
21997
|
+
trustAppliedManyHeader: "{{verbPast}}: {{count}} plugin(s)\n",
|
|
21998
|
+
trustAppliedManyRow: " - {{id}}\n",
|
|
21999
|
+
/**
|
|
22000
|
+
* Rejection when a trust verb targets a built-in (or host-locked) id.
|
|
22001
|
+
* Those are never import-trust-gated, so a trust grant is meaningless.
|
|
22002
|
+
*/
|
|
22003
|
+
trustBuiltInRejected: '{{glyph}} Plugin "{{id}}" is a built-in (or host-locked) and is never import-trust-gated.\n {{hint}}\n',
|
|
22004
|
+
trustBuiltInRejectedHint: "Import trust applies only to project-local drop-in plugins under .skill-map/plugins/.",
|
|
22005
|
+
/** `--all` found no project-local drop-in plugins to act on. */
|
|
22006
|
+
trustNoPlugins: "No project-local plugins discovered to {{verb}}.\n",
|
|
21783
22007
|
/**
|
|
21784
22008
|
* Macro expansion summary printed on stderr before the confirm
|
|
21785
22009
|
* prompt (or before the `--yes` rejection). The block lists every
|
|
@@ -21911,7 +22135,7 @@ var PLUGINS_TEXTS = {
|
|
|
21911
22135
|
* Success block printed after scaffolding. Kind-agnostic (the main stub
|
|
21912
22136
|
* path is interpolated). Follows the no-em-dash rule across every line.
|
|
21913
22137
|
*/
|
|
21914
|
-
createSuccess: "Created {{targetDir}}\nNext:\n - Edit {{mainFile}}\n - Run sm plugins doctor to confirm it loads\n - sm plugins slots list: browse slots and input-types\n",
|
|
22138
|
+
createSuccess: "Created {{targetDir}}\nNext:\n - Edit {{mainFile}}\n - Run sm plugins doctor to confirm it loads\n - Run sm plugins trust {{pluginId}} to let its code run (project-local plugins are untrusted until you allow them)\n - sm plugins slots list: browse slots and input-types\n",
|
|
21915
22139
|
// --- slots list verb -------------------------------------------------
|
|
21916
22140
|
/** Section header for the view-slots catalogue. */
|
|
21917
22141
|
slotsListHeaderViewSlots: " View slots ({{count}})\n",
|
|
@@ -21953,12 +22177,7 @@ function resolveSearchPaths2(opts, cwd) {
|
|
|
21953
22177
|
async function buildResolver() {
|
|
21954
22178
|
const ctx = defaultRuntimeContext();
|
|
21955
22179
|
const { effective: cfg } = loadConfig({ cwd: ctx.cwd });
|
|
21956
|
-
|
|
21957
|
-
const dbOverrides = await tryWithSqlite(
|
|
21958
|
-
{ databasePath: dbPath, autoBackup: false },
|
|
21959
|
-
(adapter) => adapter.pluginConfig.loadOverrideMap()
|
|
21960
|
-
) ?? /* @__PURE__ */ new Map();
|
|
21961
|
-
return makeEnabledResolver(cfg, dbOverrides);
|
|
22180
|
+
return makeEnabledResolver(cfg);
|
|
21962
22181
|
}
|
|
21963
22182
|
async function loadAll(opts) {
|
|
21964
22183
|
const ctx = defaultRuntimeContext();
|
|
@@ -22954,6 +23173,9 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
22954
23173
|
yes = Option25.Boolean("--yes,-y", false, {
|
|
22955
23174
|
description: "Skip the interactive confirm when a bare plugin id (or --all) fans the toggle out across multiple extensions."
|
|
22956
23175
|
});
|
|
23176
|
+
local = Option25.Boolean("--local", false, {
|
|
23177
|
+
description: "Write the enable toggle to the gitignored settings.local.json (per-checkout) instead of the team-shared settings.json."
|
|
23178
|
+
});
|
|
22957
23179
|
ids = Option25.Rest({ name: "ids" });
|
|
22958
23180
|
async toggle(enabled) {
|
|
22959
23181
|
const verb = enabled ? "enable" : "disable";
|
|
@@ -23121,20 +23343,25 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
23121
23343
|
return ExitCode.NotFound;
|
|
23122
23344
|
}
|
|
23123
23345
|
/**
|
|
23124
|
-
* Persist every qualified id in
|
|
23125
|
-
*
|
|
23126
|
-
*
|
|
23127
|
-
*
|
|
23128
|
-
*
|
|
23346
|
+
* Persist the per-extension `enabled` toggle for every qualified id in
|
|
23347
|
+
* the config layers (`plugins.<plugin>.extensions.<ext>.enabled`),
|
|
23348
|
+
* targeting `settings.json` by default or `settings.local.json` with
|
|
23349
|
+
* `--local`. On disable, also purge the plugin's `scan_contributions`
|
|
23350
|
+
* rows immediately (matches the BFF route, see
|
|
23351
|
+
* `server/routes/plugins.ts:applyChangeToAdapter`). Every key is
|
|
23352
|
+
* `<plugin>/<ext>` shape so both the config dot-path and the
|
|
23353
|
+
* contribution purge split into `(pluginId, extensionId)` cleanly.
|
|
23129
23354
|
*/
|
|
23130
23355
|
async #persistKeys(keys, enabled) {
|
|
23131
23356
|
const ctx = defaultRuntimeContext();
|
|
23357
|
+
const target = this.local ? "project-local" : "project";
|
|
23358
|
+
for (const id of keys) {
|
|
23359
|
+
writeConfigValue(toEnableConfigKey(id), enabled, { target, cwd: ctx.cwd });
|
|
23360
|
+
}
|
|
23361
|
+
if (enabled) return;
|
|
23132
23362
|
const dbPath = resolveDbPath({ db: void 0, cwd: ctx.cwd });
|
|
23133
23363
|
await withSqlite({ databasePath: dbPath, autoBackup: false }, async (adapter) => {
|
|
23134
|
-
for (const id of keys)
|
|
23135
|
-
await adapter.pluginConfig.set(id, enabled);
|
|
23136
|
-
if (!enabled) await purgeContributionsFor(adapter, id);
|
|
23137
|
-
}
|
|
23364
|
+
for (const id of keys) await purgeContributionsFor(adapter, id);
|
|
23138
23365
|
});
|
|
23139
23366
|
}
|
|
23140
23367
|
#renderSuccess(keys, enabled) {
|
|
@@ -23175,17 +23402,23 @@ async function purgeContributionsFor(adapter, id) {
|
|
|
23175
23402
|
}
|
|
23176
23403
|
await adapter.contributions.purgeByPlugin(id.slice(0, slash), id.slice(slash + 1));
|
|
23177
23404
|
}
|
|
23405
|
+
function toEnableConfigKey(id) {
|
|
23406
|
+
const slash = id.indexOf("/");
|
|
23407
|
+
if (slash < 0) return `plugins.${id}.enabled`;
|
|
23408
|
+
return `plugins.${id.slice(0, slash)}.extensions.${id.slice(slash + 1)}.enabled`;
|
|
23409
|
+
}
|
|
23178
23410
|
var PluginsEnableCommand = class extends TogglePluginsBase {
|
|
23179
23411
|
static paths = [["plugins", "enable"]];
|
|
23180
23412
|
static usage = Command26.Usage({
|
|
23181
23413
|
category: "Plugins",
|
|
23182
|
-
description: "Enable one or more extensions (or --all). Persists in
|
|
23414
|
+
description: "Enable one or more extensions (or --all). Persists the per-extension enabled in the config layers.",
|
|
23183
23415
|
details: `
|
|
23184
|
-
Writes
|
|
23185
|
-
extension id
|
|
23186
|
-
|
|
23187
|
-
|
|
23188
|
-
|
|
23416
|
+
Writes plugins.<plugin>.extensions.<ext>.enabled=true per qualified
|
|
23417
|
+
extension id to the team-shared settings.json (or settings.local.json
|
|
23418
|
+
with --local). This is the OPERATIONAL axis only; it does NOT grant
|
|
23419
|
+
import trust for a project-local plugin (use sm plugins trust).
|
|
23420
|
+
Use sm plugins disable to flip; sm config reset
|
|
23421
|
+
plugins.<plugin>.extensions.<ext>.enabled drops the override.
|
|
23189
23422
|
|
|
23190
23423
|
Accepts qualified ids (\`claude/at-directive\`) and bare plugin
|
|
23191
23424
|
ids (\`claude\`, which fans the toggle out across every extension
|
|
@@ -23207,10 +23440,11 @@ var PluginsDisableCommand = class extends TogglePluginsBase {
|
|
|
23207
23440
|
static paths = [["plugins", "disable"]];
|
|
23208
23441
|
static usage = Command26.Usage({
|
|
23209
23442
|
category: "Plugins",
|
|
23210
|
-
description: "Disable one or more extensions (or --all). Persists in
|
|
23443
|
+
description: "Disable one or more extensions (or --all). Persists the per-extension enabled in the config layers; does not delete files.",
|
|
23211
23444
|
details: `
|
|
23212
|
-
Writes
|
|
23213
|
-
extension id
|
|
23445
|
+
Writes plugins.<plugin>.extensions.<ext>.enabled=false per qualified
|
|
23446
|
+
extension id to the team-shared settings.json (or settings.local.json
|
|
23447
|
+
with --local). Discovery still surfaces the plugin in
|
|
23214
23448
|
sm plugins list, but with status=disabled; the kernel will not
|
|
23215
23449
|
run any of its disabled extensions.
|
|
23216
23450
|
|
|
@@ -23259,10 +23493,176 @@ function resolveBareToggle(id, catalogue) {
|
|
|
23259
23493
|
};
|
|
23260
23494
|
}
|
|
23261
23495
|
|
|
23496
|
+
// cli/commands/plugins/trust.ts
|
|
23497
|
+
import { Command as Command27, Option as Option26 } from "clipanion";
|
|
23498
|
+
var TrustPluginsBase = class extends SmCommand {
|
|
23499
|
+
all = Option26.Boolean("--all", false);
|
|
23500
|
+
ids = Option26.Rest({ name: "ids" });
|
|
23501
|
+
async applyTrust(trusted) {
|
|
23502
|
+
const verb = trusted ? "trust" : "untrust";
|
|
23503
|
+
const stderrAnsi = this.ansiFor("stderr");
|
|
23504
|
+
const argError = this.#validateArgs(stderrAnsi, verb);
|
|
23505
|
+
if (argError !== null) return argError;
|
|
23506
|
+
const plugins = await loadAll({ pluginDir: void 0 });
|
|
23507
|
+
const discoveredIds = new Set(plugins.map((p) => p.id));
|
|
23508
|
+
const resolved = this.#resolvePluginIds(plugins, discoveredIds, verb, stderrAnsi);
|
|
23509
|
+
if (typeof resolved === "number") return resolved;
|
|
23510
|
+
if (resolved.length === 0) {
|
|
23511
|
+
this.printer.info(tx(PLUGINS_TEXTS.trustNoPlugins, { verb }));
|
|
23512
|
+
return ExitCode.Ok;
|
|
23513
|
+
}
|
|
23514
|
+
await this.#persist(resolved, trusted);
|
|
23515
|
+
this.#renderSuccess(resolved, trusted);
|
|
23516
|
+
return ExitCode.Ok;
|
|
23517
|
+
}
|
|
23518
|
+
/**
|
|
23519
|
+
* `--all` vs `<id>...` mutex check (one must be present, not both).
|
|
23520
|
+
* Reuses the toggle family's two-line rejection blocks so trust /
|
|
23521
|
+
* enable read in parallel.
|
|
23522
|
+
*/
|
|
23523
|
+
#validateArgs(ansi, verb) {
|
|
23524
|
+
const errGlyph = ansi.red("\u2715");
|
|
23525
|
+
if (this.all && this.ids.length > 0) {
|
|
23526
|
+
this.printer.error(
|
|
23527
|
+
tx(PLUGINS_TEXTS.toggleBothIdAndAll, {
|
|
23528
|
+
glyph: errGlyph,
|
|
23529
|
+
hint: ansi.dim(tx(PLUGINS_TEXTS.toggleBothIdAndAllHint, { verb }))
|
|
23530
|
+
})
|
|
23531
|
+
);
|
|
23532
|
+
return ExitCode.Error;
|
|
23533
|
+
}
|
|
23534
|
+
if (!this.all && this.ids.length === 0) {
|
|
23535
|
+
this.printer.error(
|
|
23536
|
+
tx(PLUGINS_TEXTS.toggleNeitherIdNorAll, {
|
|
23537
|
+
glyph: errGlyph,
|
|
23538
|
+
hint: ansi.dim(tx(PLUGINS_TEXTS.toggleNeitherIdNorAllHint, { verb }))
|
|
23539
|
+
})
|
|
23540
|
+
);
|
|
23541
|
+
return ExitCode.Error;
|
|
23542
|
+
}
|
|
23543
|
+
return null;
|
|
23544
|
+
}
|
|
23545
|
+
/**
|
|
23546
|
+
* Resolve `<id>...` (or `--all`) into the deduped set of BARE plugin
|
|
23547
|
+
* ids to write. A qualified `<plugin>/<ext>` collapses to its plugin.
|
|
23548
|
+
* The first unresolvable id (built-in / host-locked, or unknown)
|
|
23549
|
+
* aborts the whole batch before any write so the operator never lands
|
|
23550
|
+
* in a partial state.
|
|
23551
|
+
*/
|
|
23552
|
+
#resolvePluginIds(_plugins, discoveredIds, _verb, ansi) {
|
|
23553
|
+
if (this.all) {
|
|
23554
|
+
return [...discoveredIds];
|
|
23555
|
+
}
|
|
23556
|
+
const out = [];
|
|
23557
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23558
|
+
for (const rawId of this.ids) {
|
|
23559
|
+
const bare = collapseToPluginId(rawId);
|
|
23560
|
+
if (isBuiltInOrLocked(bare)) {
|
|
23561
|
+
this.printer.error(
|
|
23562
|
+
tx(PLUGINS_TEXTS.trustBuiltInRejected, {
|
|
23563
|
+
glyph: ansi.red("\u2715"),
|
|
23564
|
+
id: sanitizeForTerminal(bare),
|
|
23565
|
+
hint: ansi.dim(PLUGINS_TEXTS.trustBuiltInRejectedHint)
|
|
23566
|
+
})
|
|
23567
|
+
);
|
|
23568
|
+
return ExitCode.NotFound;
|
|
23569
|
+
}
|
|
23570
|
+
if (!discoveredIds.has(bare)) {
|
|
23571
|
+
this.printer.error(
|
|
23572
|
+
tx(PLUGINS_TEXTS.pluginNotFound, {
|
|
23573
|
+
glyph: ansi.red("\u2715"),
|
|
23574
|
+
id: sanitizeForTerminal(bare),
|
|
23575
|
+
hint: ansi.dim(PLUGINS_TEXTS.pluginNotFoundHint)
|
|
23576
|
+
})
|
|
23577
|
+
);
|
|
23578
|
+
return ExitCode.NotFound;
|
|
23579
|
+
}
|
|
23580
|
+
if (seen.has(bare)) continue;
|
|
23581
|
+
seen.add(bare);
|
|
23582
|
+
out.push(bare);
|
|
23583
|
+
}
|
|
23584
|
+
return out;
|
|
23585
|
+
}
|
|
23586
|
+
/**
|
|
23587
|
+
* Write the trust grant for every resolved bare plugin id. Single
|
|
23588
|
+
* SQLite open for the whole batch. `trusted` true grants import trust,
|
|
23589
|
+
* false revokes it (the next scan / restart reverts the plugin to
|
|
23590
|
+
* discovered-but-unexecuted).
|
|
23591
|
+
*/
|
|
23592
|
+
async #persist(pluginIds, trusted) {
|
|
23593
|
+
const ctx = defaultRuntimeContext();
|
|
23594
|
+
const dbPath = resolveDbPath({ db: void 0, cwd: ctx.cwd });
|
|
23595
|
+
await withSqlite({ databasePath: dbPath, autoBackup: false }, async (adapter) => {
|
|
23596
|
+
for (const id of pluginIds) await adapter.trust.set(id, trusted);
|
|
23597
|
+
});
|
|
23598
|
+
}
|
|
23599
|
+
#renderSuccess(pluginIds, trusted) {
|
|
23600
|
+
const verbPast = trusted ? "trusted" : "untrusted";
|
|
23601
|
+
if (pluginIds.length === 1) {
|
|
23602
|
+
this.printer.data(tx(PLUGINS_TEXTS.trustAppliedSingle, { verbPast, id: pluginIds[0] }));
|
|
23603
|
+
return;
|
|
23604
|
+
}
|
|
23605
|
+
this.printer.data(
|
|
23606
|
+
tx(PLUGINS_TEXTS.trustAppliedManyHeader, { verbPast, count: pluginIds.length })
|
|
23607
|
+
);
|
|
23608
|
+
for (const id of pluginIds) {
|
|
23609
|
+
this.printer.data(tx(PLUGINS_TEXTS.trustAppliedManyRow, { id }));
|
|
23610
|
+
}
|
|
23611
|
+
}
|
|
23612
|
+
};
|
|
23613
|
+
function collapseToPluginId(id) {
|
|
23614
|
+
const slash = id.indexOf("/");
|
|
23615
|
+
return slash < 0 ? id : id.slice(0, slash);
|
|
23616
|
+
}
|
|
23617
|
+
function isBuiltInOrLocked(id) {
|
|
23618
|
+
if (isPluginLocked(id)) return true;
|
|
23619
|
+
return builtInPlugins.some((p) => p.id === id);
|
|
23620
|
+
}
|
|
23621
|
+
var PluginsTrustCommand = class extends TrustPluginsBase {
|
|
23622
|
+
static paths = [["plugins", "trust"]];
|
|
23623
|
+
static usage = Command27.Usage({
|
|
23624
|
+
category: "Plugins",
|
|
23625
|
+
description: "Grant LOCAL import trust to one or more project-local plugins (or --all). Persists in the config_plugins trust store.",
|
|
23626
|
+
details: `
|
|
23627
|
+
Records this machine's consent to import and run the plugin's code.
|
|
23628
|
+
Trust is the SECURITY axis, distinct from enable: a project-local
|
|
23629
|
+
plugin runs only when it is BOTH enabled (config) and trusted (this
|
|
23630
|
+
DB store). Per-plugin (bare id); a qualified <plugin>/<ext> collapses
|
|
23631
|
+
to its plugin. Local only, never committed, so it cannot travel in a
|
|
23632
|
+
clone.
|
|
23633
|
+
|
|
23634
|
+
Accepts one or more ids, or --all (every discovered drop-in plugin).
|
|
23635
|
+
Batches are all-or-nothing: a built-in / host-locked / unknown id
|
|
23636
|
+
aborts before any write. Repeated ids are deduped. Granting trust
|
|
23637
|
+
lets an enabled plugin's code import on the next scan / sm serve
|
|
23638
|
+
restart.
|
|
23639
|
+
`
|
|
23640
|
+
});
|
|
23641
|
+
async run() {
|
|
23642
|
+
return this.applyTrust(true);
|
|
23643
|
+
}
|
|
23644
|
+
};
|
|
23645
|
+
var PluginsUntrustCommand = class extends TrustPluginsBase {
|
|
23646
|
+
static paths = [["plugins", "untrust"]];
|
|
23647
|
+
static usage = Command27.Usage({
|
|
23648
|
+
category: "Plugins",
|
|
23649
|
+
description: "Revoke LOCAL import trust from one or more project-local plugins (or --all). Does not delete files or change enable state.",
|
|
23650
|
+
details: `
|
|
23651
|
+
Drops the plugin's config_plugins trust row, so it reverts to
|
|
23652
|
+
discovered-but-unexecuted on the next scan / restart. Does NOT change
|
|
23653
|
+
the enable state and does NOT delete the plugin directory. Same
|
|
23654
|
+
id / batch semantics as sm plugins trust.
|
|
23655
|
+
`
|
|
23656
|
+
});
|
|
23657
|
+
async run() {
|
|
23658
|
+
return this.applyTrust(false);
|
|
23659
|
+
}
|
|
23660
|
+
};
|
|
23661
|
+
|
|
23262
23662
|
// cli/commands/plugins/create.ts
|
|
23263
23663
|
import { existsSync as existsSync26, mkdirSync as mkdirSync5, writeFileSync } from "fs";
|
|
23264
23664
|
import { dirname as dirname18, join as join18, resolve as resolve37 } from "path";
|
|
23265
|
-
import { Command as
|
|
23665
|
+
import { Command as Command28, Option as Option27 } from "clipanion";
|
|
23266
23666
|
|
|
23267
23667
|
// cli/commands/plugins/scaffold/action.ts
|
|
23268
23668
|
function indexStub(extId) {
|
|
@@ -23618,6 +24018,7 @@ Generated by \`sm plugins create ${kind} ${pluginId}\`. Edit \`${mainFileRel}\`
|
|
|
23618
24018
|
|
|
23619
24019
|
## Verbs
|
|
23620
24020
|
|
|
24021
|
+
- \`sm plugins trust ${pluginId}\`: allow this project-local plugin's code to run (it is untrusted until you do)
|
|
23621
24022
|
- \`sm plugins list ${pluginId}\`: manifest + extensions + load status
|
|
23622
24023
|
- \`sm plugins doctor\`: full plugin diagnostic
|
|
23623
24024
|
- \`sm scan\`: re-emit contributions / re-run analysis
|
|
@@ -23667,7 +24068,7 @@ function generateScaffold(kind, pluginId, specVersion) {
|
|
|
23667
24068
|
// cli/commands/plugins/create.ts
|
|
23668
24069
|
var PluginsCreateCommand = class extends SmCommand {
|
|
23669
24070
|
static paths = [["plugins", "create"]];
|
|
23670
|
-
static usage =
|
|
24071
|
+
static usage = Command28.Usage({
|
|
23671
24072
|
category: "Plugins",
|
|
23672
24073
|
description: "Scaffold a new plugin directory.",
|
|
23673
24074
|
details: "Emits plugin.json + a per-kind extension stub + README. `<kind>` is one of: provider, extractor, analyzer, action, formatter, hook. The extractor stub ships one view contribution (slot `card.footer.left`) and one setting (`string-list`); edit to taste. Use `sm plugins slots list` to browse the slot / input-type catalog.",
|
|
@@ -23679,10 +24080,10 @@ var PluginsCreateCommand = class extends SmCommand {
|
|
|
23679
24080
|
});
|
|
23680
24081
|
// First positional: the extension kind (required). Declared before
|
|
23681
24082
|
// `pluginId` so clipanion assigns it the first positional slot.
|
|
23682
|
-
kind =
|
|
23683
|
-
pluginId =
|
|
23684
|
-
at =
|
|
23685
|
-
force =
|
|
24083
|
+
kind = Option27.String({ required: true, name: "kind" });
|
|
24084
|
+
pluginId = Option27.String({ required: true, name: "plugin-id" });
|
|
24085
|
+
at = Option27.String("--at", { required: false });
|
|
24086
|
+
force = Option27.Boolean("--force", false);
|
|
23686
24087
|
async run() {
|
|
23687
24088
|
const ansi = this.ansiFor("stderr");
|
|
23688
24089
|
const errGlyph = ansi.red("\u2715");
|
|
@@ -23733,7 +24134,8 @@ var PluginsCreateCommand = class extends SmCommand {
|
|
|
23733
24134
|
this.printer.data(
|
|
23734
24135
|
tx(PLUGINS_TEXTS.createSuccess, {
|
|
23735
24136
|
targetDir: sanitizeForTerminal(targetDir),
|
|
23736
|
-
mainFile
|
|
24137
|
+
mainFile,
|
|
24138
|
+
pluginId: this.pluginId
|
|
23737
24139
|
})
|
|
23738
24140
|
);
|
|
23739
24141
|
return ExitCode.Ok;
|
|
@@ -23741,7 +24143,7 @@ var PluginsCreateCommand = class extends SmCommand {
|
|
|
23741
24143
|
};
|
|
23742
24144
|
|
|
23743
24145
|
// cli/commands/plugins/slots.ts
|
|
23744
|
-
import { Command as
|
|
24146
|
+
import { Command as Command29 } from "clipanion";
|
|
23745
24147
|
|
|
23746
24148
|
// cli/commands/plugins/slots-catalog.ts
|
|
23747
24149
|
var VIEW_SLOTS_CATALOG = [
|
|
@@ -23777,7 +24179,7 @@ var INPUT_TYPES_CATALOG = [
|
|
|
23777
24179
|
// cli/commands/plugins/slots.ts
|
|
23778
24180
|
var PluginsSlotsListCommand = class extends SmCommand {
|
|
23779
24181
|
static paths = [["plugins", "slots", "list"]];
|
|
23780
|
-
static usage =
|
|
24182
|
+
static usage = Command29.Usage({
|
|
23781
24183
|
category: "Plugins",
|
|
23782
24184
|
description: "Print the closed catalogs of view slots and input-types.",
|
|
23783
24185
|
details: "Read-only. Use this when picking a slot / input-type for a new plugin."
|
|
@@ -23826,15 +24228,15 @@ var PluginsSlotsListCommand = class extends SmCommand {
|
|
|
23826
24228
|
};
|
|
23827
24229
|
|
|
23828
24230
|
// cli/commands/plugins/upgrade.ts
|
|
23829
|
-
import { Command as
|
|
24231
|
+
import { Command as Command30, Option as Option28 } from "clipanion";
|
|
23830
24232
|
var PluginsUpgradeCommand = class extends SmCommand {
|
|
23831
24233
|
static paths = [["plugins", "upgrade"]];
|
|
23832
|
-
static usage =
|
|
24234
|
+
static usage = Command30.Usage({
|
|
23833
24235
|
category: "Plugins",
|
|
23834
24236
|
description: "Apply catalog migrations to plugin manifests.",
|
|
23835
24237
|
details: "No migrations registered against catalog v1.0.0 yet; this verb is a no-op today. The structure exists so future slot renames / deprecations land without spec churn."
|
|
23836
24238
|
});
|
|
23837
|
-
pluginId =
|
|
24239
|
+
pluginId = Option28.String({ required: false, name: "plugin-id" });
|
|
23838
24240
|
async run() {
|
|
23839
24241
|
this.printer.data(
|
|
23840
24242
|
"sm plugins upgrade: no migrations registered for catalog v1.0.0.\n All loaded plugins are catalog-current.\n Run `sm plugins doctor` to surface any incompatible-catalog status.\n"
|
|
@@ -23844,7 +24246,7 @@ var PluginsUpgradeCommand = class extends SmCommand {
|
|
|
23844
24246
|
};
|
|
23845
24247
|
|
|
23846
24248
|
// cli/commands/plugins/config.ts
|
|
23847
|
-
import { Command as
|
|
24249
|
+
import { Command as Command31, Option as Option29 } from "clipanion";
|
|
23848
24250
|
|
|
23849
24251
|
// cli/i18n/plugins-config.texts.ts
|
|
23850
24252
|
var PLUGINS_CONFIG_TEXTS = {
|
|
@@ -23885,7 +24287,7 @@ var PLUGINS_CONFIG_TEXTS = {
|
|
|
23885
24287
|
// cli/commands/plugins/config.ts
|
|
23886
24288
|
var PluginsConfigCommand = class extends SmCommand {
|
|
23887
24289
|
static paths = [["plugins", "config"]];
|
|
23888
|
-
static usage =
|
|
24290
|
+
static usage = Command31.Usage({
|
|
23889
24291
|
category: "Plugins",
|
|
23890
24292
|
description: "Read or write an extension's declared settings.",
|
|
23891
24293
|
details: `
|
|
@@ -23900,13 +24302,13 @@ var PluginsConfigCommand = class extends SmCommand {
|
|
|
23900
24302
|
Secret values are shown as <redacted>. Run \`sm scan\` to apply.
|
|
23901
24303
|
`
|
|
23902
24304
|
});
|
|
23903
|
-
id =
|
|
23904
|
-
settingId =
|
|
23905
|
-
value =
|
|
23906
|
-
reset =
|
|
24305
|
+
id = Option29.String({ required: true });
|
|
24306
|
+
settingId = Option29.String({ required: false });
|
|
24307
|
+
value = Option29.String({ required: false });
|
|
24308
|
+
reset = Option29.Boolean("--reset", false, {
|
|
23907
24309
|
description: "Remove the override for <settingId> so the manifest default applies."
|
|
23908
24310
|
});
|
|
23909
|
-
pluginDir =
|
|
24311
|
+
pluginDir = Option29.String("--plugin-dir", { required: false });
|
|
23910
24312
|
// Read-only when listing; the write / reset paths emit their own
|
|
23911
24313
|
// receipt. `sm config` exempts the config family from "done in <…>";
|
|
23912
24314
|
// mirror that here for the read path. The write path keeps the line.
|
|
@@ -24219,6 +24621,8 @@ var PLUGIN_COMMANDS = [
|
|
|
24219
24621
|
PluginsDoctorCommand,
|
|
24220
24622
|
PluginsEnableCommand,
|
|
24221
24623
|
PluginsDisableCommand,
|
|
24624
|
+
PluginsTrustCommand,
|
|
24625
|
+
PluginsUntrustCommand,
|
|
24222
24626
|
PluginsCreateCommand,
|
|
24223
24627
|
PluginsSlotsListCommand,
|
|
24224
24628
|
PluginsUpgradeCommand,
|
|
@@ -24228,7 +24632,7 @@ var PLUGIN_COMMANDS = [
|
|
|
24228
24632
|
// cli/commands/refresh.ts
|
|
24229
24633
|
import { readFile as readFile4 } from "fs/promises";
|
|
24230
24634
|
import { resolve as resolve38 } from "path";
|
|
24231
|
-
import { Command as
|
|
24635
|
+
import { Command as Command32, Option as Option30 } from "clipanion";
|
|
24232
24636
|
|
|
24233
24637
|
// cli/i18n/refresh.texts.ts
|
|
24234
24638
|
var REFRESH_TEXTS = {
|
|
@@ -24284,7 +24688,7 @@ var REFRESH_TEXTS = {
|
|
|
24284
24688
|
// cli/commands/refresh.ts
|
|
24285
24689
|
var RefreshCommand = class extends SmCommand {
|
|
24286
24690
|
static paths = [["refresh"]];
|
|
24287
|
-
static usage =
|
|
24691
|
+
static usage = Command32.Usage({
|
|
24288
24692
|
category: "Scan",
|
|
24289
24693
|
description: "Refresh enrichment rows: granular (single node) or batch (every stale row).",
|
|
24290
24694
|
details: `
|
|
@@ -24306,11 +24710,11 @@ var RefreshCommand = class extends SmCommand {
|
|
|
24306
24710
|
["Refresh every node with stale enrichments", "$0 refresh --stale"]
|
|
24307
24711
|
]
|
|
24308
24712
|
});
|
|
24309
|
-
nodePath =
|
|
24310
|
-
stale =
|
|
24713
|
+
nodePath = Option30.String({ name: "node", required: false });
|
|
24714
|
+
stale = Option30.Boolean("--stale", false, {
|
|
24311
24715
|
description: "Refresh every node carrying a stale enrichment row (no-op in this revision; reserved for future Action-prob enrichments)."
|
|
24312
24716
|
});
|
|
24313
|
-
noPlugins =
|
|
24717
|
+
noPlugins = Option30.Boolean("--no-plugins", false, {
|
|
24314
24718
|
description: "Skip drop-in plugin discovery; use only the built-in extractor set."
|
|
24315
24719
|
});
|
|
24316
24720
|
// The remaining cyclomatic count comes from CLI ergonomics that don't
|
|
@@ -24614,7 +25018,7 @@ var IntentionalFailCommand = class extends SmCommand {
|
|
|
24614
25018
|
};
|
|
24615
25019
|
|
|
24616
25020
|
// cli/commands/scan.ts
|
|
24617
|
-
import { Command as
|
|
25021
|
+
import { Command as Command34, Option as Option32 } from "clipanion";
|
|
24618
25022
|
|
|
24619
25023
|
// kernel/util/format-bytes.ts
|
|
24620
25024
|
var UNITS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"];
|
|
@@ -24773,22 +25177,17 @@ var SCAN_TEXTS = {
|
|
|
24773
25177
|
};
|
|
24774
25178
|
|
|
24775
25179
|
// cli/commands/watch.ts
|
|
24776
|
-
import { Command as
|
|
25180
|
+
import { Command as Command33, Option as Option31 } from "clipanion";
|
|
24777
25181
|
|
|
24778
25182
|
// core/watcher/runtime.ts
|
|
24779
25183
|
import { dirname as dirname19, isAbsolute as isAbsolute13, relative as relative9, resolve as resolve39, sep as sep6 } from "path";
|
|
24780
25184
|
|
|
24781
25185
|
// core/runtime/fresh-resolver.ts
|
|
24782
25186
|
async function buildFreshResolver(deps) {
|
|
24783
|
-
|
|
24784
|
-
{ databasePath: deps.databasePath, autoBackup: false },
|
|
24785
|
-
async (adapter) => adapter.pluginConfig.loadOverrideMap()
|
|
24786
|
-
);
|
|
24787
|
-
if (overrides === null) return deps.fallbackResolver;
|
|
24788
|
-
return makeEnabledResolver(deps.effectiveConfig(), overrides);
|
|
25187
|
+
return makeEnabledResolver(deps.effectiveConfig());
|
|
24789
25188
|
}
|
|
24790
|
-
function composeResolver(effectiveConfig
|
|
24791
|
-
return makeEnabledResolver(effectiveConfig
|
|
25189
|
+
function composeResolver(effectiveConfig) {
|
|
25190
|
+
return makeEnabledResolver(effectiveConfig);
|
|
24792
25191
|
}
|
|
24793
25192
|
|
|
24794
25193
|
// core/watcher/i18n/runtime.texts.ts
|
|
@@ -24904,9 +25303,7 @@ function createWatcherRuntime(opts) {
|
|
|
24904
25303
|
const runOnePass = async (changedPaths) => {
|
|
24905
25304
|
notifyBatchStart();
|
|
24906
25305
|
const resolveEnabledOverride = await buildFreshResolver({
|
|
24907
|
-
|
|
24908
|
-
effectiveConfig: () => cfg,
|
|
24909
|
-
fallbackResolver: pluginRuntime.resolveEnabled
|
|
25306
|
+
effectiveConfig: () => cfg
|
|
24910
25307
|
});
|
|
24911
25308
|
const kernel = createKernel();
|
|
24912
25309
|
registerEnabledExtensions(kernel, pluginRuntime, {
|
|
@@ -25370,7 +25767,7 @@ async function runWatchLoop(opts) {
|
|
|
25370
25767
|
}
|
|
25371
25768
|
var WatchCommand = class extends SmCommand {
|
|
25372
25769
|
static paths = [["watch"]];
|
|
25373
|
-
static usage =
|
|
25770
|
+
static usage = Command33.Usage({
|
|
25374
25771
|
category: "Scan",
|
|
25375
25772
|
description: "Watch roots and run an incremental scan after each debounced batch of filesystem events.",
|
|
25376
25773
|
details: `
|
|
@@ -25394,25 +25791,25 @@ var WatchCommand = class extends SmCommand {
|
|
|
25394
25791
|
["Stream ScanResult per batch as ndjson", "$0 watch --json"]
|
|
25395
25792
|
]
|
|
25396
25793
|
});
|
|
25397
|
-
roots =
|
|
25398
|
-
noTokens =
|
|
25794
|
+
roots = Option31.Rest({ name: "roots" });
|
|
25795
|
+
noTokens = Option31.Boolean("--no-tokens", false, {
|
|
25399
25796
|
description: "Skip per-node token counts (cl100k_base BPE)."
|
|
25400
25797
|
});
|
|
25401
|
-
strict =
|
|
25798
|
+
strict = Option31.Boolean("--strict", false, {
|
|
25402
25799
|
description: "Promote frontmatter-validation findings from warn to error inside each batch. Does not change the watcher exit code."
|
|
25403
25800
|
});
|
|
25404
|
-
noPlugins =
|
|
25801
|
+
noPlugins = Option31.Boolean("--no-plugins", false, {
|
|
25405
25802
|
description: "Skip drop-in plugin discovery for the watcher session."
|
|
25406
25803
|
});
|
|
25407
|
-
maxConsecutiveFailures =
|
|
25804
|
+
maxConsecutiveFailures = Option31.String("--max-consecutive-failures", {
|
|
25408
25805
|
required: false,
|
|
25409
25806
|
description: "Shut down with exit 2 after N consecutive batch failures (default 5; 0 disables the breaker)."
|
|
25410
25807
|
});
|
|
25411
|
-
maxScan =
|
|
25808
|
+
maxScan = Option31.String("--max-scan", {
|
|
25412
25809
|
required: false,
|
|
25413
25810
|
description: "Per-batch override of scan.maxScan (default 50000), the WALK-INTAKE ceiling. The scan walks, parses, analyzes, and reference-validates the full corpus up to this number. Bidirectional: raises OR lowers the ceiling. When a batch hits it, additional files are dropped in stable order and the UI surfaces the persistent truncation banner. Validation: integer >= 1."
|
|
25414
25811
|
});
|
|
25415
|
-
maxNodes =
|
|
25812
|
+
maxNodes = Option31.String("--max-nodes", {
|
|
25416
25813
|
required: false,
|
|
25417
25814
|
description: "Per-batch override of scan.maxNodes (default 256), the MAP RENDER cap (pure metadata): it does NOT bound the scan, only the graph projection. Bidirectional: raises OR lowers the render cap. Validation: integer >= 1."
|
|
25418
25815
|
});
|
|
@@ -25499,7 +25896,7 @@ function parseMaxNodesLimit(raw, stderr, noColor) {
|
|
|
25499
25896
|
// cli/commands/scan.ts
|
|
25500
25897
|
var ScanCommand = class extends SmCommand {
|
|
25501
25898
|
static paths = [["scan"]];
|
|
25502
|
-
static usage =
|
|
25899
|
+
static usage = Command34.Usage({
|
|
25503
25900
|
category: "Scan",
|
|
25504
25901
|
description: "Scan roots for markdown nodes, run extractors and analyzers.",
|
|
25505
25902
|
details: `
|
|
@@ -25534,39 +25931,39 @@ var ScanCommand = class extends SmCommand {
|
|
|
25534
25931
|
["What would the next incremental scan persist?", "$0 scan --changed -n --json"]
|
|
25535
25932
|
]
|
|
25536
25933
|
});
|
|
25537
|
-
roots =
|
|
25538
|
-
noBuiltIns =
|
|
25934
|
+
roots = Option32.Rest({ name: "roots" });
|
|
25935
|
+
noBuiltIns = Option32.Boolean("--no-built-ins", false, {
|
|
25539
25936
|
description: "Skip the built-in extension set. Yields a zero-filled ScanResult (kernel-empty-boot parity); skips DB persistence."
|
|
25540
25937
|
});
|
|
25541
|
-
noPlugins =
|
|
25938
|
+
noPlugins = Option32.Boolean("--no-plugins", false, {
|
|
25542
25939
|
description: "Skip drop-in plugin discovery. Only the built-in set runs. Combine with --no-built-ins for a fully empty pipeline."
|
|
25543
25940
|
});
|
|
25544
|
-
noTokens =
|
|
25941
|
+
noTokens = Option32.Boolean("--no-tokens", false, {
|
|
25545
25942
|
description: "Skip per-node token counts (cl100k_base BPE). Leaves node.tokens undefined; spec-valid since the field is optional."
|
|
25546
25943
|
});
|
|
25547
|
-
dryRun =
|
|
25944
|
+
dryRun = Option32.Boolean("-n,--dry-run", false, {
|
|
25548
25945
|
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."
|
|
25549
25946
|
});
|
|
25550
|
-
changed =
|
|
25947
|
+
changed = Option32.Boolean("--changed", false, {
|
|
25551
25948
|
description: "Incremental scan: reuse unchanged nodes from the persisted prior snapshot. Degrades to a full scan if no prior snapshot exists."
|
|
25552
25949
|
});
|
|
25553
|
-
allowEmpty =
|
|
25950
|
+
allowEmpty = Option32.Boolean("--allow-empty", false, {
|
|
25554
25951
|
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."
|
|
25555
25952
|
});
|
|
25556
|
-
strict =
|
|
25953
|
+
strict = Option32.Boolean("--strict", false, {
|
|
25557
25954
|
description: "Promote frontmatter-validation findings from warn to error (exit code 1 on any violation). Overrides scan.strict from config when both are set."
|
|
25558
25955
|
});
|
|
25559
|
-
watch =
|
|
25956
|
+
watch = Option32.Boolean("--watch", false, {
|
|
25560
25957
|
description: "Long-running mode: watch the roots and trigger an incremental scan after each debounced batch of filesystem events. Alias of `sm watch`."
|
|
25561
25958
|
});
|
|
25562
|
-
yes =
|
|
25959
|
+
yes = Option32.Boolean("--yes", false, {
|
|
25563
25960
|
description: "Non-interactive mode. For ambiguous activeProvider auto-detect, multiple provider markers (.claude/, .codex/, AGENTS.md, .cursor/) under the scan tree exit non-zero instead of prompting; set the lens manually via `sm config set activeProvider <id>` and re-run. Also auto-confirms the pre-1.0 schema-drift rebuild (when the DB was written by a different skill-map major.minor it is deleted and regenerated) instead of prompting."
|
|
25564
25961
|
});
|
|
25565
|
-
maxScan =
|
|
25962
|
+
maxScan = Option32.String("--max-scan", {
|
|
25566
25963
|
required: false,
|
|
25567
25964
|
description: "Per-invocation override of `scan.maxScan` (default 50000). The WALK-INTAKE ceiling: the scan walks, parses, analyzes, and reference-validates the full corpus up to this number. Bidirectional: raises OR lowers the ceiling. When the walker hits it, additional files are dropped in stable order and the scan is marked truncated in scan_meta (the UI raises a persistent banner pointing at the .skillmapignore editor in Settings \u2192 Project). Validation: integer >= 1."
|
|
25568
25965
|
});
|
|
25569
|
-
maxNodes =
|
|
25966
|
+
maxNodes = Option32.String("--max-nodes", {
|
|
25570
25967
|
required: false,
|
|
25571
25968
|
description: "Per-invocation override of `scan.maxNodes` (default 256). The MAP RENDER cap (pure metadata): it does NOT bound the scan, only how many nodes the graph view projects onto the canvas. Bidirectional: raises OR lowers the render cap. Validation: integer >= 1."
|
|
25572
25969
|
});
|
|
@@ -25927,10 +26324,10 @@ function capOverrides(caps) {
|
|
|
25927
26324
|
|
|
25928
26325
|
// cli/commands/scan-compare.ts
|
|
25929
26326
|
import { access, readFile as readFile5 } from "fs/promises";
|
|
25930
|
-
import { Command as
|
|
26327
|
+
import { Command as Command35, Option as Option33 } from "clipanion";
|
|
25931
26328
|
var ScanCompareCommand = class extends SmCommand {
|
|
25932
26329
|
static paths = [["scan", "compare-with"]];
|
|
25933
|
-
static usage =
|
|
26330
|
+
static usage = Command35.Usage({
|
|
25934
26331
|
category: "Scan",
|
|
25935
26332
|
description: "Run a fresh scan in memory and emit a delta against the saved ScanResult dump at <dump>. Read-only.",
|
|
25936
26333
|
details: `
|
|
@@ -25958,15 +26355,15 @@ var ScanCompareCommand = class extends SmCommand {
|
|
|
25958
26355
|
["JSON output for tooling", "$0 scan compare-with baseline.json --json"]
|
|
25959
26356
|
]
|
|
25960
26357
|
});
|
|
25961
|
-
dump =
|
|
25962
|
-
roots =
|
|
25963
|
-
noTokens =
|
|
26358
|
+
dump = Option33.String({ required: true });
|
|
26359
|
+
roots = Option33.Rest({ name: "roots" });
|
|
26360
|
+
noTokens = Option33.Boolean("--no-tokens", false, {
|
|
25964
26361
|
description: "Skip per-node token counts during the fresh scan."
|
|
25965
26362
|
});
|
|
25966
|
-
strict =
|
|
26363
|
+
strict = Option33.Boolean("--strict", false, {
|
|
25967
26364
|
description: "Promote layered-config warnings and frontmatter-validation findings from warn to error."
|
|
25968
26365
|
});
|
|
25969
|
-
noPlugins =
|
|
26366
|
+
noPlugins = Option33.Boolean("--no-plugins", false, {
|
|
25970
26367
|
description: "Skip drop-in plugin discovery."
|
|
25971
26368
|
});
|
|
25972
26369
|
// Cyclomatic count comes from CLI ergonomics: 3 distinct try/catch
|
|
@@ -26173,7 +26570,7 @@ function renderDeltaIssues(issues) {
|
|
|
26173
26570
|
// cli/commands/serve.ts
|
|
26174
26571
|
import { spawn as spawn2 } from "child_process";
|
|
26175
26572
|
import { existsSync as existsSync32 } from "fs";
|
|
26176
|
-
import { Command as
|
|
26573
|
+
import { Command as Command36, Option as Option34 } from "clipanion";
|
|
26177
26574
|
|
|
26178
26575
|
// kernel/util/dev-mode.ts
|
|
26179
26576
|
import { sep as sep7 } from "path";
|
|
@@ -26420,6 +26817,14 @@ var SERVER_TEXTS = {
|
|
|
26420
26817
|
pluginsBodyNotJson: "Request body must be valid JSON.",
|
|
26421
26818
|
pluginsBodyNotObject: "Request body must be a JSON object.",
|
|
26422
26819
|
pluginsEnabledRequired: "`enabled` is required and must be a boolean.",
|
|
26820
|
+
pluginsTrustedRequired: "`trusted` is required and must be a boolean.",
|
|
26821
|
+
// 403, trust toggle targeted a built-in (or host-locked) id. Those are
|
|
26822
|
+
// never import-trust-gated, so a trust grant is meaningless. Reuses the
|
|
26823
|
+
// 403 `locked` envelope code per the spec.
|
|
26824
|
+
pluginsTrustBuiltIn: 'Plugin "{{id}}" is a built-in (or host-locked) and is never import-trust-gated.',
|
|
26825
|
+
// 400, the trust route received a qualified `<plugin>/<ext>` id; trust
|
|
26826
|
+
// is per-plugin, so it must be a bare plugin id.
|
|
26827
|
+
pluginsTrustQualifiedRejected: 'Plugin id "{{id}}" contains "/"; import trust is per-plugin, pass the bare plugin id.',
|
|
26423
26828
|
// 400, cascade route rejects qualified ids: the bare-id PATCH is the
|
|
26424
26829
|
// bundle macro endpoint. Anything containing `/` needs the dedicated
|
|
26425
26830
|
// per-extension route below.
|
|
@@ -26482,9 +26887,11 @@ var SERVER_TEXTS = {
|
|
|
26482
26887
|
// silently widen the scan surface.
|
|
26483
26888
|
projectPrefsBodyNotJson: "Request body must be valid JSON.",
|
|
26484
26889
|
projectPrefsBodyNotObject: "Request body must be a JSON object.",
|
|
26485
|
-
projectPrefsBodyEmpty: "Request body must contain `allowSidecarWriters` and/or a `
|
|
26890
|
+
projectPrefsBodyEmpty: "Request body must contain `allowSidecarWriters`, a `scan` block with `referencePaths`, and/or a `pluginTrust` block with `projectEnabled`.",
|
|
26486
26891
|
projectPrefsConfirmNotBoolean: "`confirm` must be a boolean.",
|
|
26487
26892
|
projectPrefsSidecarWritersNotBoolean: "`allowSidecarWriters` must be a boolean.",
|
|
26893
|
+
projectPrefsTrustNotObject: '`pluginTrust` must be an object (e.g. `{"pluginTrust": {"projectEnabled": true}}`).',
|
|
26894
|
+
projectPrefsTrustEnabledNotBoolean: "`pluginTrust.projectEnabled` must be a boolean.",
|
|
26488
26895
|
// Server-stderr advisory after `PATCH /api/project-preferences`
|
|
26489
26896
|
// toggles the committed sidecar-writer policy. Lets the operator see
|
|
26490
26897
|
// the team-shared change land without opening settings.json.
|
|
@@ -26493,6 +26900,12 @@ var SERVER_TEXTS = {
|
|
|
26493
26900
|
projectPrefsListNotArray: "`{{key}}` must be an array of strings.",
|
|
26494
26901
|
projectPrefsListEntryNotString: "`{{key}}` entries must be strings.",
|
|
26495
26902
|
projectPrefsConfirmRequired: "This change opens disk access outside the project: {{paths}}. Re-issue the request with `confirm: true` to proceed.",
|
|
26903
|
+
// 412, turning on the local plugin-trust opt-in. Expands the LOCAL
|
|
26904
|
+
// code-execution surface (every plugin the project enables becomes
|
|
26905
|
+
// trusted), so the route refuses without `confirm: true`.
|
|
26906
|
+
projectPrefsTrustConfirmRequired: "Turning on pluginTrust.projectEnabled trusts every plugin this project enables; their code may then import and run on this machine. Re-issue the request with `confirm: true` to proceed.",
|
|
26907
|
+
// Server-stderr advisory after the local plugin-trust opt-in changes.
|
|
26908
|
+
projectPrefsTrustSet: "project-prefs: pluginTrust.projectEnabled = {{value}}",
|
|
26496
26909
|
projectPrefsPersistFailed: "Could not persist `{{key}}`: {{message}}",
|
|
26497
26910
|
// Returned for every NEW entry that does not resolve to an existing
|
|
26498
26911
|
// directory on disk. The list is comma-separated; pre-existing
|
|
@@ -27667,6 +28080,24 @@ var parsePatchBody = makeBodyValidator(SINGLE_PATCH_BODY_SCHEMA, {
|
|
|
27667
28080
|
"/enabled:type:boolean": SERVER_TEXTS.pluginsEnabledRequired
|
|
27668
28081
|
}
|
|
27669
28082
|
});
|
|
28083
|
+
var TRUST_PATCH_BODY_SCHEMA = {
|
|
28084
|
+
type: "object",
|
|
28085
|
+
additionalProperties: false,
|
|
28086
|
+
required: ["trusted"],
|
|
28087
|
+
properties: {
|
|
28088
|
+
trusted: { type: "boolean" }
|
|
28089
|
+
}
|
|
28090
|
+
};
|
|
28091
|
+
var parseTrustPatchBody = makeBodyValidator(TRUST_PATCH_BODY_SCHEMA, {
|
|
28092
|
+
notJson: SERVER_TEXTS.pluginsBodyNotJson,
|
|
28093
|
+
notObject: SERVER_TEXTS.pluginsBodyNotObject,
|
|
28094
|
+
invalid: SERVER_TEXTS.pluginsTrustedRequired,
|
|
28095
|
+
mapping: {
|
|
28096
|
+
":required:trusted": SERVER_TEXTS.pluginsTrustedRequired,
|
|
28097
|
+
"/trusted:required": SERVER_TEXTS.pluginsTrustedRequired,
|
|
28098
|
+
"/trusted:type:boolean": SERVER_TEXTS.pluginsTrustedRequired
|
|
28099
|
+
}
|
|
28100
|
+
});
|
|
27670
28101
|
var BULK_PATCH_BODY_SCHEMA = {
|
|
27671
28102
|
type: "object",
|
|
27672
28103
|
additionalProperties: false,
|
|
@@ -27712,7 +28143,8 @@ var parseBulkPatchBody = makeBodyValidator(BULK_PATCH_BODY_SCHEMA, {
|
|
|
27712
28143
|
function registerPluginsRoute(app, deps) {
|
|
27713
28144
|
app.get("/api/plugins", async (c) => {
|
|
27714
28145
|
const resolveEnabled = await buildFreshResolver2(deps);
|
|
27715
|
-
const
|
|
28146
|
+
const trust = await loadTrustState(deps);
|
|
28147
|
+
const items = listItems(deps, resolveEnabled, trust);
|
|
27716
28148
|
const errorsByPlugin = await loadRuntimeContributionErrors(deps);
|
|
27717
28149
|
attachRuntimeContributionErrors(items, errorsByPlugin);
|
|
27718
28150
|
return c.json(
|
|
@@ -27771,7 +28203,28 @@ function registerPluginsRoute(app, deps) {
|
|
|
27771
28203
|
});
|
|
27772
28204
|
}
|
|
27773
28205
|
const body = await parsePatchBody(c.req.raw);
|
|
27774
|
-
return await
|
|
28206
|
+
return await persistManyAndProject(c, deps, [qualified], body.enabled);
|
|
28207
|
+
});
|
|
28208
|
+
app.patch("/api/plugins/:id/trust", async (c) => {
|
|
28209
|
+
const id = c.req.param("id");
|
|
28210
|
+
if (id.includes("/")) {
|
|
28211
|
+
throw new HTTPException10(400, {
|
|
28212
|
+
message: tx(SERVER_TEXTS.pluginsTrustQualifiedRejected, { id })
|
|
28213
|
+
});
|
|
28214
|
+
}
|
|
28215
|
+
const handle = findHandle(id, deps);
|
|
28216
|
+
if (!handle) {
|
|
28217
|
+
throw new HTTPException10(404, {
|
|
28218
|
+
message: tx(SERVER_TEXTS.pluginsUnknown, { id })
|
|
28219
|
+
});
|
|
28220
|
+
}
|
|
28221
|
+
if (handle.kind === "built-in" || isPluginLocked(id)) {
|
|
28222
|
+
throw new HTTPException10(403, {
|
|
28223
|
+
message: tx(SERVER_TEXTS.pluginsTrustBuiltIn, { id })
|
|
28224
|
+
});
|
|
28225
|
+
}
|
|
28226
|
+
const body = await parseTrustPatchBody(c.req.raw);
|
|
28227
|
+
return await persistTrustAndProject(c, deps, id, body.trusted);
|
|
27775
28228
|
});
|
|
27776
28229
|
app.patch("/api/plugins", async (c) => {
|
|
27777
28230
|
const { changes } = await parseBulkPatchBody(c.req.raw);
|
|
@@ -27789,13 +28242,21 @@ function registerPluginsRoute(app, deps) {
|
|
|
27789
28242
|
return await persistBulkAndProject(c, deps, changes);
|
|
27790
28243
|
});
|
|
27791
28244
|
}
|
|
27792
|
-
function listItems(deps, resolveEnabled) {
|
|
28245
|
+
function listItems(deps, resolveEnabled, trust) {
|
|
27793
28246
|
const config = deps.configService.effective();
|
|
27794
28247
|
return [
|
|
27795
28248
|
...deps.options.noBuiltIns ? [] : buildBuiltInItems(resolveEnabled, config),
|
|
27796
|
-
...buildDiscoveredItems(deps.pluginRuntime.discovered, deps, resolveEnabled, config)
|
|
28249
|
+
...buildDiscoveredItems(deps.pluginRuntime.discovered, deps, resolveEnabled, config, trust)
|
|
27797
28250
|
];
|
|
27798
28251
|
}
|
|
28252
|
+
async function loadTrustState(deps) {
|
|
28253
|
+
const trustMap = await tryWithSqlite(
|
|
28254
|
+
{ databasePath: deps.options.dbPath, autoBackup: false },
|
|
28255
|
+
(adapter) => adapter.trust.loadTrustMap()
|
|
28256
|
+
) ?? /* @__PURE__ */ new Map();
|
|
28257
|
+
const trustProjectEnabled = deps.configService.effective().pluginTrust?.projectEnabled ?? false;
|
|
28258
|
+
return { trustMap, trustProjectEnabled };
|
|
28259
|
+
}
|
|
27799
28260
|
function buildBuiltInItems(resolveEnabled, config) {
|
|
27800
28261
|
return sortPluginsForPresentation(builtInPlugins).map((plugin) => {
|
|
27801
28262
|
const pluginLocked = isPluginLocked(plugin.id);
|
|
@@ -27833,10 +28294,10 @@ function buildBuiltInItems(resolveEnabled, config) {
|
|
|
27833
28294
|
};
|
|
27834
28295
|
});
|
|
27835
28296
|
}
|
|
27836
|
-
function buildDiscoveredItems(discovered, deps, resolveEnabled, config) {
|
|
27837
|
-
return discovered.map((plugin) => buildDiscoveredItem(plugin, deps, resolveEnabled, config));
|
|
28297
|
+
function buildDiscoveredItems(discovered, deps, resolveEnabled, config, trust) {
|
|
28298
|
+
return discovered.map((plugin) => buildDiscoveredItem(plugin, deps, resolveEnabled, config, trust));
|
|
27838
28299
|
}
|
|
27839
|
-
function buildDiscoveredItem(plugin, deps, resolveEnabled, config) {
|
|
28300
|
+
function buildDiscoveredItem(plugin, deps, resolveEnabled, config, trust) {
|
|
27840
28301
|
const pluginLocked = isPluginLocked(plugin.id);
|
|
27841
28302
|
const extensions = projectExtensionRows(plugin, resolveEnabled, pluginLocked, config);
|
|
27842
28303
|
const optional = optionalDiscoveredFields(plugin, extensions);
|
|
@@ -27848,8 +28309,15 @@ function buildDiscoveredItem(plugin, deps, resolveEnabled, config) {
|
|
|
27848
28309
|
reason: plugin.reason ?? null,
|
|
27849
28310
|
source: classifyPluginSource(plugin.path, deps),
|
|
27850
28311
|
...optional,
|
|
28312
|
+
...discoveredFlags(plugin, pluginLocked, trust)
|
|
28313
|
+
};
|
|
28314
|
+
}
|
|
28315
|
+
function discoveredFlags(plugin, pluginLocked, trust) {
|
|
28316
|
+
const trusted = trust.trustMap.get(plugin.id) === true || trust.trustProjectEnabled;
|
|
28317
|
+
return {
|
|
27851
28318
|
...pluginLocked ? { locked: true } : {},
|
|
27852
|
-
...
|
|
28319
|
+
...trusted ? { trusted: true } : {},
|
|
28320
|
+
...plugin.status === "disabled" && plugin.untrusted !== true ? { startsAsDisabled: true } : {}
|
|
27853
28321
|
};
|
|
27854
28322
|
}
|
|
27855
28323
|
function optionalDiscoveredFields(plugin, extensions) {
|
|
@@ -27941,49 +28409,54 @@ function attachRuntimeContributionErrors(items, errorsByPlugin) {
|
|
|
27941
28409
|
if (errors && errors.length > 0) item.runtimeContributionErrors = errors;
|
|
27942
28410
|
}
|
|
27943
28411
|
}
|
|
27944
|
-
async function
|
|
27945
|
-
const
|
|
28412
|
+
async function persistManyAndProject(c, deps, keys, enabled) {
|
|
28413
|
+
const cwd = deps.runtimeContext.cwd;
|
|
28414
|
+
for (const key of keys) {
|
|
28415
|
+
writeConfigValue(toEnableConfigKey2(key), enabled, { target: "project", cwd });
|
|
28416
|
+
}
|
|
28417
|
+
if (!enabled && keys.length > 0) await purgeContributionsForKeys(deps, keys);
|
|
28418
|
+
if (keys.length > 0) deps.configService.reload();
|
|
28419
|
+
return await projectListResponse(c, deps);
|
|
28420
|
+
}
|
|
28421
|
+
async function persistTrustAndProject(c, deps, pluginId, trusted) {
|
|
28422
|
+
const ok = await tryWithSqlite(
|
|
27946
28423
|
{ databasePath: deps.options.dbPath, autoBackup: false },
|
|
27947
28424
|
async (adapter) => {
|
|
27948
|
-
await
|
|
27949
|
-
return
|
|
28425
|
+
await adapter.trust.set(pluginId, trusted);
|
|
28426
|
+
return true;
|
|
27950
28427
|
}
|
|
27951
28428
|
);
|
|
27952
|
-
|
|
28429
|
+
if (ok === null) {
|
|
28430
|
+
throw new DbMissingError(
|
|
28431
|
+
tx(SERVER_TEXTS.pluginsDbMissing, { path: deps.options.dbPath })
|
|
28432
|
+
);
|
|
28433
|
+
}
|
|
28434
|
+
return await projectListResponse(c, deps);
|
|
27953
28435
|
}
|
|
27954
|
-
|
|
27955
|
-
const
|
|
28436
|
+
function toEnableConfigKey2(id) {
|
|
28437
|
+
const slash = id.indexOf("/");
|
|
28438
|
+
if (slash < 0) return `plugins.${id}.enabled`;
|
|
28439
|
+
return `plugins.${id.slice(0, slash)}.extensions.${id.slice(slash + 1)}.enabled`;
|
|
28440
|
+
}
|
|
28441
|
+
async function purgeContributionsForKeys(deps, keys) {
|
|
28442
|
+
await tryWithSqlite(
|
|
27956
28443
|
{ databasePath: deps.options.dbPath, autoBackup: false },
|
|
27957
28444
|
async (adapter) => {
|
|
27958
28445
|
for (const key of keys) {
|
|
27959
|
-
|
|
28446
|
+
const slash = key.indexOf("/");
|
|
28447
|
+
if (slash < 0) {
|
|
28448
|
+
await adapter.contributions.purgeByPlugin(key);
|
|
28449
|
+
} else {
|
|
28450
|
+
await adapter.contributions.purgeByPlugin(key.slice(0, slash), key.slice(slash + 1));
|
|
28451
|
+
}
|
|
27960
28452
|
}
|
|
27961
|
-
return await adapter.pluginConfig.loadOverrideMap();
|
|
27962
28453
|
}
|
|
27963
28454
|
);
|
|
27964
|
-
return projectListResponse(c, deps, overrides);
|
|
27965
|
-
}
|
|
27966
|
-
async function applyChangeToAdapter(adapter, configKey, enabled) {
|
|
27967
|
-
await adapter.pluginConfig.set(configKey, enabled);
|
|
27968
|
-
if (enabled) return;
|
|
27969
|
-
const slash = configKey.indexOf("/");
|
|
27970
|
-
if (slash < 0) {
|
|
27971
|
-
await adapter.contributions.purgeByPlugin(configKey);
|
|
27972
|
-
return;
|
|
27973
|
-
}
|
|
27974
|
-
await adapter.contributions.purgeByPlugin(
|
|
27975
|
-
configKey.slice(0, slash),
|
|
27976
|
-
configKey.slice(slash + 1)
|
|
27977
|
-
);
|
|
27978
28455
|
}
|
|
27979
|
-
function projectListResponse(c, deps
|
|
27980
|
-
|
|
27981
|
-
|
|
27982
|
-
|
|
27983
|
-
);
|
|
27984
|
-
}
|
|
27985
|
-
const freshResolver = composeResolver2(deps, overrides);
|
|
27986
|
-
const items = listItems(deps, freshResolver);
|
|
28456
|
+
async function projectListResponse(c, deps) {
|
|
28457
|
+
const resolveEnabled = composeResolver2(deps);
|
|
28458
|
+
const trust = await loadTrustState(deps);
|
|
28459
|
+
const items = listItems(deps, resolveEnabled, trust);
|
|
27987
28460
|
return c.json(
|
|
27988
28461
|
buildListEnvelope({
|
|
27989
28462
|
kind: "plugins",
|
|
@@ -28088,27 +28561,26 @@ function handleExtensionSettings(handle, extensionId) {
|
|
|
28088
28561
|
return readManifestSettings(ext?.instance);
|
|
28089
28562
|
}
|
|
28090
28563
|
async function persistBulkAndProject(c, deps, changes) {
|
|
28091
|
-
const
|
|
28092
|
-
|
|
28093
|
-
|
|
28094
|
-
|
|
28095
|
-
|
|
28096
|
-
|
|
28097
|
-
|
|
28098
|
-
|
|
28099
|
-
|
|
28100
|
-
|
|
28101
|
-
|
|
28564
|
+
const { disabledKeys, toggleTouched } = applyBulkEnableWrites(deps, changes);
|
|
28565
|
+
const settingsTouched = persistBulkSettings(deps, changes);
|
|
28566
|
+
if (disabledKeys.length > 0) await purgeContributionsForKeys(deps, disabledKeys);
|
|
28567
|
+
if (toggleTouched || settingsTouched) deps.configService.reload();
|
|
28568
|
+
return await projectListResponse(c, deps);
|
|
28569
|
+
}
|
|
28570
|
+
function applyBulkEnableWrites(deps, changes) {
|
|
28571
|
+
const cwd = deps.runtimeContext.cwd;
|
|
28572
|
+
const disabledKeys = [];
|
|
28573
|
+
let toggleTouched = false;
|
|
28574
|
+
for (const change of changes) {
|
|
28575
|
+
if (change.enabled === void 0) continue;
|
|
28576
|
+
const writeKeys = expandBulkChangeKeys(change, deps);
|
|
28577
|
+
for (const key of writeKeys) {
|
|
28578
|
+
writeConfigValue(toEnableConfigKey2(key), change.enabled, { target: "project", cwd });
|
|
28579
|
+
if (!change.enabled) disabledKeys.push(key);
|
|
28102
28580
|
}
|
|
28103
|
-
|
|
28104
|
-
if (overrides === null) {
|
|
28105
|
-
throw new DbMissingError(
|
|
28106
|
-
tx(SERVER_TEXTS.pluginsDbMissing, { path: deps.options.dbPath })
|
|
28107
|
-
);
|
|
28581
|
+
if (writeKeys.length > 0) toggleTouched = true;
|
|
28108
28582
|
}
|
|
28109
|
-
|
|
28110
|
-
if (settingsTouched) deps.configService.reload();
|
|
28111
|
-
return projectListResponse(c, deps, overrides);
|
|
28583
|
+
return { disabledKeys, toggleTouched };
|
|
28112
28584
|
}
|
|
28113
28585
|
function persistBulkSettings(deps, changes) {
|
|
28114
28586
|
const cwd = deps.runtimeContext.cwd;
|
|
@@ -28143,13 +28615,11 @@ function expandBulkChangeKeys(change, deps) {
|
|
|
28143
28615
|
}
|
|
28144
28616
|
async function buildFreshResolver2(deps) {
|
|
28145
28617
|
return buildFreshResolver({
|
|
28146
|
-
|
|
28147
|
-
effectiveConfig: () => deps.configService.effective(),
|
|
28148
|
-
fallbackResolver: deps.pluginRuntime.resolveEnabled
|
|
28618
|
+
effectiveConfig: () => deps.configService.effective()
|
|
28149
28619
|
});
|
|
28150
28620
|
}
|
|
28151
|
-
function composeResolver2(deps
|
|
28152
|
-
return composeResolver(deps.configService.effective()
|
|
28621
|
+
function composeResolver2(deps) {
|
|
28622
|
+
return composeResolver(deps.configService.effective());
|
|
28153
28623
|
}
|
|
28154
28624
|
function findHandle(id, deps) {
|
|
28155
28625
|
const builtIn = builtInPlugins.find((b) => b.id === id);
|
|
@@ -28467,6 +28937,12 @@ function buildEnvelope3(deps) {
|
|
|
28467
28937
|
cwd,
|
|
28468
28938
|
default: []
|
|
28469
28939
|
}) ?? []
|
|
28940
|
+
},
|
|
28941
|
+
pluginTrust: {
|
|
28942
|
+
projectEnabled: readConfigValue("pluginTrust.projectEnabled", {
|
|
28943
|
+
cwd,
|
|
28944
|
+
default: false
|
|
28945
|
+
}) ?? false
|
|
28470
28946
|
}
|
|
28471
28947
|
};
|
|
28472
28948
|
}
|
|
@@ -28474,8 +28950,32 @@ async function applyPatch3(deps, body) {
|
|
|
28474
28950
|
const cwd = deps.runtimeContext.cwd;
|
|
28475
28951
|
const policyChanged = typeof body.allowSidecarWriters === "boolean" && writeSidecarWritersPolicy(body.allowSidecarWriters, cwd);
|
|
28476
28952
|
const scan = applyScanWrites(body, cwd);
|
|
28953
|
+
const trustChanged = applyTrustWrite(body, cwd);
|
|
28477
28954
|
if (policyChanged || scan.mutated) await maybeRestartWatcher2(deps);
|
|
28478
|
-
if (policyChanged || scan.attempted) deps.configService.reload();
|
|
28955
|
+
if (policyChanged || scan.attempted || trustChanged) deps.configService.reload();
|
|
28956
|
+
}
|
|
28957
|
+
function applyTrustWrite(body, cwd) {
|
|
28958
|
+
const next = body.pluginTrust?.projectEnabled;
|
|
28959
|
+
if (next === void 0) return false;
|
|
28960
|
+
const before = readConfigValue("pluginTrust.projectEnabled", { cwd, default: false }) ?? false;
|
|
28961
|
+
if (before === next) return false;
|
|
28962
|
+
if (projectTrustExposure({ value: next, cwd }).expandsSurface && body.confirm !== true) {
|
|
28963
|
+
throw new HTTPException13(412, {
|
|
28964
|
+
message: SERVER_TEXTS.projectPrefsTrustConfirmRequired
|
|
28965
|
+
});
|
|
28966
|
+
}
|
|
28967
|
+
try {
|
|
28968
|
+
writeConfigValue("pluginTrust.projectEnabled", next, { target: "project-local", cwd });
|
|
28969
|
+
} catch (err) {
|
|
28970
|
+
throw new HTTPException13(400, {
|
|
28971
|
+
message: tx(SERVER_TEXTS.projectPrefsPersistFailed, {
|
|
28972
|
+
key: "pluginTrust.projectEnabled",
|
|
28973
|
+
message: formatErrorMessage(err)
|
|
28974
|
+
})
|
|
28975
|
+
});
|
|
28976
|
+
}
|
|
28977
|
+
log.warn(tx(SERVER_TEXTS.projectPrefsTrustSet, { value: String(next) }));
|
|
28978
|
+
return true;
|
|
28479
28979
|
}
|
|
28480
28980
|
function applyScanWrites(body, cwd) {
|
|
28481
28981
|
const writes = collectWrites(body);
|
|
@@ -28627,7 +29127,11 @@ function isExistingDirectory(entry, cwd) {
|
|
|
28627
29127
|
var PATCH_BODY_SCHEMA3 = {
|
|
28628
29128
|
type: "object",
|
|
28629
29129
|
additionalProperties: false,
|
|
28630
|
-
anyOf: [
|
|
29130
|
+
anyOf: [
|
|
29131
|
+
{ required: ["allowSidecarWriters"] },
|
|
29132
|
+
{ required: ["scan"] },
|
|
29133
|
+
{ required: ["pluginTrust"] }
|
|
29134
|
+
],
|
|
28631
29135
|
properties: {
|
|
28632
29136
|
confirm: { type: "boolean" },
|
|
28633
29137
|
allowSidecarWriters: { type: "boolean" },
|
|
@@ -28641,6 +29145,14 @@ var PATCH_BODY_SCHEMA3 = {
|
|
|
28641
29145
|
items: { type: "string", pattern: "^[^,]+$" }
|
|
28642
29146
|
}
|
|
28643
29147
|
}
|
|
29148
|
+
},
|
|
29149
|
+
pluginTrust: {
|
|
29150
|
+
type: "object",
|
|
29151
|
+
additionalProperties: false,
|
|
29152
|
+
minProperties: 1,
|
|
29153
|
+
properties: {
|
|
29154
|
+
projectEnabled: { type: "boolean" }
|
|
29155
|
+
}
|
|
28644
29156
|
}
|
|
28645
29157
|
}
|
|
28646
29158
|
};
|
|
@@ -28652,6 +29164,9 @@ var parsePatchBody4 = makeBodyValidator(PATCH_BODY_SCHEMA3, {
|
|
|
28652
29164
|
":anyOf": SERVER_TEXTS.projectPrefsBodyEmpty,
|
|
28653
29165
|
"/scan:minProperties": SERVER_TEXTS.projectPrefsBodyEmpty,
|
|
28654
29166
|
"/scan:type:object": SERVER_TEXTS.projectPrefsScanNotObject,
|
|
29167
|
+
"/pluginTrust:minProperties": SERVER_TEXTS.projectPrefsBodyEmpty,
|
|
29168
|
+
"/pluginTrust:type:object": SERVER_TEXTS.projectPrefsTrustNotObject,
|
|
29169
|
+
"/pluginTrust/projectEnabled:type:boolean": SERVER_TEXTS.projectPrefsTrustEnabledNotBoolean,
|
|
28655
29170
|
"/confirm:type:boolean": SERVER_TEXTS.projectPrefsConfirmNotBoolean,
|
|
28656
29171
|
"/allowSidecarWriters:type:boolean": SERVER_TEXTS.projectPrefsSidecarWritersNotBoolean,
|
|
28657
29172
|
"/scan/referencePaths:type:array": tx(SERVER_TEXTS.projectPrefsListNotArray, { key: "scan.referencePaths" }),
|
|
@@ -28694,9 +29209,7 @@ async function buildEnvelope4(deps) {
|
|
|
28694
29209
|
}
|
|
28695
29210
|
async function resolveSelectableProviders(deps) {
|
|
28696
29211
|
const resolveEnabled = await buildFreshResolver({
|
|
28697
|
-
|
|
28698
|
-
effectiveConfig: () => deps.configService.effective(),
|
|
28699
|
-
fallbackResolver: deps.pluginRuntime.resolveEnabled
|
|
29212
|
+
effectiveConfig: () => deps.configService.effective()
|
|
28700
29213
|
});
|
|
28701
29214
|
const selectable = /* @__PURE__ */ new Set();
|
|
28702
29215
|
for (const provider of deps.providers) {
|
|
@@ -29263,9 +29776,7 @@ async function runPersistedScan(c, deps) {
|
|
|
29263
29776
|
}
|
|
29264
29777
|
async function buildBffResolverOverride(deps) {
|
|
29265
29778
|
return buildFreshResolver({
|
|
29266
|
-
|
|
29267
|
-
effectiveConfig: () => deps.configService.effective(),
|
|
29268
|
-
fallbackResolver: deps.pluginRuntime.resolveEnabled
|
|
29779
|
+
effectiveConfig: () => deps.configService.effective()
|
|
29269
29780
|
});
|
|
29270
29781
|
}
|
|
29271
29782
|
async function loadPersistedScanMeta(deps) {
|
|
@@ -30047,6 +30558,7 @@ function presentationOptionals(ui) {
|
|
|
30047
30558
|
if (ui.emoji !== void 0) out.emoji = ui.emoji;
|
|
30048
30559
|
if (ui.icon !== void 0) out.icon = ui.icon;
|
|
30049
30560
|
if (ui.hideChip !== void 0) out.hideChip = ui.hideChip;
|
|
30561
|
+
if (ui.invocationSigil !== void 0) out.invocationSigil = ui.invocationSigil;
|
|
30050
30562
|
return out;
|
|
30051
30563
|
}
|
|
30052
30564
|
function resolveProviderBodyField(read) {
|
|
@@ -30604,7 +31116,7 @@ var SERVE_TEXTS = {
|
|
|
30604
31116
|
// cli/commands/serve.ts
|
|
30605
31117
|
var ServeCommand = class extends SmCommand {
|
|
30606
31118
|
static paths = [["serve"]];
|
|
30607
|
-
static usage =
|
|
31119
|
+
static usage = Command36.Usage({
|
|
30608
31120
|
category: "Setup",
|
|
30609
31121
|
description: "Start the Hono BFF (single-port: REST + WebSocket + SPA bundle).",
|
|
30610
31122
|
details: `
|
|
@@ -30628,18 +31140,18 @@ var ServeCommand = class extends SmCommand {
|
|
|
30628
31140
|
["Point at a pre-built UI bundle", "$0 serve --ui-dist ./ui/dist/browser"]
|
|
30629
31141
|
]
|
|
30630
31142
|
});
|
|
30631
|
-
port =
|
|
31143
|
+
port = Option34.String("--port", {
|
|
30632
31144
|
required: false,
|
|
30633
31145
|
description: "Listening port (default 4242). 0 = OS-assigned."
|
|
30634
31146
|
});
|
|
30635
|
-
host =
|
|
31147
|
+
host = Option34.String("--host", {
|
|
30636
31148
|
required: false,
|
|
30637
31149
|
description: "Listening host (default 127.0.0.1). Loopback-only enforced when --dev-cors is set."
|
|
30638
31150
|
});
|
|
30639
|
-
noBuiltIns =
|
|
31151
|
+
noBuiltIns = Option34.Boolean("--no-built-ins", false, {
|
|
30640
31152
|
description: "Skip built-in plugin registration (parity with sm scan --no-built-ins)."
|
|
30641
31153
|
});
|
|
30642
|
-
noPlugins =
|
|
31154
|
+
noPlugins = Option34.Boolean("--no-plugins", false, {
|
|
30643
31155
|
description: "Skip drop-in plugin discovery."
|
|
30644
31156
|
});
|
|
30645
31157
|
// `Option.Boolean('--open', true)`, Clipanion's parser auto-derives
|
|
@@ -30649,35 +31161,35 @@ var ServeCommand = class extends SmCommand {
|
|
|
30649
31161
|
// two registrations for the same flag and rejects the invocation
|
|
30650
31162
|
// with "Ambiguous Syntax Error". Same convention shipped by every
|
|
30651
31163
|
// other `--no-...` flag in the CLI tree.
|
|
30652
|
-
open =
|
|
31164
|
+
open = Option34.Boolean("--open", true, {
|
|
30653
31165
|
description: "Auto-open the SPA in the user's default browser after listen. --no-open opts out."
|
|
30654
31166
|
});
|
|
30655
|
-
devCors =
|
|
31167
|
+
devCors = Option34.Boolean("--dev-cors", false, {
|
|
30656
31168
|
description: "Enable permissive CORS for the Angular dev-server proxy workflow."
|
|
30657
31169
|
});
|
|
30658
31170
|
// `--ui-dist` is intentionally undocumented in the Usage block above
|
|
30659
31171
|
// (the demo build pipeline + tests rely on it; everyday users never
|
|
30660
31172
|
// need it). Clipanion still exposes it on the parser; the Usage
|
|
30661
31173
|
// omission is the "hidden" contract per the 14.1 brief.
|
|
30662
|
-
uiDist =
|
|
30663
|
-
noUi =
|
|
31174
|
+
uiDist = Option34.String("--ui-dist", { required: false, hidden: true });
|
|
31175
|
+
noUi = Option34.Boolean("--no-ui", false, {
|
|
30664
31176
|
description: "Don't serve the Angular UI bundle. Use this when running the BFF alongside `ui:dev` (Angular dev server with HMR). The root `/` then renders an inline placeholder pointing the user at the dev server."
|
|
30665
31177
|
});
|
|
30666
|
-
noWatcher =
|
|
31178
|
+
noWatcher = Option34.Boolean("--no-watcher", false, {
|
|
30667
31179
|
description: "Disable the chokidar-fed scan-and-broadcast loop. Use only for CI / read-only deployments."
|
|
30668
31180
|
});
|
|
30669
|
-
yes =
|
|
31181
|
+
yes = Option34.Boolean("--yes", false, {
|
|
30670
31182
|
description: "Skip the interactive prompt and rebuild the local cache when the on-disk DB has drifted (version skew or an inline schema change). Non-TTY invocations rebuild without asking regardless of this flag."
|
|
30671
31183
|
});
|
|
30672
31184
|
// `--watcher-debounce-ms` is undocumented sugar for advanced users
|
|
30673
31185
|
// who want to tighten / relax the watcher's batching window without
|
|
30674
31186
|
// editing settings.json. Hidden flag, the Usage block omits it.
|
|
30675
|
-
watcherDebounceMs =
|
|
30676
|
-
maxScan =
|
|
31187
|
+
watcherDebounceMs = Option34.String("--watcher-debounce-ms", { required: false, hidden: true });
|
|
31188
|
+
maxScan = Option34.String("--max-scan", {
|
|
30677
31189
|
required: false,
|
|
30678
31190
|
description: "Per-invocation override of scan.maxScan (default 50000), the WALK-INTAKE ceiling. The scan walks, parses, analyzes, and reference-validates the full corpus up to this number. Bidirectional: raises OR lowers the ceiling. Applies to every scan the server runs (initial watcher pass, debounced batches, POST /api/scan, GET /api/scan?fresh=1). Same flag is honoured on the bare `sm` invocation, which routes to `sm serve`."
|
|
30679
31191
|
});
|
|
30680
|
-
maxNodes =
|
|
31192
|
+
maxNodes = Option34.String("--max-nodes", {
|
|
30681
31193
|
required: false,
|
|
30682
31194
|
description: "Per-invocation override of scan.maxNodes (default 256), the MAP RENDER cap (pure metadata): it does NOT bound the scan, only how many nodes the graph view projects onto the canvas. Bidirectional: raises OR lowers the render cap. Same flag is honoured on the bare `sm` invocation, which routes to `sm serve`."
|
|
30683
31195
|
});
|
|
@@ -31041,7 +31553,7 @@ function tryOpenBrowser(url, stderr, warnGlyph) {
|
|
|
31041
31553
|
}
|
|
31042
31554
|
|
|
31043
31555
|
// cli/commands/show.ts
|
|
31044
|
-
import { Command as
|
|
31556
|
+
import { Command as Command37, Option as Option35 } from "clipanion";
|
|
31045
31557
|
|
|
31046
31558
|
// cli/i18n/show.texts.ts
|
|
31047
31559
|
var SHOW_TEXTS = {
|
|
@@ -31092,7 +31604,7 @@ var SHOW_TEXTS = {
|
|
|
31092
31604
|
// cli/commands/show.ts
|
|
31093
31605
|
var ShowCommand = class extends SmCommand {
|
|
31094
31606
|
static paths = [["show"]];
|
|
31095
|
-
static usage =
|
|
31607
|
+
static usage = Command37.Usage({
|
|
31096
31608
|
category: "Browse",
|
|
31097
31609
|
description: "Node detail: weight, frontmatter, links, issues.",
|
|
31098
31610
|
details: `
|
|
@@ -31108,7 +31620,7 @@ var ShowCommand = class extends SmCommand {
|
|
|
31108
31620
|
["Machine-readable detail", "$0 show .claude/agents/architect.md --json"]
|
|
31109
31621
|
]
|
|
31110
31622
|
});
|
|
31111
|
-
nodePath =
|
|
31623
|
+
nodePath = Option35.String({ required: true });
|
|
31112
31624
|
async run() {
|
|
31113
31625
|
const dbPath = resolveDbPath({ db: this.db, ...defaultRuntimeContext() });
|
|
31114
31626
|
const exit = requireDbOrExit(dbPath, this.context.stderr);
|
|
@@ -31350,7 +31862,7 @@ function rankConfidenceForGrouping(c) {
|
|
|
31350
31862
|
// cli/commands/sidecar.ts
|
|
31351
31863
|
import { unlink as unlink3 } from "fs/promises";
|
|
31352
31864
|
import { resolve as resolve43 } from "path";
|
|
31353
|
-
import { Command as
|
|
31865
|
+
import { Command as Command38, Option as Option36 } from "clipanion";
|
|
31354
31866
|
|
|
31355
31867
|
// cli/i18n/sidecar.texts.ts
|
|
31356
31868
|
var SIDECAR_TEXTS = {
|
|
@@ -31431,7 +31943,7 @@ async function runWithSidecarConsent(bag, ansi, dispatch) {
|
|
|
31431
31943
|
}
|
|
31432
31944
|
var SidecarRefreshCommand = class extends SmCommand {
|
|
31433
31945
|
static paths = [["sidecar", "refresh"]];
|
|
31434
|
-
static usage =
|
|
31946
|
+
static usage = Command38.Usage({
|
|
31435
31947
|
category: "Actions",
|
|
31436
31948
|
description: "Refresh a sidecar's `for.{bodyHash, frontmatterHash}` to match the live node. Does NOT bump the version.",
|
|
31437
31949
|
details: `
|
|
@@ -31448,8 +31960,8 @@ var SidecarRefreshCommand = class extends SmCommand {
|
|
|
31448
31960
|
["Refresh a node's sidecar hashes", "$0 sidecar refresh .claude/agents/architect.md"]
|
|
31449
31961
|
]
|
|
31450
31962
|
});
|
|
31451
|
-
nodePath =
|
|
31452
|
-
yes =
|
|
31963
|
+
nodePath = Option36.String({ required: true });
|
|
31964
|
+
yes = Option36.Boolean("--yes", false, {
|
|
31453
31965
|
description: "Confirm writing .sm sidecar files in this project (sets allowEditSmFiles=true on first run)."
|
|
31454
31966
|
});
|
|
31455
31967
|
async run() {
|
|
@@ -31571,7 +32083,7 @@ var SidecarRefreshCommand = class extends SmCommand {
|
|
|
31571
32083
|
};
|
|
31572
32084
|
var SidecarPruneCommand = class extends SmCommand {
|
|
31573
32085
|
static paths = [["sidecar", "prune"]];
|
|
31574
|
-
static usage =
|
|
32086
|
+
static usage = Command38.Usage({
|
|
31575
32087
|
category: "Actions",
|
|
31576
32088
|
description: "Delete orphan .sm files (sidecars whose accompanying .md no longer exists).",
|
|
31577
32089
|
details: `
|
|
@@ -31593,8 +32105,8 @@ var SidecarPruneCommand = class extends SmCommand {
|
|
|
31593
32105
|
["Delete every orphan .sm file (non-interactive)", "$0 sidecar prune --yes"]
|
|
31594
32106
|
]
|
|
31595
32107
|
});
|
|
31596
|
-
dryRun =
|
|
31597
|
-
yes =
|
|
32108
|
+
dryRun = Option36.Boolean("-n,--dry-run", false);
|
|
32109
|
+
yes = Option36.Boolean("--yes,--force", false, {
|
|
31598
32110
|
description: "Skip the interactive confirmation prompt. Required for non-interactive callers (CI, pre-commit hooks)."
|
|
31599
32111
|
});
|
|
31600
32112
|
// Complexity is from per-orphan handling, empty-set / dry-run /
|
|
@@ -31714,7 +32226,7 @@ var SidecarPruneCommand = class extends SmCommand {
|
|
|
31714
32226
|
};
|
|
31715
32227
|
var SidecarAnnotateCommand = class extends SmCommand {
|
|
31716
32228
|
static paths = [["sidecar", "annotate"]];
|
|
31717
|
-
static usage =
|
|
32229
|
+
static usage = Command38.Usage({
|
|
31718
32230
|
category: "Actions",
|
|
31719
32231
|
description: "Scaffold an empty `<basename>.sm` next to a node ready for editing.",
|
|
31720
32232
|
details: `
|
|
@@ -31732,9 +32244,9 @@ var SidecarAnnotateCommand = class extends SmCommand {
|
|
|
31732
32244
|
["Overwrite an existing one", "$0 sidecar annotate .claude/agents/architect.md --force"]
|
|
31733
32245
|
]
|
|
31734
32246
|
});
|
|
31735
|
-
nodePath =
|
|
31736
|
-
force =
|
|
31737
|
-
yes =
|
|
32247
|
+
nodePath = Option36.String({ required: true });
|
|
32248
|
+
force = Option36.Boolean("--force", false);
|
|
32249
|
+
yes = Option36.Boolean("--yes", false, {
|
|
31738
32250
|
description: "Confirm writing .sm sidecar files in this project (sets allowEditSmFiles=true on first run)."
|
|
31739
32251
|
});
|
|
31740
32252
|
async run() {
|
|
@@ -31873,7 +32385,7 @@ var SIDECAR_COMMANDS = [
|
|
|
31873
32385
|
];
|
|
31874
32386
|
|
|
31875
32387
|
// cli/commands/stubs.ts
|
|
31876
|
-
import { Command as
|
|
32388
|
+
import { Command as Command39, Option as Option37 } from "clipanion";
|
|
31877
32389
|
|
|
31878
32390
|
// cli/i18n/stubs.texts.ts
|
|
31879
32391
|
var STUBS_TEXTS = {
|
|
@@ -31899,7 +32411,7 @@ var StubCommand = class extends SmCommand {
|
|
|
31899
32411
|
};
|
|
31900
32412
|
var DoctorCommand = class extends StubCommand {
|
|
31901
32413
|
static paths = [["doctor"]];
|
|
31902
|
-
static usage =
|
|
32414
|
+
static usage = Command39.Usage({
|
|
31903
32415
|
category: "Setup",
|
|
31904
32416
|
description: planned("Diagnostic report: DB integrity, pending migrations, orphan rows, plugin status, runner availability.")
|
|
31905
32417
|
});
|
|
@@ -31907,18 +32419,18 @@ var DoctorCommand = class extends StubCommand {
|
|
|
31907
32419
|
};
|
|
31908
32420
|
var FindingsCommand = class extends StubCommand {
|
|
31909
32421
|
static paths = [["findings"]];
|
|
31910
|
-
static usage =
|
|
32422
|
+
static usage = Command39.Usage({
|
|
31911
32423
|
category: "Browse",
|
|
31912
32424
|
description: planned("Probabilistic findings: injection, stale summaries, low confidence.")
|
|
31913
32425
|
});
|
|
31914
|
-
kind =
|
|
31915
|
-
since =
|
|
31916
|
-
threshold =
|
|
32426
|
+
kind = Option37.String("--kind", { required: false });
|
|
32427
|
+
since = Option37.String("--since", { required: false });
|
|
32428
|
+
threshold = Option37.String("--threshold", { required: false });
|
|
31917
32429
|
verbName = "findings";
|
|
31918
32430
|
};
|
|
31919
32431
|
var ActionsListCommand = class extends StubCommand {
|
|
31920
32432
|
static paths = [["actions", "list"]];
|
|
31921
|
-
static usage =
|
|
32433
|
+
static usage = Command39.Usage({
|
|
31922
32434
|
category: "Jobs",
|
|
31923
32435
|
description: planned("Registered action types (manifest view).")
|
|
31924
32436
|
});
|
|
@@ -31926,103 +32438,103 @@ var ActionsListCommand = class extends StubCommand {
|
|
|
31926
32438
|
};
|
|
31927
32439
|
var ActionsShowCommand = class extends StubCommand {
|
|
31928
32440
|
static paths = [["actions", "show"]];
|
|
31929
|
-
static usage =
|
|
32441
|
+
static usage = Command39.Usage({
|
|
31930
32442
|
category: "Jobs",
|
|
31931
32443
|
description: planned("Full action manifest, including preconditions and expected duration.")
|
|
31932
32444
|
});
|
|
31933
|
-
id =
|
|
32445
|
+
id = Option37.String({ required: true });
|
|
31934
32446
|
verbName = "actions show";
|
|
31935
32447
|
};
|
|
31936
32448
|
var JobSubmitCommand = class extends StubCommand {
|
|
31937
32449
|
static paths = [["job", "submit"]];
|
|
31938
|
-
static usage =
|
|
32450
|
+
static usage = Command39.Usage({
|
|
31939
32451
|
category: "Jobs",
|
|
31940
32452
|
description: planned("Enqueue a single job or fan out to every matching node (--all).")
|
|
31941
32453
|
});
|
|
31942
|
-
action =
|
|
31943
|
-
node =
|
|
31944
|
-
all =
|
|
32454
|
+
action = Option37.String({ required: true });
|
|
32455
|
+
node = Option37.String("-n", { required: false });
|
|
32456
|
+
all = Option37.Boolean("--all", false);
|
|
31945
32457
|
// CLI flag stays `--run`; field name is `runFlag` per the
|
|
31946
32458
|
// shadow-avoidance convention documented on `SmCommand`.
|
|
31947
|
-
runFlag =
|
|
31948
|
-
force =
|
|
31949
|
-
ttl =
|
|
31950
|
-
priority =
|
|
32459
|
+
runFlag = Option37.Boolean("--run", false);
|
|
32460
|
+
force = Option37.Boolean("--force", false);
|
|
32461
|
+
ttl = Option37.String("--ttl", { required: false });
|
|
32462
|
+
priority = Option37.String("--priority", { required: false });
|
|
31951
32463
|
verbName = "job submit";
|
|
31952
32464
|
};
|
|
31953
32465
|
var JobListCommand = class extends StubCommand {
|
|
31954
32466
|
static paths = [["job", "list"]];
|
|
31955
|
-
static usage =
|
|
31956
|
-
status =
|
|
31957
|
-
action =
|
|
31958
|
-
node =
|
|
32467
|
+
static usage = Command39.Usage({ category: "Jobs", description: planned("List jobs.") });
|
|
32468
|
+
status = Option37.String("--status", { required: false });
|
|
32469
|
+
action = Option37.String("--action", { required: false });
|
|
32470
|
+
node = Option37.String("--node", { required: false });
|
|
31959
32471
|
verbName = "job list";
|
|
31960
32472
|
};
|
|
31961
32473
|
var JobShowCommand = class extends StubCommand {
|
|
31962
32474
|
static paths = [["job", "show"]];
|
|
31963
|
-
static usage =
|
|
31964
|
-
id =
|
|
32475
|
+
static usage = Command39.Usage({ category: "Jobs", description: planned("Job detail: state, claim time, TTL, runner, content hash.") });
|
|
32476
|
+
id = Option37.String({ required: true });
|
|
31965
32477
|
verbName = "job show";
|
|
31966
32478
|
};
|
|
31967
32479
|
var JobPreviewCommand = class extends StubCommand {
|
|
31968
32480
|
static paths = [["job", "preview"]];
|
|
31969
|
-
static usage =
|
|
31970
|
-
id =
|
|
32481
|
+
static usage = Command39.Usage({ category: "Jobs", description: planned("Render the job MD file without executing.") });
|
|
32482
|
+
id = Option37.String({ required: true });
|
|
31971
32483
|
verbName = "job preview";
|
|
31972
32484
|
};
|
|
31973
32485
|
var JobClaimCommand = class extends StubCommand {
|
|
31974
32486
|
static paths = [["job", "claim"]];
|
|
31975
|
-
static usage =
|
|
32487
|
+
static usage = Command39.Usage({
|
|
31976
32488
|
category: "Jobs",
|
|
31977
32489
|
description: planned("Atomic primitive: return next queued job id, mark it running.")
|
|
31978
32490
|
});
|
|
31979
|
-
filter =
|
|
32491
|
+
filter = Option37.String("--filter", { required: false });
|
|
31980
32492
|
verbName = "job claim";
|
|
31981
32493
|
};
|
|
31982
32494
|
var JobRunCommand = class extends StubCommand {
|
|
31983
32495
|
static paths = [["job", "run"]];
|
|
31984
|
-
static usage =
|
|
32496
|
+
static usage = Command39.Usage({
|
|
31985
32497
|
category: "Jobs",
|
|
31986
32498
|
description: planned("Full CLI-runner loop: claim + spawn + record.")
|
|
31987
32499
|
});
|
|
31988
|
-
all =
|
|
31989
|
-
max =
|
|
32500
|
+
all = Option37.Boolean("--all", false);
|
|
32501
|
+
max = Option37.String("--max", { required: false });
|
|
31990
32502
|
verbName = "job run";
|
|
31991
32503
|
};
|
|
31992
32504
|
var JobStatusCommand = class extends StubCommand {
|
|
31993
32505
|
static paths = [["job", "status"]];
|
|
31994
|
-
static usage =
|
|
32506
|
+
static usage = Command39.Usage({
|
|
31995
32507
|
category: "Jobs",
|
|
31996
32508
|
description: planned("Counts (per status) or single-job status.")
|
|
31997
32509
|
});
|
|
31998
|
-
id =
|
|
32510
|
+
id = Option37.String({ required: false });
|
|
31999
32511
|
verbName = "job status";
|
|
32000
32512
|
};
|
|
32001
32513
|
var JobCancelCommand = class extends StubCommand {
|
|
32002
32514
|
static paths = [["job", "cancel"]];
|
|
32003
|
-
static usage =
|
|
32515
|
+
static usage = Command39.Usage({
|
|
32004
32516
|
category: "Jobs",
|
|
32005
32517
|
description: planned("Force a running job to failed with reason user-cancelled.")
|
|
32006
32518
|
});
|
|
32007
|
-
id =
|
|
32008
|
-
all =
|
|
32519
|
+
id = Option37.String({ required: false });
|
|
32520
|
+
all = Option37.Boolean("--all", false);
|
|
32009
32521
|
verbName = "job cancel";
|
|
32010
32522
|
};
|
|
32011
32523
|
var RecordCommand = class extends StubCommand {
|
|
32012
32524
|
static paths = [["record"]];
|
|
32013
|
-
static usage =
|
|
32525
|
+
static usage = Command39.Usage({
|
|
32014
32526
|
category: "Jobs",
|
|
32015
32527
|
description: planned("Close a running job with success or failure. Nonce is the sole credential.")
|
|
32016
32528
|
});
|
|
32017
|
-
id =
|
|
32018
|
-
nonce =
|
|
32019
|
-
status =
|
|
32020
|
-
report =
|
|
32021
|
-
tokensIn =
|
|
32022
|
-
tokensOut =
|
|
32023
|
-
durationMs =
|
|
32024
|
-
model =
|
|
32025
|
-
error =
|
|
32529
|
+
id = Option37.String("--id", { required: true });
|
|
32530
|
+
nonce = Option37.String("--nonce", { required: true });
|
|
32531
|
+
status = Option37.String("--status", { required: true });
|
|
32532
|
+
report = Option37.String("--report", { required: false });
|
|
32533
|
+
tokensIn = Option37.String("--tokens-in", { required: false });
|
|
32534
|
+
tokensOut = Option37.String("--tokens-out", { required: false });
|
|
32535
|
+
durationMs = Option37.String("--duration-ms", { required: false });
|
|
32536
|
+
model = Option37.String("--model", { required: false });
|
|
32537
|
+
error = Option37.String("--error", { required: false });
|
|
32026
32538
|
verbName = "record";
|
|
32027
32539
|
};
|
|
32028
32540
|
var STUB_COMMANDS = [
|
|
@@ -32046,7 +32558,7 @@ import { cpSync as cpSync3, existsSync as existsSync33, mkdirSync as mkdirSync6,
|
|
|
32046
32558
|
import { dirname as dirname21, join as join21, resolve as resolve44 } from "path";
|
|
32047
32559
|
import { createInterface as createInterface6 } from "readline";
|
|
32048
32560
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
32049
|
-
import { Command as
|
|
32561
|
+
import { Command as Command40, Option as Option38 } from "clipanion";
|
|
32050
32562
|
|
|
32051
32563
|
// cli/i18n/tutorial.texts.ts
|
|
32052
32564
|
var TUTORIAL_TEXTS = {
|
|
@@ -32110,7 +32622,7 @@ var TRIGGER_EN = "run the tutorial";
|
|
|
32110
32622
|
var TRIGGER_ES = "ejecuta el tutorial";
|
|
32111
32623
|
var TutorialCommand = class extends SmCommand {
|
|
32112
32624
|
static paths = [["tutorial"]];
|
|
32113
|
-
static usage =
|
|
32625
|
+
static usage = Command40.Usage({
|
|
32114
32626
|
category: "Setup",
|
|
32115
32627
|
description: "Materialize an interactive tester tutorial as a Claude Code skill folder under `<cwd>/.claude/skills/`.",
|
|
32116
32628
|
details: `
|
|
@@ -32139,18 +32651,18 @@ var TutorialCommand = class extends SmCommand {
|
|
|
32139
32651
|
// more. Accept one so a stale `sm tutorial master` lands on a friendly
|
|
32140
32652
|
// usage error (guarded in `run()`) instead of clipanion's generic
|
|
32141
32653
|
// "extraneous argument" message.
|
|
32142
|
-
legacyPositional =
|
|
32654
|
+
legacyPositional = Option38.String({ required: false });
|
|
32143
32655
|
// Named `forProvider`, NOT `for` (reserved word). The CLI surface stays
|
|
32144
32656
|
// `--for`; selects the destination Provider whose `scaffold.skillDir`
|
|
32145
32657
|
// the skill is materialised under, skipping the interactive prompt.
|
|
32146
|
-
forProvider =
|
|
32658
|
+
forProvider = Option38.String("--for", {
|
|
32147
32659
|
required: false,
|
|
32148
32660
|
description: "Destination provider id (e.g. claude). Skips the prompt."
|
|
32149
32661
|
});
|
|
32150
|
-
force =
|
|
32662
|
+
force = Option38.Boolean("--force", false, {
|
|
32151
32663
|
description: "Overwrite an existing target directory without prompting."
|
|
32152
32664
|
});
|
|
32153
|
-
experimental =
|
|
32665
|
+
experimental = Option38.Boolean("--experimental", false, {
|
|
32154
32666
|
description: "Offer experimental providers as destinations. They ship disabled; enable the chosen one with `sm plugins enable <id>`."
|
|
32155
32667
|
});
|
|
32156
32668
|
async run() {
|
|
@@ -32384,7 +32896,7 @@ function resolveSkillSourceDir() {
|
|
|
32384
32896
|
}
|
|
32385
32897
|
|
|
32386
32898
|
// cli/commands/version.ts
|
|
32387
|
-
import { Command as
|
|
32899
|
+
import { Command as Command41 } from "clipanion";
|
|
32388
32900
|
|
|
32389
32901
|
// cli/i18n/version.texts.ts
|
|
32390
32902
|
var VERSION_TEXTS = {
|
|
@@ -32399,7 +32911,7 @@ var VERSION_TEXTS = {
|
|
|
32399
32911
|
// cli/commands/version.ts
|
|
32400
32912
|
var VersionCommand = class extends SmCommand {
|
|
32401
32913
|
static paths = [["version"]];
|
|
32402
|
-
static usage =
|
|
32914
|
+
static usage = Command41.Usage({
|
|
32403
32915
|
category: "Introspection",
|
|
32404
32916
|
description: "Print the CLI / spec / runtime / db-schema version matrix."
|
|
32405
32917
|
});
|
|
@@ -32616,4 +33128,4 @@ function resolveBareDefault() {
|
|
|
32616
33128
|
process.exit(ExitCode.Error);
|
|
32617
33129
|
}
|
|
32618
33130
|
//# sourceMappingURL=cli.js.map
|
|
32619
|
-
//# debugId=
|
|
33131
|
+
//# debugId=ca8113af-a7ac-5cd7-b45c-03a5974bca86
|