@skill-map/cli 0.66.0 → 0.68.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 +16 -8
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/agents-hub/providers/agent-skills/en/agents-hub.md +2 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/agents-hub/providers/agent-skills/es/agents-hub.md +2 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/content-editor-style/providers/agent-skills/en/content-editor-style.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/content-editor-style/providers/agent-skills/es/content-editor-style.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/en/todo-bullet-guideline.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/en/todo-bullet-guideline2.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/en/todo-bullet-skill.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/es/todo-bullet-guideline.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/es/todo-bullet-guideline2.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/edits/todo-connectors/providers/agent-skills/es/todo-bullet-skill.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/manifest.json +9 -1
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/agent-skills/en/__PROVIDER__/skills/publish/SKILL.md +15 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/agent-skills/es/__PROVIDER__/skills/publish/SKILL.md +16 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/codex/en/__PROVIDER__/skills/publish/SKILL.md +15 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/harness/providers/codex/es/__PROVIDER__/skills/publish/SKILL.md +16 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/agent-skills/en/__PROVIDER__/skills/master-agent/SKILL.md +13 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/agent-skills/es/__PROVIDER__/skills/master-agent/SKILL.md +14 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/codex/en/.codex/agents/master-agent.toml +10 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/master/providers/codex/es/.codex/agents/master-agent.toml +10 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/agent-skills/en/AGENTS.md +7 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/agent-skills/en/__PROVIDER__/skills/content-editor/SKILL.md +20 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/agent-skills/es/AGENTS.md +7 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/agent-skills/es/__PROVIDER__/skills/content-editor/SKILL.md +20 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/agent-skills/shared/CLAUDE.md +1 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/codex/en/.codex/agents/content-editor.toml +19 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/portfolio/providers/codex/es/.codex/agents/content-editor.toml +19 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/en/.codex/agents/demo-agent.toml +13 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/en/__PROVIDER__/skills/demo-command/SKILL.md +11 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/es/.codex/agents/demo-agent.toml +13 -0
- package/dist/cli/tutorial/sm-tutorial/fixtures-data/sets/prologue/providers/codex/es/__PROVIDER__/skills/demo-command/SKILL.md +12 -0
- package/dist/cli/tutorial/sm-tutorial/references/_core.md +101 -48
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.json +174 -0
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +90 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-connect.md +166 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-daily.md +267 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-fundamentals.md +350 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-kickoff.md +140 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-connect-harness.md +6 -4
- package/dist/cli/tutorial/sm-tutorial/references/part-daily-loop.md +21 -26
- package/dist/cli/tutorial/sm-tutorial/references/part-fundamentals.md +10 -5
- package/dist/cli/tutorial/sm-tutorial/references/part-mcp.md +3 -6
- package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +29 -14
- package/dist/cli/tutorial/sm-tutorial/references/part-settings.md +17 -13
- package/dist/cli/tutorial/sm-tutorial/scripts/fixtures.js +85 -22
- package/dist/cli/tutorial/sm-tutorial/scripts/lib/paths.js +74 -4
- package/dist/cli/tutorial/sm-tutorial/scripts/state.js +22 -6
- package/dist/cli.js +527 -251
- package/dist/conformance/index.js +42 -2
- package/dist/index.js +43 -30
- package/dist/kernel/index.d.ts +28 -5
- package/dist/kernel/index.js +43 -30
- package/dist/ui/chunk-3ANNEMV4.js +499 -0
- package/dist/ui/chunk-3GDWM5VM.js +2 -0
- package/dist/ui/{chunk-5BJGO7GH.js → chunk-3U4QZKU2.js} +4 -4
- package/dist/ui/chunk-3ZAHOYQ7.js +1 -0
- package/dist/ui/chunk-4F53HBGG.js +1845 -0
- package/dist/ui/{chunk-56CBK7LB.js → chunk-6FGV5O5J.js} +1 -1
- package/dist/ui/chunk-7WMT2LX4.js +1 -0
- package/dist/ui/chunk-BJUBDHJR.js +3 -0
- package/dist/ui/{chunk-276RLZR4.js → chunk-BSIR3ADF.js} +14 -14
- package/dist/ui/{chunk-FC22ZJQZ.js → chunk-CG25RHMO.js} +1 -1
- package/dist/ui/chunk-EFSC6SOL.js +3 -0
- package/dist/ui/chunk-EJVWTBMV.js +4 -0
- package/dist/ui/chunk-EZI3BXQN.js +1 -0
- package/dist/ui/{chunk-JZ2YF7EL.js → chunk-GUPPOK7U.js} +8 -8
- package/dist/ui/{chunk-CJURGJTN.js → chunk-HLALESGR.js} +1 -1
- package/dist/ui/chunk-I3I4KHR5.js +2 -0
- package/dist/ui/{chunk-BOVJVOLH.js → chunk-I6ED2OW7.js} +1 -1
- package/dist/ui/chunk-JKPG5PO7.js +375 -0
- package/dist/ui/chunk-KHDWXSGR.js +1 -0
- package/dist/ui/{chunk-HEK4PH5A.js → chunk-KMHXNOFZ.js} +1 -1
- package/dist/ui/chunk-KWT7E2RJ.js +16 -0
- package/dist/ui/{chunk-WHZVGOS3.js → chunk-MQSU6EFZ.js} +1 -1
- package/dist/ui/{chunk-43S72FTV.js → chunk-OGEE252A.js} +1 -1
- package/dist/ui/{chunk-J4J42HJ4.js → chunk-PU5OP5RN.js} +1 -1
- package/dist/ui/{chunk-UTRZTB6V.js → chunk-QVG7J2MP.js} +1 -1
- package/dist/ui/chunk-TQBXK5JN.js +1 -0
- package/dist/ui/chunk-Z7SOKILO.js +2 -0
- package/dist/ui/{chunk-WCABR6TI.js → chunk-ZRJ5ZCFR.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/ui/main-ZYRIR6DB.js +4 -0
- package/dist/ui/styles-VEGETYWD.css +1 -0
- package/package.json +17 -18
- package/dist/ui/chunk-34ZZDYNQ.js +0 -1
- package/dist/ui/chunk-44VNNUSQ.js +0 -2
- package/dist/ui/chunk-4SG4352Z.js +0 -7
- package/dist/ui/chunk-5ITZXW3A.js +0 -1
- package/dist/ui/chunk-7ANZW2OI.js +0 -499
- package/dist/ui/chunk-BJ6X6WBO.js +0 -4
- package/dist/ui/chunk-CZSLV6YD.js +0 -1
- package/dist/ui/chunk-DLYJHLJX.js +0 -2
- package/dist/ui/chunk-LGFABCIA.js +0 -16
- package/dist/ui/chunk-LPDD2DHE.js +0 -369
- package/dist/ui/chunk-MSKP5A4B.js +0 -3
- package/dist/ui/chunk-P3SNMV4X.js +0 -2
- package/dist/ui/chunk-S4S5ZMXJ.js +0 -3
- package/dist/ui/chunk-VHEFRMK3.js +0 -1
- package/dist/ui/chunk-X6TRIDBI.js +0 -1845
- package/dist/ui/main-NCNZHLLJ.js +0 -4
- package/dist/ui/styles-I4ULXD3V.css +0 -1
- /package/dist/ui/{chunk-Y2Z26SRI.js → chunk-5RNLC6V4.js} +0 -0
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]="bde63370-f02c-51bb-92b1-0c58f46b6aee")}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.68.0",
|
|
254
254
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
255
255
|
license: "MIT",
|
|
256
256
|
type: "module",
|
|
@@ -323,39 +323,38 @@ var package_default = {
|
|
|
323
323
|
clean: "rm -rf dist coverage"
|
|
324
324
|
},
|
|
325
325
|
dependencies: {
|
|
326
|
-
"@hono/node-server": "2.0.
|
|
327
|
-
"@sentry/node": "10.
|
|
326
|
+
"@hono/node-server": "2.0.6",
|
|
327
|
+
"@sentry/node": "10.61.0",
|
|
328
328
|
"@skill-map/spec": "workspace:*",
|
|
329
|
-
ajv: "8.
|
|
329
|
+
ajv: "8.20.0",
|
|
330
330
|
"ajv-formats": "3.0.1",
|
|
331
331
|
chokidar: "5.0.0",
|
|
332
332
|
clipanion: "4.0.0-rc.4",
|
|
333
|
-
hono: "4.12.
|
|
333
|
+
hono: "4.12.27",
|
|
334
334
|
ignore: "7.0.5",
|
|
335
335
|
"js-tiktoken": "1.0.21",
|
|
336
|
-
"js-yaml": "
|
|
337
|
-
kysely: "0.
|
|
338
|
-
"posthog-node": "5.
|
|
339
|
-
semver: "7.
|
|
340
|
-
"smol-toml": "1.
|
|
336
|
+
"js-yaml": "5.1.0",
|
|
337
|
+
kysely: "0.29.2",
|
|
338
|
+
"posthog-node": "5.38.5",
|
|
339
|
+
semver: "7.8.5",
|
|
340
|
+
"smol-toml": "1.7.0",
|
|
341
341
|
typanion: "3.14.0",
|
|
342
342
|
ws: "8.21.0"
|
|
343
343
|
},
|
|
344
344
|
devDependencies: {
|
|
345
345
|
"@eslint/js": "10.0.1",
|
|
346
346
|
"@stylistic/eslint-plugin": "5.10.0",
|
|
347
|
-
"@types/
|
|
348
|
-
"@types/node": "24.12.2",
|
|
347
|
+
"@types/node": "26.0.1",
|
|
349
348
|
"@types/semver": "7.7.1",
|
|
350
349
|
"@types/ws": "8.18.1",
|
|
351
350
|
c8: "11.0.0",
|
|
352
|
-
eslint: "10.
|
|
353
|
-
"eslint-plugin-import-x": "4.
|
|
351
|
+
eslint: "10.5.0",
|
|
352
|
+
"eslint-plugin-import-x": "4.17.0",
|
|
354
353
|
"json-schema-to-typescript": "15.0.4",
|
|
355
354
|
tsup: "8.5.1",
|
|
356
|
-
tsx: "4.22.
|
|
357
|
-
typescript: "
|
|
358
|
-
"typescript-eslint": "8.
|
|
355
|
+
tsx: "4.22.4",
|
|
356
|
+
typescript: "6.0.3",
|
|
357
|
+
"typescript-eslint": "8.62.0"
|
|
359
358
|
},
|
|
360
359
|
engines: {
|
|
361
360
|
node: ">=24.0"
|
|
@@ -850,9 +849,9 @@ function stripFences(input) {
|
|
|
850
849
|
}
|
|
851
850
|
continue;
|
|
852
851
|
}
|
|
853
|
-
const
|
|
854
|
-
if (
|
|
855
|
-
openFence =
|
|
852
|
+
const open3 = FENCE_RE.exec(line);
|
|
853
|
+
if (open3?.groups) {
|
|
854
|
+
openFence = open3.groups["fence"];
|
|
856
855
|
out.push(blank(line));
|
|
857
856
|
continue;
|
|
858
857
|
}
|
|
@@ -1008,12 +1007,16 @@ var slashCommandExtractor = {
|
|
|
1008
1007
|
kind: "extractor",
|
|
1009
1008
|
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.",
|
|
1010
1009
|
scope: "body",
|
|
1011
|
-
// Also authorised under the codex
|
|
1012
|
-
//
|
|
1013
|
-
//
|
|
1014
|
-
//
|
|
1015
|
-
//
|
|
1016
|
-
|
|
1010
|
+
// Also authorised under the codex and antigravity lenses, which share the
|
|
1011
|
+
// `/command` grammar. Under codex a sub-agent's prompt body (the TOML
|
|
1012
|
+
// `developer_instructions` field) has its `/command` tokens parsed for
|
|
1013
|
+
// pipeline parity; codex resolves them to its open-standard skills
|
|
1014
|
+
// (`invokes: ['skill']`). Under antigravity a workflow / skill / AGENTS.md
|
|
1015
|
+
// body's `/name` tokens resolve to BOTH skills and workflows
|
|
1016
|
+
// (`invokes: ['skill', 'workflow']`), since Antigravity invokes either by
|
|
1017
|
+
// the same slash. A lens that declares no `invokes` resolution leaves the
|
|
1018
|
+
// signals unresolved (no spurious edges).
|
|
1019
|
+
precondition: { provider: ["claude", "codex", "antigravity"] },
|
|
1017
1020
|
extract(ctx) {
|
|
1018
1021
|
const seen = /* @__PURE__ */ new Set();
|
|
1019
1022
|
const body = stripCodeAndHtml(ctx.body);
|
|
@@ -1093,6 +1096,27 @@ function buildTooltip(names) {
|
|
|
1093
1096
|
return `${joined.slice(0, TOOLTIP_MAX - 1)}\u2026`;
|
|
1094
1097
|
}
|
|
1095
1098
|
|
|
1099
|
+
// plugins/antigravity/providers/antigravity/schemas/workflow.schema.json
|
|
1100
|
+
var workflow_schema_default = {
|
|
1101
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1102
|
+
$id: "https://skill-map.ai/providers/antigravity/v1/frontmatter/workflow.schema.json",
|
|
1103
|
+
title: "FrontmatterAntigravityWorkflow",
|
|
1104
|
+
description: "Frontmatter shape for nodes classified as `workflow` by the Google Antigravity Provider. Workflows are standalone Markdown files under `.agent/workflows/<name>.md` (note the SINGULAR `.agent`, distinct from the open-standard `.agents/skills/` plural that Antigravity adopted for skills). A workflow file is YAML frontmatter followed by a numbered list of markdown steps; the agent runs it when invoked as the slash command `/<name>`, where the handle is ALWAYS the filename stem. Per the documented Antigravity workflow contract (https://antigravity.google/docs/rules-workflows) `description` is the ONLY frontmatter field: workflows have NO `name` field (unlike skills, where `name` is an optional override), so this schema requires `description` and declares no other property. The step body may carry execution-control comments, the shipped runtime documents `// turbo` (per-step) and `// turbo-all` (file-wide); those are body markup, not frontmatter, so they are not modelled here. `additionalProperties: true` lets any future frontmatter key flow through unchanged.",
|
|
1105
|
+
allOf: [
|
|
1106
|
+
{ $ref: "https://skill-map.ai/spec/v0/frontmatter/base.schema.json" }
|
|
1107
|
+
],
|
|
1108
|
+
type: "object",
|
|
1109
|
+
additionalProperties: true,
|
|
1110
|
+
required: ["description"],
|
|
1111
|
+
properties: {
|
|
1112
|
+
description: {
|
|
1113
|
+
type: "string",
|
|
1114
|
+
maxLength: 1024,
|
|
1115
|
+
description: "What the workflow does and when to run it. Antigravity surfaces it in the slash-command picker and uses it for smart detection; skill-map mirrors it on the node card. Required by the Antigravity workflow contract (the only documented workflow frontmatter field). Max 1024 chars, non-empty (minLength from the spec base)."
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
|
|
1096
1120
|
// plugins/agent-skills/providers/agent-skills/schemas/skill.schema.json
|
|
1097
1121
|
var skill_schema_default2 = {
|
|
1098
1122
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1222,12 +1246,14 @@ var agentSkillsProvider = {
|
|
|
1222
1246
|
// Provider-owned.
|
|
1223
1247
|
detect: { markers: [".agents"] },
|
|
1224
1248
|
// Authoring target for `sm tutorial`: the open standard discovers skills
|
|
1225
|
-
// under `.agents/skills/<name>/SKILL.md`.
|
|
1226
|
-
//
|
|
1227
|
-
//
|
|
1228
|
-
//
|
|
1229
|
-
// `
|
|
1230
|
-
|
|
1249
|
+
// under `.agents/skills/<name>/SKILL.md`. `aka` lists Antigravity, which
|
|
1250
|
+
// shares this territory AND the BASIC tutorial track (skill + markdown,
|
|
1251
|
+
// references), so a tester on Antigravity scaffolds here. OpenAI Codex
|
|
1252
|
+
// also reads `.agents/skills/`, but Codex is a RICH-track lens (it has the
|
|
1253
|
+
// `agent` kind, slash and `@`), so advertising it under this basic row
|
|
1254
|
+
// would hand it the wrong book; Codex is surfaced once a Codex rich
|
|
1255
|
+
// scaffold target lands. `aka` is display-only, `--for` matches the id.
|
|
1256
|
+
scaffold: { skillDir: ".agents/skills", aka: ["Google's Antigravity"] },
|
|
1231
1257
|
read: COMMONS_READ,
|
|
1232
1258
|
kinds: COMMONS_KINDS,
|
|
1233
1259
|
resolution: COMMONS_RESOLUTION,
|
|
@@ -1239,11 +1265,43 @@ var agentSkillsProvider = {
|
|
|
1239
1265
|
};
|
|
1240
1266
|
|
|
1241
1267
|
// plugins/antigravity/providers/antigravity/index.ts
|
|
1268
|
+
var ANTIGRAVITY_RESERVED_SLASH_VERBS = [
|
|
1269
|
+
// Inherited open-standard base (universal cross-agent slash commands).
|
|
1270
|
+
...COMMONS_RESERVED_NAMES["skill"] ?? [],
|
|
1271
|
+
// Antigravity-specific verbs (not part of the open-standard base).
|
|
1272
|
+
"artifact",
|
|
1273
|
+
"branch",
|
|
1274
|
+
"btw",
|
|
1275
|
+
"changelog",
|
|
1276
|
+
"context",
|
|
1277
|
+
"conversation",
|
|
1278
|
+
"copy",
|
|
1279
|
+
"credits",
|
|
1280
|
+
"diff",
|
|
1281
|
+
"fast",
|
|
1282
|
+
"fork",
|
|
1283
|
+
"goal",
|
|
1284
|
+
"grill-me",
|
|
1285
|
+
"keybindings",
|
|
1286
|
+
"new",
|
|
1287
|
+
"open",
|
|
1288
|
+
"planning",
|
|
1289
|
+
"quota",
|
|
1290
|
+
"rename",
|
|
1291
|
+
"rewind",
|
|
1292
|
+
"schedule",
|
|
1293
|
+
"settings",
|
|
1294
|
+
"skills",
|
|
1295
|
+
"switch",
|
|
1296
|
+
"tasks",
|
|
1297
|
+
"title",
|
|
1298
|
+
"undo"
|
|
1299
|
+
];
|
|
1242
1300
|
var antigravityProvider = {
|
|
1243
1301
|
id: "antigravity",
|
|
1244
1302
|
pluginId: ANTIGRAVITY_PLUGIN_ID,
|
|
1245
1303
|
kind: "provider",
|
|
1246
|
-
description: "
|
|
1304
|
+
description: "Classifies `.agent/workflows/*.md` as Antigravity workflows and `.agents/skills/*/SKILL.md` as skills (open standard); declares the Antigravity runtime identity and its reserved built-in names.",
|
|
1247
1305
|
// Provider identity for the active-lens dropdown, the topbar lens chip,
|
|
1248
1306
|
// and the per-node provider chip. Antigravity violet, distinct from the
|
|
1249
1307
|
// other vendor palettes.
|
|
@@ -1252,92 +1310,71 @@ var antigravityProvider = {
|
|
|
1252
1310
|
color: "#7c3aed",
|
|
1253
1311
|
colorDark: "#a78bfa"
|
|
1254
1312
|
},
|
|
1255
|
-
//
|
|
1256
|
-
// (
|
|
1257
|
-
//
|
|
1258
|
-
//
|
|
1259
|
-
//
|
|
1260
|
-
//
|
|
1261
|
-
|
|
1262
|
-
//
|
|
1263
|
-
//
|
|
1313
|
+
// Auto-detect marker: Antigravity's workflows live under `.agent/workflows/`
|
|
1314
|
+
// (SINGULAR `.agent`), its one vendor-specific on-disk territory. Skills
|
|
1315
|
+
// live under the shared open-standard `.agents/` (owned by `agent-skills`),
|
|
1316
|
+
// so they are deliberately NOT a marker here. Now that antigravity ships
|
|
1317
|
+
// `beta` (enabled by default), this marker is live: a `.agent/workflows/`
|
|
1318
|
+
// project auto-detects the antigravity lens.
|
|
1319
|
+
detect: { markers: [".agent/workflows"] },
|
|
1320
|
+
// Vendor provider: Antigravity declares its own `workflow` kind
|
|
1321
|
+
// (`.agent/workflows/*.md`) on top of the open-standard skills it adopts.
|
|
1322
|
+
// Gating the classifier behind the active lens keeps the walker from
|
|
1323
|
+
// claiming Antigravity workflows under another lens, where the Antigravity
|
|
1324
|
+
// runtime would never resolve them anyway.
|
|
1264
1325
|
gatedByActiveLens: true,
|
|
1265
|
-
//
|
|
1266
|
-
//
|
|
1267
|
-
//
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
// `
|
|
1271
|
-
//
|
|
1272
|
-
//
|
|
1273
|
-
// `
|
|
1274
|
-
// below apply via SELF scope. `agent-skills` itself is gated to its own
|
|
1275
|
-
// lens, so it never competes here (under the antigravity lens it does
|
|
1276
|
-
// not participate). This is why there is no cross-provider lens-scope
|
|
1277
|
-
// rule in the kernel any more.
|
|
1326
|
+
// Beta: ships ENABLED by default (auto-detects `.agent/workflows/`,
|
|
1327
|
+
// selectable as the active lens) with a maturity badge, the same posture
|
|
1328
|
+
// as codex, since the workflow kind + slash wiring are freshly landed.
|
|
1329
|
+
// Promote to `stable` (drop the field) once it has real-world mileage.
|
|
1330
|
+
stability: "beta",
|
|
1331
|
+
// `.md` + YAML frontmatter covers BOTH families (skills and workflows);
|
|
1332
|
+
// a single read rule suffices because the parser/extension are identical,
|
|
1333
|
+
// `classify()` below routes each path to its kind. (Codex needs a
|
|
1334
|
+
// multi-rule `read` only because it mixes `.toml` + `.md`.)
|
|
1278
1335
|
read: COMMONS_READ,
|
|
1279
|
-
kinds:
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
//
|
|
1283
|
-
//
|
|
1284
|
-
// `
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
//
|
|
1305
|
-
//
|
|
1306
|
-
//
|
|
1307
|
-
// `
|
|
1336
|
+
// Two kinds: the open-standard `skill` (inherited from `agent-skills` by
|
|
1337
|
+
// manifest composition, so under the antigravity lens
|
|
1338
|
+
// `.agents/skills/<name>/SKILL.md` classifies as
|
|
1339
|
+
// `{ provider: 'antigravity', kind: 'skill' }` and the reservedNames below
|
|
1340
|
+
// apply via SELF scope) and the OWN `workflow` (`.agent/workflows/*.md`).
|
|
1341
|
+
// `agent-skills` itself is gated to its own lens, so it never competes here.
|
|
1342
|
+
kinds: {
|
|
1343
|
+
...COMMONS_KINDS,
|
|
1344
|
+
workflow: {
|
|
1345
|
+
schema: "./schemas/workflow.schema.json",
|
|
1346
|
+
schemaJson: workflow_schema_default,
|
|
1347
|
+
ui: {
|
|
1348
|
+
label: "Workflows",
|
|
1349
|
+
// Antigravity violet, so a workflow node reads as Antigravity's own
|
|
1350
|
+
// (skills keep the normalised cross-provider green of COMMONS_KINDS).
|
|
1351
|
+
color: "#7c3aed",
|
|
1352
|
+
colorDark: "#a78bfa",
|
|
1353
|
+
icon: { kind: "pi", id: "pi-sitemap" }
|
|
1354
|
+
},
|
|
1355
|
+
// The handle is ALWAYS the filename stem (`/<name>`): Antigravity
|
|
1356
|
+
// workflows have no `name` frontmatter field (unlike skills), so there
|
|
1357
|
+
// is no override source, only `filename-basename`.
|
|
1358
|
+
identifiers: ["filename-basename"]
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
// `/<name>` slash invocations resolve to BOTH skills and workflows: under
|
|
1362
|
+
// the antigravity lens a `/deploy` links to either `.agents/skills/deploy`
|
|
1363
|
+
// or `.agent/workflows/deploy.md`. Overrides the open-standard default
|
|
1364
|
+
// (`invokes: ['skill']`) to add the own `workflow` kind.
|
|
1365
|
+
resolution: { invokes: ["skill", "workflow"] },
|
|
1366
|
+
classify(path) {
|
|
1367
|
+
if (/^\.agent\/workflows\/[^/]+\.md$/.test(path.toLowerCase())) return "workflow";
|
|
1368
|
+
return classifyCommonsPath(path);
|
|
1369
|
+
},
|
|
1370
|
+
// Reserved-name catalog (`ANTIGRAVITY_RESERVED_SLASH_VERBS`, defined above).
|
|
1371
|
+
// Applied to BOTH `skill` and `workflow`: Antigravity invokes either kind
|
|
1372
|
+
// by the same `/<name>` slash, so a user file of either kind named after a
|
|
1373
|
+
// built-in is silently shadowed. `core/name-reserved` tests each node
|
|
1374
|
+
// against `reservedNames[node.kind]`, so both keys must carry the catalog.
|
|
1308
1375
|
reservedNames: {
|
|
1309
|
-
skill:
|
|
1310
|
-
|
|
1311
|
-
...COMMONS_RESERVED_NAMES["skill"] ?? [],
|
|
1312
|
-
// Antigravity-specific verbs (not part of the open-standard base).
|
|
1313
|
-
"artifact",
|
|
1314
|
-
"branch",
|
|
1315
|
-
"btw",
|
|
1316
|
-
"changelog",
|
|
1317
|
-
"context",
|
|
1318
|
-
"conversation",
|
|
1319
|
-
"copy",
|
|
1320
|
-
"credits",
|
|
1321
|
-
"diff",
|
|
1322
|
-
"fast",
|
|
1323
|
-
"fork",
|
|
1324
|
-
"goal",
|
|
1325
|
-
"grill-me",
|
|
1326
|
-
"keybindings",
|
|
1327
|
-
"new",
|
|
1328
|
-
"open",
|
|
1329
|
-
"planning",
|
|
1330
|
-
"quota",
|
|
1331
|
-
"rename",
|
|
1332
|
-
"rewind",
|
|
1333
|
-
"schedule",
|
|
1334
|
-
"settings",
|
|
1335
|
-
"skills",
|
|
1336
|
-
"switch",
|
|
1337
|
-
"tasks",
|
|
1338
|
-
"title",
|
|
1339
|
-
"undo"
|
|
1340
|
-
]
|
|
1376
|
+
skill: ANTIGRAVITY_RESERVED_SLASH_VERBS,
|
|
1377
|
+
workflow: ANTIGRAVITY_RESERVED_SLASH_VERBS
|
|
1341
1378
|
}
|
|
1342
1379
|
};
|
|
1343
1380
|
|
|
@@ -1437,6 +1474,12 @@ var codexProvider = {
|
|
|
1437
1474
|
// open-standard project, not necessarily a Codex one. A genuine Codex
|
|
1438
1475
|
// project is identified by `.codex/`.
|
|
1439
1476
|
detect: { markers: [".codex"] },
|
|
1477
|
+
// Tutorial scaffold target (rich track). Codex skills adopt the open
|
|
1478
|
+
// `.agents/skills/` layout, but the codex LENS resolves off `.codex/`,
|
|
1479
|
+
// which the open territory does not carry, so `sm tutorial --for codex`
|
|
1480
|
+
// also drops a `.codex/` marker (the home its TOML agents land under) to
|
|
1481
|
+
// disambiguate from the `agent-skills` lens that shares `.agents/skills/`.
|
|
1482
|
+
scaffold: { skillDir: ".agents/skills", marker: ".codex" },
|
|
1440
1483
|
// Vendor provider: Codex CLI only reads its own territory (its `.codex/`
|
|
1441
1484
|
// agents plus the open `.agents/skills/` skills it adopted). Gating the
|
|
1442
1485
|
// classifier behind the active lens keeps the walker from claiming Codex
|
|
@@ -3620,7 +3663,7 @@ import { existsSync, readFileSync as readFileSync3 } from "fs";
|
|
|
3620
3663
|
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
3621
3664
|
import { createRequire as createRequire3 } from "module";
|
|
3622
3665
|
import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
|
|
3623
|
-
import
|
|
3666
|
+
import { load as yamlLoad, JSON_SCHEMA } from "js-yaml";
|
|
3624
3667
|
|
|
3625
3668
|
// kernel/util/strip-prototype-pollution.ts
|
|
3626
3669
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -3661,7 +3704,7 @@ function readSidecarFor(mdAbsolutePath) {
|
|
|
3661
3704
|
}
|
|
3662
3705
|
let parsedYaml;
|
|
3663
3706
|
try {
|
|
3664
|
-
parsedYaml =
|
|
3707
|
+
parsedYaml = yamlLoad(raw, { schema: JSON_SCHEMA });
|
|
3665
3708
|
} catch (err) {
|
|
3666
3709
|
return {
|
|
3667
3710
|
parsed: null,
|
|
@@ -4520,7 +4563,7 @@ var builtInPlugins = [
|
|
|
4520
4563
|
},
|
|
4521
4564
|
{
|
|
4522
4565
|
id: "antigravity",
|
|
4523
|
-
description: "Google Antigravity CLI platform integration (replaces the retired Gemini CLI). Antigravity
|
|
4566
|
+
description: "Google Antigravity CLI platform integration (replaces the retired Gemini CLI). Classifies Antigravity workflows under `.agent/workflows/*.md` (its own kind) and adopts the open-standard `.agents/skills/` layout for skills; contributes the Antigravity runtime identity and reserved built-in names.",
|
|
4524
4567
|
extensions: [
|
|
4525
4568
|
antigravityProvider2
|
|
4526
4569
|
]
|
|
@@ -5947,7 +5990,7 @@ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
|
5947
5990
|
import { dirname as dirname6, resolve as resolve8 } from "path";
|
|
5948
5991
|
import { createRequire as createRequire4 } from "module";
|
|
5949
5992
|
import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
|
|
5950
|
-
import
|
|
5993
|
+
import { dump as yamlDump, load as yamlLoad2, CORE_SCHEMA, JSON_SCHEMA as JSON_SCHEMA2 } from "js-yaml";
|
|
5951
5994
|
var FilesystemSidecarStore = class {
|
|
5952
5995
|
/**
|
|
5953
5996
|
* Path-keyed in-process lock chain. Each path maps to the tail of a
|
|
@@ -5999,11 +6042,13 @@ var FilesystemSidecarStore = class {
|
|
|
5999
6042
|
`sidecar patch produces a schema-invalid result at ${sidecarAbsPath}: ${errors}`
|
|
6000
6043
|
);
|
|
6001
6044
|
}
|
|
6002
|
-
const yamlText =
|
|
6045
|
+
const yamlText = yamlDump(merged, {
|
|
6003
6046
|
sortKeys: true,
|
|
6004
6047
|
lineWidth: -1,
|
|
6005
6048
|
noRefs: true,
|
|
6006
|
-
noCompatMode: true
|
|
6049
|
+
// js-yaml v5: CORE_SCHEMA reproduces the old `noCompatMode: true`
|
|
6050
|
+
// output (YAML 1.2, no 1.1-compat quoting of yes/no/on/off).
|
|
6051
|
+
schema: CORE_SCHEMA
|
|
6007
6052
|
});
|
|
6008
6053
|
atomicWriteFile(sidecarAbsPath, yamlText);
|
|
6009
6054
|
}
|
|
@@ -6033,7 +6078,7 @@ function isPlainObject4(value) {
|
|
|
6033
6078
|
function readSidecarObject(sidecarAbsPath) {
|
|
6034
6079
|
if (!existsSync6(sidecarAbsPath)) return {};
|
|
6035
6080
|
const raw = readFileSync7(sidecarAbsPath, "utf8");
|
|
6036
|
-
const parsed =
|
|
6081
|
+
const parsed = yamlLoad2(raw, { schema: JSON_SCHEMA2 });
|
|
6037
6082
|
if (parsed === null || parsed === void 0) return {};
|
|
6038
6083
|
if (!isPlainObject4(parsed)) {
|
|
6039
6084
|
throw new Error(
|
|
@@ -6374,7 +6419,7 @@ var SmCommand = class extends Command {
|
|
|
6374
6419
|
};
|
|
6375
6420
|
|
|
6376
6421
|
// core/sqlite/with-sqlite.ts
|
|
6377
|
-
import { existsSync as
|
|
6422
|
+
import { existsSync as existsSync12 } from "fs";
|
|
6378
6423
|
|
|
6379
6424
|
// kernel/adapters/sqlite/storage-adapter.ts
|
|
6380
6425
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
@@ -9122,6 +9167,8 @@ function createSqliteStorage(options) {
|
|
|
9122
9167
|
}
|
|
9123
9168
|
|
|
9124
9169
|
// core/sqlite/db-version-check.ts
|
|
9170
|
+
import { existsSync as existsSync11 } from "fs";
|
|
9171
|
+
import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
|
|
9125
9172
|
async function detectDbVersionSkew(db, currentVersion) {
|
|
9126
9173
|
const meta = await db.selectFrom("scan_meta").select(["scannedByVersion"]).executeTakeFirst();
|
|
9127
9174
|
if (!meta) return { kind: "no-meta" };
|
|
@@ -9151,6 +9198,20 @@ function classifyVersionSkew(dbVersion, currentVersion) {
|
|
|
9151
9198
|
}
|
|
9152
9199
|
return { kind: "warn-older", dbVersion, currentVersion };
|
|
9153
9200
|
}
|
|
9201
|
+
function readScannedByVersion(dbPath) {
|
|
9202
|
+
if (dbPath === ":memory:" || !existsSync11(dbPath)) return null;
|
|
9203
|
+
let raw = null;
|
|
9204
|
+
try {
|
|
9205
|
+
raw = new DatabaseSync5(dbPath, { readOnly: true });
|
|
9206
|
+
const row = raw.prepare("SELECT scanned_by_version AS v FROM scan_meta LIMIT 1").get();
|
|
9207
|
+
const v = row?.v;
|
|
9208
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
9209
|
+
} catch {
|
|
9210
|
+
return null;
|
|
9211
|
+
} finally {
|
|
9212
|
+
raw?.close();
|
|
9213
|
+
}
|
|
9214
|
+
}
|
|
9154
9215
|
function parseVersionTriple(input) {
|
|
9155
9216
|
if (typeof input !== "string" || input.length === 0) return null;
|
|
9156
9217
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(input.trim());
|
|
@@ -9322,7 +9383,7 @@ async function withSqlite(options, fn) {
|
|
|
9322
9383
|
}
|
|
9323
9384
|
}
|
|
9324
9385
|
async function tryWithSqlite(options, fn) {
|
|
9325
|
-
if (options.databasePath !== ":memory:" && !
|
|
9386
|
+
if (options.databasePath !== ":memory:" && !existsSync12(options.databasePath)) {
|
|
9326
9387
|
return null;
|
|
9327
9388
|
}
|
|
9328
9389
|
return withSqlite(options, fn);
|
|
@@ -9926,6 +9987,15 @@ var CHECK_TEXTS = {
|
|
|
9926
9987
|
noIssues: "{{glyph}} No issues.\n",
|
|
9927
9988
|
/** Header summary line: `sm check: 10 warnings · 0 errors`. */
|
|
9928
9989
|
summaryHeader: "sm check: {{summary}}\n\n",
|
|
9990
|
+
/**
|
|
9991
|
+
* Summary fragments joined by ` · `, each colored at the call site.
|
|
9992
|
+
* `{{plural}}` is `''` / `'s'` resolved by count, matching the
|
|
9993
|
+
* `{{plural}}`-slot pattern used across the other verbs (info has no
|
|
9994
|
+
* plural form).
|
|
9995
|
+
*/
|
|
9996
|
+
summaryErrorFragment: "{{count}} error{{plural}}",
|
|
9997
|
+
summaryWarningFragment: "{{count}} warning{{plural}}",
|
|
9998
|
+
summaryInfoFragment: "{{count}} info",
|
|
9929
9999
|
/** Section heading: one per file with at least one issue. */
|
|
9930
10000
|
fileSection: " {{file}}\n",
|
|
9931
10001
|
/**
|
|
@@ -9995,6 +10065,20 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
9995
10065
|
invalidManifestExtensionShape: "{{relEntry}}: {{errors}}. See {{docUrl}}.",
|
|
9996
10066
|
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.).",
|
|
9997
10067
|
disabledByConfig: "disabled by config_plugins or settings.json",
|
|
10068
|
+
/**
|
|
10069
|
+
* Reason stamped on a project-local disk plugin discovered but not
|
|
10070
|
+
* imported because the operator never granted local trust. Distinct
|
|
10071
|
+
* from `disabledByConfig` (an explicit toggle-off): this id has no
|
|
10072
|
+
* `config_plugins` override at all, so its code stays unexecuted until
|
|
10073
|
+
* `sm plugins enable` records local intent.
|
|
10074
|
+
*/
|
|
10075
|
+
untrustedNotLoaded: "not loaded: project-local plugin is untrusted until enabled. Run `sm plugins enable {{pluginId}}` to load it.",
|
|
10076
|
+
/**
|
|
10077
|
+
* One-time aggregate notice the runtime emits when project-local
|
|
10078
|
+
* plugins were found on disk but left unloaded for lack of trust. The
|
|
10079
|
+
* `{{count}}` plugins ride the scan without executing any code.
|
|
10080
|
+
*/
|
|
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 enable any you trust with `sm plugins enable <id>`.",
|
|
9998
10082
|
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.",
|
|
9999
10083
|
idCollision: "Plugin '{{id}}' at {{pathA}} collides with the plugin at {{pathB}}. Rename one and rerun.",
|
|
10000
10084
|
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.",
|
|
@@ -10014,7 +10098,7 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
10014
10098
|
|
|
10015
10099
|
// kernel/adapters/plugin-loader/index.ts
|
|
10016
10100
|
import { createRequire as createRequire5 } from "module";
|
|
10017
|
-
import { existsSync as
|
|
10101
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
10018
10102
|
import { join as join8, resolve as resolve17 } from "path";
|
|
10019
10103
|
import { pathToFileURL } from "url";
|
|
10020
10104
|
import semver from "semver";
|
|
@@ -10117,7 +10201,7 @@ function stripFunctionsAndPluginId(input) {
|
|
|
10117
10201
|
|
|
10118
10202
|
// kernel/adapters/plugin-loader/validation.ts
|
|
10119
10203
|
import * as nodeFs from "fs";
|
|
10120
|
-
import { existsSync as
|
|
10204
|
+
import { existsSync as existsSync13 } from "fs";
|
|
10121
10205
|
import { dirname as dirname10, join as join7 } from "path";
|
|
10122
10206
|
import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
|
|
10123
10207
|
|
|
@@ -10243,7 +10327,7 @@ function validateActionFileConventions(pluginPath, pluginId, manifest, relEntry,
|
|
|
10243
10327
|
const reportSchemaPath = join7(actionDir, "report.schema.json");
|
|
10244
10328
|
const promptPath = join7(actionDir, "prompt.md");
|
|
10245
10329
|
const mode = isRecord(manifestView) && typeof manifestView["mode"] === "string" ? manifestView["mode"] : "deterministic";
|
|
10246
|
-
if (!
|
|
10330
|
+
if (!existsSync13(reportSchemaPath)) {
|
|
10247
10331
|
return {
|
|
10248
10332
|
...fail(
|
|
10249
10333
|
pluginPath,
|
|
@@ -10254,7 +10338,7 @@ function validateActionFileConventions(pluginPath, pluginId, manifest, relEntry,
|
|
|
10254
10338
|
manifest
|
|
10255
10339
|
};
|
|
10256
10340
|
}
|
|
10257
|
-
const promptExists =
|
|
10341
|
+
const promptExists = existsSync13(promptPath);
|
|
10258
10342
|
if (mode === "probabilistic" && !promptExists) {
|
|
10259
10343
|
return {
|
|
10260
10344
|
...fail(
|
|
@@ -10468,11 +10552,11 @@ var PluginLoader = class {
|
|
|
10468
10552
|
discoverPaths() {
|
|
10469
10553
|
const out = [];
|
|
10470
10554
|
for (const root of this.#options.searchPaths) {
|
|
10471
|
-
if (!
|
|
10555
|
+
if (!existsSync14(root)) continue;
|
|
10472
10556
|
for (const entry of readdirSync5(root, { withFileTypes: true })) {
|
|
10473
10557
|
if (!entry.isDirectory()) continue;
|
|
10474
10558
|
const candidate = join8(root, entry.name);
|
|
10475
|
-
if (
|
|
10559
|
+
if (existsSync14(join8(candidate, "plugin.json"))) {
|
|
10476
10560
|
out.push(resolve17(candidate));
|
|
10477
10561
|
}
|
|
10478
10562
|
}
|
|
@@ -10514,15 +10598,8 @@ var PluginLoader = class {
|
|
|
10514
10598
|
const manifestResult = this.#parseAndValidateManifest(pluginPath, pluginId);
|
|
10515
10599
|
if (!manifestResult.ok) return manifestResult.failure;
|
|
10516
10600
|
const manifest = manifestResult.manifest;
|
|
10517
|
-
|
|
10518
|
-
|
|
10519
|
-
path: pluginPath,
|
|
10520
|
-
id: pluginId,
|
|
10521
|
-
status: "disabled",
|
|
10522
|
-
manifest,
|
|
10523
|
-
reason: PLUGIN_LOADER_TEXTS.disabledByConfig
|
|
10524
|
-
};
|
|
10525
|
-
}
|
|
10601
|
+
const gated = this.#preImportGate(pluginPath, pluginId, manifest);
|
|
10602
|
+
if (gated) return gated;
|
|
10526
10603
|
const loaded = [];
|
|
10527
10604
|
for (const relEntry of discoverExtensionEntries(pluginPath)) {
|
|
10528
10605
|
const result = await this.#loadAndValidateExtensionEntry(pluginPath, pluginId, manifest, relEntry);
|
|
@@ -10545,6 +10622,39 @@ var PluginLoader = class {
|
|
|
10545
10622
|
...storageSchemasResult.schemas ? { storageSchemas: storageSchemasResult.schemas } : {}
|
|
10546
10623
|
};
|
|
10547
10624
|
}
|
|
10625
|
+
/**
|
|
10626
|
+
* Pre-import gates run AFTER the JSON manifest parse (safe) and BEFORE
|
|
10627
|
+
* any extension `import()` (executes code). Returns a short-circuit
|
|
10628
|
+
* `disabled` discovery (manifest kept, code NOT imported) when a gate
|
|
10629
|
+
* refuses, or `null` to proceed to the import loop:
|
|
10630
|
+
*
|
|
10631
|
+
* - enable resolution: the per-config `resolveEnabled` plugin gate.
|
|
10632
|
+
* - import trust: the security boundary, refuse to execute a
|
|
10633
|
+
* project-local plugin the operator has not locally trusted; the
|
|
10634
|
+
* plugin stays discoverable in `sm plugins list` without running.
|
|
10635
|
+
*/
|
|
10636
|
+
#preImportGate(pluginPath, pluginId, manifest) {
|
|
10637
|
+
if (this.#options.resolveEnabled && !this.#options.resolveEnabled(pluginId)) {
|
|
10638
|
+
return {
|
|
10639
|
+
path: pluginPath,
|
|
10640
|
+
id: pluginId,
|
|
10641
|
+
status: "disabled",
|
|
10642
|
+
manifest,
|
|
10643
|
+
reason: PLUGIN_LOADER_TEXTS.disabledByConfig
|
|
10644
|
+
};
|
|
10645
|
+
}
|
|
10646
|
+
if (this.#options.resolveImportTrust && !this.#options.resolveImportTrust(pluginId)) {
|
|
10647
|
+
return {
|
|
10648
|
+
path: pluginPath,
|
|
10649
|
+
id: pluginId,
|
|
10650
|
+
status: "disabled",
|
|
10651
|
+
untrusted: true,
|
|
10652
|
+
manifest,
|
|
10653
|
+
reason: tx(PLUGIN_LOADER_TEXTS.untrustedNotLoaded, { pluginId })
|
|
10654
|
+
};
|
|
10655
|
+
}
|
|
10656
|
+
return null;
|
|
10657
|
+
}
|
|
10548
10658
|
/**
|
|
10549
10659
|
* Phase 1 of `loadOne`, read `plugin.json`, AJV-validate the manifest,
|
|
10550
10660
|
* enforce the directory-name == pluginId structural rule, and check
|
|
@@ -10633,7 +10743,7 @@ var PluginLoader = class {
|
|
|
10633
10743
|
} };
|
|
10634
10744
|
}
|
|
10635
10745
|
const abs = resolve17(pluginPath, relEntry);
|
|
10636
|
-
if (!
|
|
10746
|
+
if (!existsSync14(abs)) {
|
|
10637
10747
|
return { ok: false, failure: {
|
|
10638
10748
|
...fail(
|
|
10639
10749
|
pluginPath,
|
|
@@ -10837,7 +10947,7 @@ function discoverExtensionEntries(pluginPath) {
|
|
|
10837
10947
|
}
|
|
10838
10948
|
function collectKindEntries(pluginPath, kindDir, out) {
|
|
10839
10949
|
const kindAbs = resolve17(pluginPath, kindDir);
|
|
10840
|
-
if (!
|
|
10950
|
+
if (!existsSync14(kindAbs)) return;
|
|
10841
10951
|
let entries;
|
|
10842
10952
|
try {
|
|
10843
10953
|
entries = readdirSync5(kindAbs);
|
|
@@ -10864,7 +10974,7 @@ function isDirectorySafe2(path) {
|
|
|
10864
10974
|
}
|
|
10865
10975
|
function findIndexCandidate(entryAbs) {
|
|
10866
10976
|
for (const candidate of INDEX_CANDIDATES) {
|
|
10867
|
-
if (
|
|
10977
|
+
if (existsSync14(resolve17(entryAbs, candidate))) return candidate;
|
|
10868
10978
|
}
|
|
10869
10979
|
return null;
|
|
10870
10980
|
}
|
|
@@ -10931,6 +11041,17 @@ function resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault = tru
|
|
|
10931
11041
|
function makeEnabledResolver(cfg, dbOverrides) {
|
|
10932
11042
|
return (pluginId, installedDefault) => resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault);
|
|
10933
11043
|
}
|
|
11044
|
+
function makeImportTrustResolver(dbOverrides) {
|
|
11045
|
+
return (pluginId) => {
|
|
11046
|
+
if (isPluginLocked(pluginId)) return true;
|
|
11047
|
+
const prefix = `${pluginId}/`;
|
|
11048
|
+
for (const [key, enabled] of dbOverrides) {
|
|
11049
|
+
if (!enabled) continue;
|
|
11050
|
+
if (key === pluginId || key.startsWith(prefix)) return true;
|
|
11051
|
+
}
|
|
11052
|
+
return false;
|
|
11053
|
+
};
|
|
11054
|
+
}
|
|
10934
11055
|
|
|
10935
11056
|
// core/runtime/plugin-runtime/resolver.ts
|
|
10936
11057
|
function defaultResolveEnabled(_id, installedDefault = true) {
|
|
@@ -10948,7 +11069,7 @@ function isPluginExtensionEnabled(ext, resolveEnabled) {
|
|
|
10948
11069
|
installedDefaultEnabled(ext.stability)
|
|
10949
11070
|
);
|
|
10950
11071
|
}
|
|
10951
|
-
async function
|
|
11072
|
+
async function buildResolverInputs(ctx) {
|
|
10952
11073
|
const { effective: cfg } = loadConfig({ ...ctx });
|
|
10953
11074
|
const dbPath = resolveDbPath({
|
|
10954
11075
|
db: void 0,
|
|
@@ -10958,7 +11079,7 @@ async function buildEnabledResolver(ctx) {
|
|
|
10958
11079
|
{ databasePath: dbPath, autoBackup: false },
|
|
10959
11080
|
(adapter) => adapter.pluginConfig.loadOverrideMap()
|
|
10960
11081
|
) ?? /* @__PURE__ */ new Map();
|
|
10961
|
-
return makeEnabledResolver(cfg, dbOverrides);
|
|
11082
|
+
return { resolveEnabled: makeEnabledResolver(cfg, dbOverrides), dbOverrides };
|
|
10962
11083
|
}
|
|
10963
11084
|
|
|
10964
11085
|
// kernel/scan/walk-content.ts
|
|
@@ -10966,7 +11087,7 @@ import { readFile, readdir, lstat } from "fs/promises";
|
|
|
10966
11087
|
import { isAbsolute as isAbsolute4, join as join9, relative as relative2, resolve as resolve19, sep as sep3 } from "path";
|
|
10967
11088
|
|
|
10968
11089
|
// kernel/scan/ignore.ts
|
|
10969
|
-
import { existsSync as
|
|
11090
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
10970
11091
|
import { dirname as dirname11, resolve as resolve18 } from "path";
|
|
10971
11092
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10972
11093
|
import ignoreFactory from "ignore";
|
|
@@ -10997,7 +11118,7 @@ function loadBundledIgnoreText() {
|
|
|
10997
11118
|
}
|
|
10998
11119
|
function readIgnoreFileText(scopeRoot) {
|
|
10999
11120
|
const path = resolve18(scopeRoot, ".skillmapignore");
|
|
11000
|
-
if (!
|
|
11121
|
+
if (!existsSync15(path)) return void 0;
|
|
11001
11122
|
try {
|
|
11002
11123
|
return readFileSync14(path, "utf8");
|
|
11003
11124
|
} catch {
|
|
@@ -11032,7 +11153,7 @@ function readDefaultsFromDisk() {
|
|
|
11032
11153
|
resolve18(here, "config/defaults/skillmapignore")
|
|
11033
11154
|
];
|
|
11034
11155
|
for (const candidate of candidates) {
|
|
11035
|
-
if (
|
|
11156
|
+
if (existsSync15(candidate)) {
|
|
11036
11157
|
try {
|
|
11037
11158
|
return readFileSync14(candidate, "utf8");
|
|
11038
11159
|
} catch {
|
|
@@ -11043,7 +11164,7 @@ function readDefaultsFromDisk() {
|
|
|
11043
11164
|
}
|
|
11044
11165
|
|
|
11045
11166
|
// plugins/core/parsers/frontmatter-yaml/index.ts
|
|
11046
|
-
import
|
|
11167
|
+
import { load as yamlLoad3, JSON_SCHEMA as JSON_SCHEMA3 } from "js-yaml";
|
|
11047
11168
|
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
11048
11169
|
var frontmatterYamlParser = {
|
|
11049
11170
|
id: "frontmatter-yaml",
|
|
@@ -11055,7 +11176,7 @@ var frontmatterYamlParser = {
|
|
|
11055
11176
|
let parsed = {};
|
|
11056
11177
|
const issues = [];
|
|
11057
11178
|
try {
|
|
11058
|
-
const doc =
|
|
11179
|
+
const doc = yamlLoad3(frontmatterRaw, { schema: JSON_SCHEMA3 });
|
|
11059
11180
|
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
11060
11181
|
parsed = stripPrototypePollution(doc);
|
|
11061
11182
|
}
|
|
@@ -11495,8 +11616,11 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11495
11616
|
const searchPaths = resolveSearchPaths(opts, ctx);
|
|
11496
11617
|
const validators = loadSchemaValidators();
|
|
11497
11618
|
let resolveEnabled;
|
|
11619
|
+
let dbOverrides;
|
|
11498
11620
|
try {
|
|
11499
|
-
|
|
11621
|
+
const inputs = await buildResolverInputs(ctx);
|
|
11622
|
+
resolveEnabled = inputs.resolveEnabled;
|
|
11623
|
+
dbOverrides = inputs.dbOverrides;
|
|
11500
11624
|
} catch {
|
|
11501
11625
|
}
|
|
11502
11626
|
const loaderOpts = {
|
|
@@ -11505,6 +11629,9 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11505
11629
|
specVersion: installedSpecVersion()
|
|
11506
11630
|
};
|
|
11507
11631
|
if (resolveEnabled) loaderOpts.resolveEnabled = resolveEnabled;
|
|
11632
|
+
if (!opts.pluginDir) {
|
|
11633
|
+
loaderOpts.resolveImportTrust = makeImportTrustResolver(dbOverrides ?? /* @__PURE__ */ new Map());
|
|
11634
|
+
}
|
|
11508
11635
|
const loader = createPluginLoader(loaderOpts);
|
|
11509
11636
|
const discovered = await loader.discoverAndLoadAll();
|
|
11510
11637
|
const runtime = {
|
|
@@ -11527,6 +11654,12 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11527
11654
|
if (plugin.status === "disabled") continue;
|
|
11528
11655
|
runtime.warnings.push(formatWarning(plugin));
|
|
11529
11656
|
}
|
|
11657
|
+
const untrustedCount = discovered.filter((p) => p.untrusted === true).length;
|
|
11658
|
+
if (untrustedCount > 0) {
|
|
11659
|
+
runtime.warnings.push(
|
|
11660
|
+
tx(PLUGIN_LOADER_TEXTS.untrustedPluginsFoundNotice, { count: untrustedCount })
|
|
11661
|
+
);
|
|
11662
|
+
}
|
|
11530
11663
|
enforceRootExclusivity(runtime.annotationContributions);
|
|
11531
11664
|
return runtime;
|
|
11532
11665
|
}
|
|
@@ -11965,15 +12098,27 @@ function groupRowsByFile(rows) {
|
|
|
11965
12098
|
function formatSummary(counts, ansi) {
|
|
11966
12099
|
const parts = [];
|
|
11967
12100
|
if (counts.error > 0) {
|
|
11968
|
-
parts.push(
|
|
12101
|
+
parts.push(
|
|
12102
|
+
ansi.red(
|
|
12103
|
+
tx(CHECK_TEXTS.summaryErrorFragment, {
|
|
12104
|
+
count: counts.error,
|
|
12105
|
+
plural: counts.error === 1 ? "" : "s"
|
|
12106
|
+
})
|
|
12107
|
+
)
|
|
12108
|
+
);
|
|
11969
12109
|
}
|
|
11970
12110
|
if (counts.warn > 0) {
|
|
11971
12111
|
parts.push(
|
|
11972
|
-
ansi.yellow(
|
|
12112
|
+
ansi.yellow(
|
|
12113
|
+
tx(CHECK_TEXTS.summaryWarningFragment, {
|
|
12114
|
+
count: counts.warn,
|
|
12115
|
+
plural: counts.warn === 1 ? "" : "s"
|
|
12116
|
+
})
|
|
12117
|
+
)
|
|
11973
12118
|
);
|
|
11974
12119
|
}
|
|
11975
12120
|
if (counts.info > 0) {
|
|
11976
|
-
parts.push(ansi.cyan(
|
|
12121
|
+
parts.push(ansi.cyan(tx(CHECK_TEXTS.summaryInfoFragment, { count: counts.info })));
|
|
11977
12122
|
}
|
|
11978
12123
|
return parts.join(" \xB7 ");
|
|
11979
12124
|
}
|
|
@@ -11998,11 +12143,11 @@ function flattenMessage(message) {
|
|
|
11998
12143
|
}
|
|
11999
12144
|
|
|
12000
12145
|
// cli/commands/config.ts
|
|
12001
|
-
import { existsSync as
|
|
12146
|
+
import { existsSync as existsSync17 } from "fs";
|
|
12002
12147
|
import { Command as Command4, Option as Option4 } from "clipanion";
|
|
12003
12148
|
|
|
12004
12149
|
// kernel/scan/detect-providers.ts
|
|
12005
|
-
import { existsSync as
|
|
12150
|
+
import { existsSync as existsSync16 } from "fs";
|
|
12006
12151
|
import { join as join10 } from "path";
|
|
12007
12152
|
function detectProvidersFromFilesystem(cwd, providers) {
|
|
12008
12153
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -12019,7 +12164,7 @@ function isDetectableUnderCwd(cwd, provider) {
|
|
|
12019
12164
|
if (!installedDefaultEnabled(provider.stability)) return false;
|
|
12020
12165
|
const markers = provider.detect?.markers;
|
|
12021
12166
|
if (!markers || markers.length === 0) return false;
|
|
12022
|
-
return markers.some((marker) =>
|
|
12167
|
+
return markers.some((marker) => existsSync16(join10(cwd, marker)));
|
|
12023
12168
|
}
|
|
12024
12169
|
|
|
12025
12170
|
// core/config/active-provider.ts
|
|
@@ -12047,7 +12192,7 @@ function relativeIfBelow(path, cwd) {
|
|
|
12047
12192
|
}
|
|
12048
12193
|
|
|
12049
12194
|
// cli/util/scan-zone-drop.ts
|
|
12050
|
-
import { DatabaseSync as
|
|
12195
|
+
import { DatabaseSync as DatabaseSync6 } from "node:sqlite";
|
|
12051
12196
|
|
|
12052
12197
|
// cli/commands/db/shared.ts
|
|
12053
12198
|
var SAFE_SQL_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
@@ -12059,7 +12204,7 @@ function assertSafeIdentifier(name) {
|
|
|
12059
12204
|
|
|
12060
12205
|
// cli/util/scan-zone-drop.ts
|
|
12061
12206
|
function dropScanZone(dbPath) {
|
|
12062
|
-
const db = new
|
|
12207
|
+
const db = new DatabaseSync6(dbPath);
|
|
12063
12208
|
try {
|
|
12064
12209
|
const rows = db.prepare(
|
|
12065
12210
|
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'scan\\_%' ESCAPE '\\'"
|
|
@@ -12650,7 +12795,7 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
12650
12795
|
announceLensSwitch(cwd, ansi) {
|
|
12651
12796
|
const dbPath = resolveDbPath({ db: void 0, cwd });
|
|
12652
12797
|
const okGlyph = ansi.green("\u2713");
|
|
12653
|
-
if (!
|
|
12798
|
+
if (!existsSync17(dbPath)) {
|
|
12654
12799
|
this.printer.info(tx(CONFIG_TEXTS.lensSwitchedNoDb, { glyph: okGlyph }));
|
|
12655
12800
|
return;
|
|
12656
12801
|
}
|
|
@@ -12690,7 +12835,7 @@ var ConfigResetCommand = class extends SmCommand {
|
|
|
12690
12835
|
const path = targetSettingsPath2(target, ctx.cwd);
|
|
12691
12836
|
const ansi = this.ansiFor("stdout");
|
|
12692
12837
|
const okGlyph = ansi.green("\u2713");
|
|
12693
|
-
if (!
|
|
12838
|
+
if (!existsSync17(path)) {
|
|
12694
12839
|
this.printer.data(
|
|
12695
12840
|
tx(CONFIG_TEXTS.unsetNoOverride, {
|
|
12696
12841
|
glyph: okGlyph,
|
|
@@ -12765,16 +12910,17 @@ var CONFIG_COMMANDS = [
|
|
|
12765
12910
|
];
|
|
12766
12911
|
|
|
12767
12912
|
// cli/commands/conformance.ts
|
|
12768
|
-
import { existsSync as
|
|
12913
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
|
|
12769
12914
|
import { dirname as dirname13, resolve as resolve23 } from "path";
|
|
12770
12915
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12771
12916
|
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
12772
12917
|
|
|
12773
12918
|
// conformance/index.ts
|
|
12774
12919
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12775
|
-
import { cpSync, existsSync as
|
|
12920
|
+
import { cpSync, existsSync as existsSync18, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync15, rmSync, statSync as statSync3 } from "fs";
|
|
12776
12921
|
import { tmpdir } from "os";
|
|
12777
12922
|
import { isAbsolute as isAbsolute6, join as join11, relative as relative3, resolve as resolve21 } from "path";
|
|
12923
|
+
import { DatabaseSync as DatabaseSync7 } from "node:sqlite";
|
|
12778
12924
|
|
|
12779
12925
|
// conformance/i18n/runner.texts.ts
|
|
12780
12926
|
var CONFORMANCE_RUNNER_TEXTS = {
|
|
@@ -12866,6 +13012,11 @@ function runConformanceCase(options) {
|
|
|
12866
13012
|
if (c.fixture) {
|
|
12867
13013
|
replaceFixture(scope, fixturesRoot, c.fixture);
|
|
12868
13014
|
}
|
|
13015
|
+
grantFixturePluginTrust(scope, options.binary, {
|
|
13016
|
+
...pickSafeEnv(process.env),
|
|
13017
|
+
...options.env,
|
|
13018
|
+
...setupEnv
|
|
13019
|
+
});
|
|
12869
13020
|
const argv = [c.invoke.verb];
|
|
12870
13021
|
if (c.invoke.sub) argv.push(c.invoke.sub);
|
|
12871
13022
|
if (c.invoke.args) argv.push(...c.invoke.args);
|
|
@@ -12935,6 +13086,40 @@ function replaceFixture(scope, fixturesRoot, fixture) {
|
|
|
12935
13086
|
const src = join11(fixturesRoot, fixture);
|
|
12936
13087
|
cpSync(src, scope, { recursive: true });
|
|
12937
13088
|
}
|
|
13089
|
+
function grantFixturePluginTrust(scope, binary, env) {
|
|
13090
|
+
const pluginsDir = join11(scope, KERNEL_SKILL_MAP_DIR, "plugins");
|
|
13091
|
+
if (!existsSync18(pluginsDir)) return;
|
|
13092
|
+
const ids = readdirSync6(pluginsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync18(join11(pluginsDir, e.name, "plugin.json"))).map((e) => e.name);
|
|
13093
|
+
if (ids.length === 0) return;
|
|
13094
|
+
const dbPath = join11(scope, KERNEL_SKILL_MAP_DIR, "skill-map.db");
|
|
13095
|
+
if (!existsSync18(dbPath)) {
|
|
13096
|
+
spawnSync2(process.execPath, [binary, "init", "--no-scan"], { cwd: scope, env, encoding: "utf8" });
|
|
13097
|
+
}
|
|
13098
|
+
if (!hasConfigPluginsTable(dbPath)) {
|
|
13099
|
+
spawnSync2(process.execPath, [binary, "scan"], { cwd: scope, env, encoding: "utf8" });
|
|
13100
|
+
}
|
|
13101
|
+
const db = new DatabaseSync7(dbPath);
|
|
13102
|
+
try {
|
|
13103
|
+
const stmt = db.prepare(
|
|
13104
|
+
"INSERT INTO config_plugins (plugin_id, enabled, updated_at) VALUES (?, 1, 0) ON CONFLICT(plugin_id) DO UPDATE SET enabled = 1"
|
|
13105
|
+
);
|
|
13106
|
+
for (const id of ids) stmt.run(id);
|
|
13107
|
+
} finally {
|
|
13108
|
+
db.close();
|
|
13109
|
+
}
|
|
13110
|
+
}
|
|
13111
|
+
function hasConfigPluginsTable(dbPath) {
|
|
13112
|
+
if (!existsSync18(dbPath)) return false;
|
|
13113
|
+
const db = new DatabaseSync7(dbPath, { readOnly: true });
|
|
13114
|
+
try {
|
|
13115
|
+
const row = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'config_plugins'").get();
|
|
13116
|
+
return row !== void 0;
|
|
13117
|
+
} catch {
|
|
13118
|
+
return false;
|
|
13119
|
+
} finally {
|
|
13120
|
+
db.close();
|
|
13121
|
+
}
|
|
13122
|
+
}
|
|
12938
13123
|
function assertContained2(root, rel, label) {
|
|
12939
13124
|
if (isAbsolute6(rel)) {
|
|
12940
13125
|
throw new Error(
|
|
@@ -12969,7 +13154,7 @@ function evaluateAssertion(a, ctx) {
|
|
|
12969
13154
|
return { ok: false, type: a.type, reason: formatErrorMessage(err) };
|
|
12970
13155
|
}
|
|
12971
13156
|
const abs = resolve21(ctx.scope, a.path);
|
|
12972
|
-
return
|
|
13157
|
+
return existsSync18(abs) ? { ok: true, type: a.type } : {
|
|
12973
13158
|
ok: false,
|
|
12974
13159
|
type: a.type,
|
|
12975
13160
|
reason: tx(CONFORMANCE_RUNNER_TEXTS.fileNotFound, { path: a.path })
|
|
@@ -12984,7 +13169,7 @@ function evaluateAssertion(a, ctx) {
|
|
|
12984
13169
|
}
|
|
12985
13170
|
const fixturePath = join11(ctx.fixturesRoot, a.fixture);
|
|
12986
13171
|
const targetPath = resolve21(ctx.scope, a.path);
|
|
12987
|
-
if (!
|
|
13172
|
+
if (!existsSync18(targetPath)) {
|
|
12988
13173
|
return {
|
|
12989
13174
|
ok: false,
|
|
12990
13175
|
type: a.type,
|
|
@@ -13165,7 +13350,7 @@ var CONFORMANCE_TEXTS = {
|
|
|
13165
13350
|
};
|
|
13166
13351
|
|
|
13167
13352
|
// cli/util/conformance-scopes.ts
|
|
13168
|
-
import { existsSync as
|
|
13353
|
+
import { existsSync as existsSync19, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
|
|
13169
13354
|
import { dirname as dirname12, resolve as resolve22 } from "path";
|
|
13170
13355
|
import { createRequire as createRequire6 } from "module";
|
|
13171
13356
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -13185,7 +13370,7 @@ function resolveCliWorkspaceRoot() {
|
|
|
13185
13370
|
let cursor = here;
|
|
13186
13371
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
13187
13372
|
const candidate = resolve22(cursor, "plugins");
|
|
13188
|
-
if (
|
|
13373
|
+
if (existsSync19(candidate) && statSync4(candidate).isDirectory()) {
|
|
13189
13374
|
return cursor;
|
|
13190
13375
|
}
|
|
13191
13376
|
const parent = dirname12(cursor);
|
|
@@ -13205,7 +13390,7 @@ function collectProviderScopes(specRoot) {
|
|
|
13205
13390
|
return out;
|
|
13206
13391
|
}
|
|
13207
13392
|
const pluginsRoot = resolve22(workspaceRoot, "plugins");
|
|
13208
|
-
if (!
|
|
13393
|
+
if (!existsSync19(pluginsRoot)) return out;
|
|
13209
13394
|
for (const pluginEntry of readdirSync7(pluginsRoot)) {
|
|
13210
13395
|
const pluginDir = resolve22(pluginsRoot, pluginEntry);
|
|
13211
13396
|
if (!isDir(pluginDir)) continue;
|
|
@@ -13217,7 +13402,7 @@ function collectProviderScopes(specRoot) {
|
|
|
13217
13402
|
}
|
|
13218
13403
|
function isDir(path) {
|
|
13219
13404
|
try {
|
|
13220
|
-
return
|
|
13405
|
+
return existsSync19(path) && statSync4(path).isDirectory();
|
|
13221
13406
|
} catch {
|
|
13222
13407
|
return false;
|
|
13223
13408
|
}
|
|
@@ -13227,10 +13412,10 @@ function collectPluginProviderScopes(providersRoot, specRoot, out) {
|
|
|
13227
13412
|
const providerDir = resolve22(providersRoot, entry);
|
|
13228
13413
|
if (!isDir(providerDir)) continue;
|
|
13229
13414
|
const conformanceDir = resolve22(providerDir, "conformance");
|
|
13230
|
-
if (!
|
|
13415
|
+
if (!existsSync19(conformanceDir)) continue;
|
|
13231
13416
|
const casesDir = resolve22(conformanceDir, "cases");
|
|
13232
13417
|
const fixturesDir = resolve22(conformanceDir, "fixtures");
|
|
13233
|
-
if (!
|
|
13418
|
+
if (!existsSync19(casesDir) || !existsSync19(fixturesDir)) continue;
|
|
13234
13419
|
out.push({
|
|
13235
13420
|
id: `provider:${entry}`,
|
|
13236
13421
|
kind: "provider",
|
|
@@ -13268,7 +13453,7 @@ function selectConformanceScopes(scope) {
|
|
|
13268
13453
|
return [match];
|
|
13269
13454
|
}
|
|
13270
13455
|
function listCaseFiles(scope) {
|
|
13271
|
-
if (!
|
|
13456
|
+
if (!existsSync19(scope.casesDir)) return [];
|
|
13272
13457
|
return readdirSync7(scope.casesDir).filter((entry) => entry.endsWith(".json")).sort().map((entry) => resolve22(scope.casesDir, entry));
|
|
13273
13458
|
}
|
|
13274
13459
|
|
|
@@ -13287,7 +13472,7 @@ function resolveBinary() {
|
|
|
13287
13472
|
let cursor = here;
|
|
13288
13473
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
13289
13474
|
const candidate = resolve23(cursor, "bin", "sm.js");
|
|
13290
|
-
if (
|
|
13475
|
+
if (existsSync20(candidate)) return candidate;
|
|
13291
13476
|
const parent = dirname13(cursor);
|
|
13292
13477
|
if (parent === cursor) break;
|
|
13293
13478
|
cursor = parent;
|
|
@@ -13353,7 +13538,7 @@ var ConformanceRunCommand = class extends SmCommand {
|
|
|
13353
13538
|
return ExitCode.Error;
|
|
13354
13539
|
}
|
|
13355
13540
|
const binary = resolveBinary();
|
|
13356
|
-
if (!
|
|
13541
|
+
if (!existsSync20(binary)) {
|
|
13357
13542
|
if (this.json) {
|
|
13358
13543
|
this.#emitJsonError(
|
|
13359
13544
|
"internal",
|
|
@@ -13571,6 +13756,20 @@ var DB_TEXTS = {
|
|
|
13571
13756
|
*/
|
|
13572
13757
|
restoreSourceNotFound: "{{glyph}} Backup not found: {{sourcePath}}\n {{hint}}\n",
|
|
13573
13758
|
restoreSourceNotFoundHint: "Run `sm db backup` first, or pick an existing file (the default backups directory is `.skill-map/backups/`).",
|
|
13759
|
+
/**
|
|
13760
|
+
* Source exists but is not a SQLite database (missing the header).
|
|
13761
|
+
* Restoring it would swap a non-DB into place; refuse with exit 2.
|
|
13762
|
+
*/
|
|
13763
|
+
restoreSourceNotSqlite: "{{glyph}} Not a SQLite database: {{sourcePath}}\n {{hint}}\n",
|
|
13764
|
+
restoreSourceNotSqliteHint: "The file is missing the SQLite header. Pick a real backup (created by `sm db backup`).",
|
|
13765
|
+
/**
|
|
13766
|
+
* Source is a valid DB but was written by a CLI this binary cannot
|
|
13767
|
+
* read forward (newer minor or different major). Refuse with exit 2.
|
|
13768
|
+
*/
|
|
13769
|
+
restoreSourceVersionSkew: "{{glyph}} Refusing to restore {{sourcePath}}\n {{detail}}\n {{hint}}\n",
|
|
13770
|
+
restoreSourceVersionNewerDetail: "It was written by skill-map {{dbVersion}}, newer than this CLI ({{currentVersion}}).",
|
|
13771
|
+
restoreSourceVersionMajorDetail: "It was written by skill-map {{dbVersion}}, a different major than this CLI ({{currentVersion}}).",
|
|
13772
|
+
restoreSourceVersionSkewHint: "Upgrade `sm` to a matching version before restoring this backup.",
|
|
13574
13773
|
restoreConfirm: "Restore {{sourcePath}} over {{target}}? This overwrites the current DB.",
|
|
13575
13774
|
restoreDone: "{{glyph}} Restored {{sourcePath}} \u2192 {{target}}\n",
|
|
13576
13775
|
// --- shared ----------------------------------------------------------
|
|
@@ -13698,6 +13897,39 @@ async function statOrNull(path) {
|
|
|
13698
13897
|
}
|
|
13699
13898
|
}
|
|
13700
13899
|
|
|
13900
|
+
// core/sqlite/restore-validation.ts
|
|
13901
|
+
import { open } from "fs/promises";
|
|
13902
|
+
var SQLITE_MAGIC_PREFIX = "SQLite format 3";
|
|
13903
|
+
async function validateRestorableDb(sourcePath, currentVersion) {
|
|
13904
|
+
if (!await hasSqliteHeader(sourcePath)) {
|
|
13905
|
+
return { ok: false, reason: "not-sqlite" };
|
|
13906
|
+
}
|
|
13907
|
+
const dbVersion = readScannedByVersion(sourcePath);
|
|
13908
|
+
if (dbVersion === null) return { ok: true };
|
|
13909
|
+
const outcome = classifyVersionSkew(dbVersion, currentVersion);
|
|
13910
|
+
if (outcome.kind === "error-newer") {
|
|
13911
|
+
return { ok: false, reason: "version-newer", dbVersion, currentVersion };
|
|
13912
|
+
}
|
|
13913
|
+
if (outcome.kind === "error-major") {
|
|
13914
|
+
return { ok: false, reason: "version-major", dbVersion, currentVersion };
|
|
13915
|
+
}
|
|
13916
|
+
return { ok: true };
|
|
13917
|
+
}
|
|
13918
|
+
async function hasSqliteHeader(sourcePath) {
|
|
13919
|
+
let handle = null;
|
|
13920
|
+
try {
|
|
13921
|
+
handle = await open(sourcePath, "r");
|
|
13922
|
+
const buf = Buffer.alloc(16);
|
|
13923
|
+
const { bytesRead } = await handle.read(buf, 0, 16, 0);
|
|
13924
|
+
if (bytesRead === 0) return true;
|
|
13925
|
+
return buf.toString("latin1", 0, 15) === SQLITE_MAGIC_PREFIX && buf[15] === 0;
|
|
13926
|
+
} catch {
|
|
13927
|
+
return false;
|
|
13928
|
+
} finally {
|
|
13929
|
+
await handle?.close();
|
|
13930
|
+
}
|
|
13931
|
+
}
|
|
13932
|
+
|
|
13701
13933
|
// cli/commands/db/restore.ts
|
|
13702
13934
|
async function chmodOwnerOnlyBestEffort(target) {
|
|
13703
13935
|
try {
|
|
@@ -13738,19 +13970,13 @@ var DbRestoreCommand = class extends SmCommand {
|
|
|
13738
13970
|
);
|
|
13739
13971
|
return ExitCode.NotFound;
|
|
13740
13972
|
}
|
|
13973
|
+
const validation = await validateRestorableDb(sourcePath, VERSION);
|
|
13974
|
+
if (!validation.ok) {
|
|
13975
|
+
this.printValidationError(validation, sourcePath);
|
|
13976
|
+
return ExitCode.Error;
|
|
13977
|
+
}
|
|
13741
13978
|
if (this.dryRun) {
|
|
13742
|
-
this.
|
|
13743
|
-
const sourceBytes = sourceStat.size;
|
|
13744
|
-
const targetClause = await pathExists(target) ? DB_TEXTS.dryRunRestoreTargetExistsClause : DB_TEXTS.dryRunRestoreTargetMissingClause;
|
|
13745
|
-
this.printer.data(
|
|
13746
|
-
tx(DB_TEXTS.dryRunRestoreWouldOverwrite, {
|
|
13747
|
-
sourcePath,
|
|
13748
|
-
sourceBytes,
|
|
13749
|
-
target,
|
|
13750
|
-
targetClause
|
|
13751
|
-
})
|
|
13752
|
-
);
|
|
13753
|
-
return ExitCode.Ok;
|
|
13979
|
+
return this.previewRestore(sourcePath, sourceStat.size, target);
|
|
13754
13980
|
}
|
|
13755
13981
|
if (!this.yes) {
|
|
13756
13982
|
const ok = await confirm(tx(DB_TEXTS.restoreConfirm, { sourcePath, target }), {
|
|
@@ -13779,21 +14005,65 @@ var DbRestoreCommand = class extends SmCommand {
|
|
|
13779
14005
|
);
|
|
13780
14006
|
return ExitCode.Ok;
|
|
13781
14007
|
}
|
|
14008
|
+
/**
|
|
14009
|
+
* `--dry-run` preview: report the source size and whether the target
|
|
14010
|
+
* would be created or overwritten, without copying or unlinking. The
|
|
14011
|
+
* validation gate has already run, so this only describes the swap.
|
|
14012
|
+
*/
|
|
14013
|
+
async previewRestore(sourcePath, sourceBytes, target) {
|
|
14014
|
+
this.printer.data(DB_TEXTS.dryRunHeader);
|
|
14015
|
+
const targetClause = await pathExists(target) ? DB_TEXTS.dryRunRestoreTargetExistsClause : DB_TEXTS.dryRunRestoreTargetMissingClause;
|
|
14016
|
+
this.printer.data(
|
|
14017
|
+
tx(DB_TEXTS.dryRunRestoreWouldOverwrite, {
|
|
14018
|
+
sourcePath,
|
|
14019
|
+
sourceBytes,
|
|
14020
|
+
target,
|
|
14021
|
+
targetClause
|
|
14022
|
+
})
|
|
14023
|
+
);
|
|
14024
|
+
return ExitCode.Ok;
|
|
14025
|
+
}
|
|
14026
|
+
/** Render a `validateRestorableDb` rejection to stderr. */
|
|
14027
|
+
printValidationError(validation, sourcePath) {
|
|
14028
|
+
const ansi = this.ansiFor("stderr");
|
|
14029
|
+
if (validation.reason === "not-sqlite") {
|
|
14030
|
+
this.printer.error(
|
|
14031
|
+
tx(DB_TEXTS.restoreSourceNotSqlite, {
|
|
14032
|
+
glyph: ansi.red("\u2715"),
|
|
14033
|
+
sourcePath,
|
|
14034
|
+
hint: ansi.dim(DB_TEXTS.restoreSourceNotSqliteHint)
|
|
14035
|
+
})
|
|
14036
|
+
);
|
|
14037
|
+
return;
|
|
14038
|
+
}
|
|
14039
|
+
const detailTemplate = validation.reason === "version-newer" ? DB_TEXTS.restoreSourceVersionNewerDetail : DB_TEXTS.restoreSourceVersionMajorDetail;
|
|
14040
|
+
this.printer.error(
|
|
14041
|
+
tx(DB_TEXTS.restoreSourceVersionSkew, {
|
|
14042
|
+
glyph: ansi.red("\u2715"),
|
|
14043
|
+
sourcePath,
|
|
14044
|
+
detail: tx(detailTemplate, {
|
|
14045
|
+
dbVersion: validation.dbVersion,
|
|
14046
|
+
currentVersion: validation.currentVersion
|
|
14047
|
+
}),
|
|
14048
|
+
hint: ansi.dim(DB_TEXTS.restoreSourceVersionSkewHint)
|
|
14049
|
+
})
|
|
14050
|
+
);
|
|
14051
|
+
}
|
|
13782
14052
|
};
|
|
13783
14053
|
|
|
13784
14054
|
// cli/commands/db/reset.ts
|
|
13785
|
-
import { DatabaseSync as
|
|
14055
|
+
import { DatabaseSync as DatabaseSync8 } from "node:sqlite";
|
|
13786
14056
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
13787
14057
|
|
|
13788
14058
|
// core/sqlite/db-files.ts
|
|
13789
|
-
import { existsSync as
|
|
14059
|
+
import { existsSync as existsSync21 } from "fs";
|
|
13790
14060
|
import { rm as rm2 } from "fs/promises";
|
|
13791
14061
|
var DB_FILE_SUFFIXES = ["", "-wal", "-shm"];
|
|
13792
14062
|
async function removeDbFiles(dbPath) {
|
|
13793
14063
|
if (dbPath === ":memory:") return;
|
|
13794
14064
|
for (const suffix of DB_FILE_SUFFIXES) {
|
|
13795
14065
|
const p = `${dbPath}${suffix}`;
|
|
13796
|
-
if (
|
|
14066
|
+
if (existsSync21(p)) await rm2(p);
|
|
13797
14067
|
}
|
|
13798
14068
|
}
|
|
13799
14069
|
|
|
@@ -13879,7 +14149,7 @@ var DbResetCommand = class extends SmCommand {
|
|
|
13879
14149
|
return ExitCode.Error;
|
|
13880
14150
|
}
|
|
13881
14151
|
}
|
|
13882
|
-
const db = new
|
|
14152
|
+
const db = new DatabaseSync8(path);
|
|
13883
14153
|
try {
|
|
13884
14154
|
const rows = db.prepare(
|
|
13885
14155
|
"SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE 'scan\\_%' ESCAPE '\\'" + (this.state ? " OR name LIKE 'state\\_%' ESCAPE '\\'" : "") + ")"
|
|
@@ -14022,7 +14292,7 @@ var DbBrowserCommand = class extends SmCommand {
|
|
|
14022
14292
|
};
|
|
14023
14293
|
|
|
14024
14294
|
// cli/commands/db/dump.ts
|
|
14025
|
-
import { DatabaseSync as
|
|
14295
|
+
import { DatabaseSync as DatabaseSync9 } from "node:sqlite";
|
|
14026
14296
|
import { Command as Command11, Option as Option10 } from "clipanion";
|
|
14027
14297
|
var DbDumpCommand = class extends SmCommand {
|
|
14028
14298
|
static paths = [["db", "dump"]];
|
|
@@ -14064,7 +14334,7 @@ var DbDumpCommand = class extends SmCommand {
|
|
|
14064
14334
|
}
|
|
14065
14335
|
};
|
|
14066
14336
|
function dumpDatabaseToStream(dbPath, out, tables) {
|
|
14067
|
-
const db = new
|
|
14337
|
+
const db = new DatabaseSync9(dbPath, { readOnly: true });
|
|
14068
14338
|
try {
|
|
14069
14339
|
out.write("PRAGMA foreign_keys=OFF;\n");
|
|
14070
14340
|
out.write("BEGIN TRANSACTION;\n");
|
|
@@ -14139,6 +14409,10 @@ function tryParseNonNegativeInt(raw) {
|
|
|
14139
14409
|
}
|
|
14140
14410
|
return parsed;
|
|
14141
14411
|
}
|
|
14412
|
+
function tryParsePositiveInt(raw) {
|
|
14413
|
+
const parsed = tryParseNonNegativeInt(raw);
|
|
14414
|
+
return parsed === null || parsed === 0 ? null : parsed;
|
|
14415
|
+
}
|
|
14142
14416
|
function parsePositiveIntegerOption(raw, label, stderr) {
|
|
14143
14417
|
const parsed = tryParseNonNegativeInt(raw);
|
|
14144
14418
|
if (parsed === null || parsed === 0) {
|
|
@@ -14399,7 +14673,7 @@ var DB_COMMANDS = [
|
|
|
14399
14673
|
];
|
|
14400
14674
|
|
|
14401
14675
|
// cli/commands/example.ts
|
|
14402
|
-
import { cpSync as cpSync2, existsSync as
|
|
14676
|
+
import { cpSync as cpSync2, existsSync as existsSync22, statSync as statSync5 } from "fs";
|
|
14403
14677
|
import { dirname as dirname16, relative as relative5, resolve as resolve27 } from "path";
|
|
14404
14678
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
14405
14679
|
import { Command as Command13, Option as Option12 } from "clipanion";
|
|
@@ -14703,7 +14977,7 @@ function resolveExampleSourceDir() {
|
|
|
14703
14977
|
resolve27(here, "../cli/example")
|
|
14704
14978
|
];
|
|
14705
14979
|
for (const candidate of candidates) {
|
|
14706
|
-
if (
|
|
14980
|
+
if (existsSync22(candidate) && statSync5(candidate).isDirectory()) {
|
|
14707
14981
|
cachedSourceDir = candidate;
|
|
14708
14982
|
return candidate;
|
|
14709
14983
|
}
|
|
@@ -14715,7 +14989,7 @@ function resolveExampleSourceDir() {
|
|
|
14715
14989
|
function isExamplePayloadEntry(sourceRoot, src) {
|
|
14716
14990
|
const rel = relative5(sourceRoot, src);
|
|
14717
14991
|
if (rel === "") return true;
|
|
14718
|
-
return rel.split(/[\\/]/)[0] !==
|
|
14992
|
+
return rel.split(/[\\/]/)[0] !== SKILL_MAP_DIR;
|
|
14719
14993
|
}
|
|
14720
14994
|
|
|
14721
14995
|
// cli/commands/export.ts
|
|
@@ -16047,7 +16321,7 @@ import { join as join16 } from "path";
|
|
|
16047
16321
|
import { Command as Command18, Option as Option17 } from "clipanion";
|
|
16048
16322
|
|
|
16049
16323
|
// kernel/orchestrator/index.ts
|
|
16050
|
-
import { existsSync as
|
|
16324
|
+
import { existsSync as existsSync25, statSync as statSync7 } from "fs";
|
|
16051
16325
|
import { isAbsolute as isAbsolute10, resolve as resolve32 } from "path";
|
|
16052
16326
|
import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
|
|
16053
16327
|
|
|
@@ -17417,7 +17691,7 @@ function computeDriftStatus(args2) {
|
|
|
17417
17691
|
}
|
|
17418
17692
|
|
|
17419
17693
|
// kernel/sidecar/discover-orphans.ts
|
|
17420
|
-
import { existsSync as
|
|
17694
|
+
import { existsSync as existsSync23, readdirSync as readdirSync8, statSync as statSync6 } from "fs";
|
|
17421
17695
|
import { join as join13, relative as relative6, sep as sep4 } from "path";
|
|
17422
17696
|
function discoverOrphanSidecars(roots, shouldSkip) {
|
|
17423
17697
|
const out = [];
|
|
@@ -17445,7 +17719,7 @@ function walk2(root, current, shouldSkip, out) {
|
|
|
17445
17719
|
if (!entry.isFile()) continue;
|
|
17446
17720
|
if (!entry.name.endsWith(".sm")) continue;
|
|
17447
17721
|
const expectedMd = `${full.slice(0, -".sm".length)}.md`;
|
|
17448
|
-
if (
|
|
17722
|
+
if (existsSync23(expectedMd) && safeIsFile(expectedMd)) continue;
|
|
17449
17723
|
out.push({ sidecarPath: full, relativePath: rel, expectedMdPath: expectedMd });
|
|
17450
17724
|
}
|
|
17451
17725
|
}
|
|
@@ -17459,10 +17733,10 @@ function safeIsFile(path) {
|
|
|
17459
17733
|
|
|
17460
17734
|
// kernel/orchestrator/node-build.ts
|
|
17461
17735
|
import { createHash as createHash2 } from "crypto";
|
|
17462
|
-
import { existsSync as
|
|
17736
|
+
import { existsSync as existsSync24 } from "fs";
|
|
17463
17737
|
import { isAbsolute as isAbsolute8, resolve as resolvePath } from "path";
|
|
17464
17738
|
import "js-tiktoken/lite";
|
|
17465
|
-
import
|
|
17739
|
+
import { dump as yamlDump2, CORE_SCHEMA as CORE_SCHEMA2 } from "js-yaml";
|
|
17466
17740
|
|
|
17467
17741
|
// kernel/orchestrator/frontmatter.ts
|
|
17468
17742
|
function validateFrontmatter(providerFrontmatter, provider, kind, frontmatter, path, strict) {
|
|
@@ -17555,22 +17829,22 @@ function canonicalFrontmatter(parsed, raw) {
|
|
|
17555
17829
|
if (!hasParsedKeys && hasRawText) {
|
|
17556
17830
|
return raw;
|
|
17557
17831
|
}
|
|
17558
|
-
return
|
|
17832
|
+
return yamlDump2(parsed, {
|
|
17559
17833
|
sortKeys: true,
|
|
17560
17834
|
lineWidth: -1,
|
|
17561
17835
|
noRefs: true,
|
|
17562
|
-
|
|
17836
|
+
schema: CORE_SCHEMA2
|
|
17563
17837
|
});
|
|
17564
17838
|
}
|
|
17565
17839
|
function canonicalSidecarAnnotations(annotations) {
|
|
17566
17840
|
if (!annotations || typeof annotations !== "object" || Array.isArray(annotations)) {
|
|
17567
|
-
return
|
|
17841
|
+
return yamlDump2({}, { sortKeys: true, lineWidth: -1, noRefs: true, schema: CORE_SCHEMA2 });
|
|
17568
17842
|
}
|
|
17569
|
-
return
|
|
17843
|
+
return yamlDump2(annotations, {
|
|
17570
17844
|
sortKeys: true,
|
|
17571
17845
|
lineWidth: -1,
|
|
17572
17846
|
noRefs: true,
|
|
17573
|
-
|
|
17847
|
+
schema: CORE_SCHEMA2
|
|
17574
17848
|
});
|
|
17575
17849
|
}
|
|
17576
17850
|
function resolveSidecarOverlay(relativePath2, nodePathForIssue, roots, liveBodyHash, liveFrontmatterHash) {
|
|
@@ -17624,11 +17898,11 @@ function resolveSidecarOverlay(relativePath2, nodePathForIssue, roots, liveBodyH
|
|
|
17624
17898
|
}
|
|
17625
17899
|
function resolveAbsoluteMdPath(relativePath2, roots) {
|
|
17626
17900
|
if (isAbsolute8(relativePath2)) {
|
|
17627
|
-
return
|
|
17901
|
+
return existsSync24(relativePath2) ? relativePath2 : null;
|
|
17628
17902
|
}
|
|
17629
17903
|
for (const root of roots) {
|
|
17630
17904
|
const candidate = resolvePath(root, relativePath2);
|
|
17631
|
-
if (
|
|
17905
|
+
if (existsSync24(candidate)) return candidate;
|
|
17632
17906
|
}
|
|
17633
17907
|
return null;
|
|
17634
17908
|
}
|
|
@@ -18441,7 +18715,7 @@ function validateRoots(roots) {
|
|
|
18441
18715
|
throw new Error(ORCHESTRATOR_TEXTS.runScanRootEmptyArray);
|
|
18442
18716
|
}
|
|
18443
18717
|
for (const root of roots) {
|
|
18444
|
-
if (!
|
|
18718
|
+
if (!existsSync25(root) || !statSync7(root).isDirectory()) {
|
|
18445
18719
|
throw new Error(tx(ORCHESTRATOR_TEXTS.runScanRootMissing, { root }));
|
|
18446
18720
|
}
|
|
18447
18721
|
}
|
|
@@ -18450,7 +18724,7 @@ function resolveActiveProviderOption(optionValue, roots, providers) {
|
|
|
18450
18724
|
if (optionValue !== void 0) return optionValue;
|
|
18451
18725
|
for (const root of roots) {
|
|
18452
18726
|
const absRoot = isAbsolute10(root) ? root : resolve32(root);
|
|
18453
|
-
if (!
|
|
18727
|
+
if (!existsSync25(absRoot)) continue;
|
|
18454
18728
|
const detected = detectProvidersFromFilesystem(absRoot, providers)[0] ?? null;
|
|
18455
18729
|
if (detected !== null) return detected;
|
|
18456
18730
|
}
|
|
@@ -19196,9 +19470,7 @@ async function promptForLens(detected, stdin, stderr, warnGlyph) {
|
|
|
19196
19470
|
}
|
|
19197
19471
|
|
|
19198
19472
|
// core/sqlite/db-drift-reset.ts
|
|
19199
|
-
import { existsSync as existsSync25 } from "fs";
|
|
19200
19473
|
import { createInterface as createInterface5 } from "readline";
|
|
19201
|
-
import { DatabaseSync as DatabaseSync8 } from "node:sqlite";
|
|
19202
19474
|
|
|
19203
19475
|
// core/sqlite/i18n/db-drift.texts.ts
|
|
19204
19476
|
var DB_DRIFT_TEXTS = {
|
|
@@ -19247,20 +19519,6 @@ function detectDriftReason(dbPath, currentVersion) {
|
|
|
19247
19519
|
}
|
|
19248
19520
|
return classifyFingerprint(dbPath).kind === "drift" ? "schema" : null;
|
|
19249
19521
|
}
|
|
19250
|
-
function readScannedByVersion(dbPath) {
|
|
19251
|
-
if (dbPath === ":memory:" || !existsSync25(dbPath)) return null;
|
|
19252
|
-
let raw = null;
|
|
19253
|
-
try {
|
|
19254
|
-
raw = new DatabaseSync8(dbPath, { readOnly: true });
|
|
19255
|
-
const row = raw.prepare("SELECT scanned_by_version AS v FROM scan_meta LIMIT 1").get();
|
|
19256
|
-
const v = row?.v;
|
|
19257
|
-
return typeof v === "string" && v.length > 0 ? v : null;
|
|
19258
|
-
} catch {
|
|
19259
|
-
return null;
|
|
19260
|
-
} finally {
|
|
19261
|
-
raw?.close();
|
|
19262
|
-
}
|
|
19263
|
-
}
|
|
19264
19522
|
function reasonText(reason) {
|
|
19265
19523
|
return reason === "version" ? DB_DRIFT_TEXTS.driftReasonVersion : DB_DRIFT_TEXTS.driftReasonSchema;
|
|
19266
19524
|
}
|
|
@@ -25205,8 +25463,8 @@ function parseBreakerLimit(raw, stderr, noColor) {
|
|
|
25205
25463
|
}
|
|
25206
25464
|
function parseMaxScanLimit(raw, stderr, noColor) {
|
|
25207
25465
|
if (raw === void 0) return void 0;
|
|
25208
|
-
const n =
|
|
25209
|
-
if (
|
|
25466
|
+
const n = tryParsePositiveInt(raw);
|
|
25467
|
+
if (n === null) {
|
|
25210
25468
|
const stderrTty = stderr;
|
|
25211
25469
|
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
25212
25470
|
stderr.write(
|
|
@@ -25222,8 +25480,8 @@ function parseMaxScanLimit(raw, stderr, noColor) {
|
|
|
25222
25480
|
}
|
|
25223
25481
|
function parseMaxNodesLimit(raw, stderr, noColor) {
|
|
25224
25482
|
if (raw === void 0) return void 0;
|
|
25225
|
-
const n =
|
|
25226
|
-
if (
|
|
25483
|
+
const n = tryParsePositiveInt(raw);
|
|
25484
|
+
if (n === null) {
|
|
25227
25485
|
const stderrTty = stderr;
|
|
25228
25486
|
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
25229
25487
|
stderr.write(
|
|
@@ -25390,8 +25648,8 @@ var ScanCommand = class extends SmCommand {
|
|
|
25390
25648
|
*/
|
|
25391
25649
|
parseIntegerFlag(raw, invalidTemplate, invalidHint) {
|
|
25392
25650
|
if (raw === void 0) return { kind: "ok", value: void 0 };
|
|
25393
|
-
const n =
|
|
25394
|
-
if (
|
|
25651
|
+
const n = tryParsePositiveInt(raw);
|
|
25652
|
+
if (n === null) {
|
|
25395
25653
|
const ansi = this.ansiFor("stderr");
|
|
25396
25654
|
this.printer.info(
|
|
25397
25655
|
tx(invalidTemplate, {
|
|
@@ -26367,7 +26625,7 @@ function originGuarded(path) {
|
|
|
26367
26625
|
}
|
|
26368
26626
|
|
|
26369
26627
|
// server/security-headers.ts
|
|
26370
|
-
var DEFAULT_CSP = "frame-ancestors 'none'; base-uri 'self'; form-action 'self'";
|
|
26628
|
+
var DEFAULT_CSP = "frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'";
|
|
26371
26629
|
function createSecurityHeaders() {
|
|
26372
26630
|
return async (c, next) => {
|
|
26373
26631
|
await next();
|
|
@@ -27018,7 +27276,7 @@ import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
|
27018
27276
|
|
|
27019
27277
|
// server/node-body.ts
|
|
27020
27278
|
import { constants as fsConstants2 } from "fs";
|
|
27021
|
-
import { open } from "fs/promises";
|
|
27279
|
+
import { open as open2 } from "fs/promises";
|
|
27022
27280
|
import { isAbsolute as isAbsolute14, resolve as resolvePath2, relative as relativePath, sep as sep8 } from "path";
|
|
27023
27281
|
async function readNodeBody(cwd, relPath) {
|
|
27024
27282
|
if (isAbsolute14(relPath)) return null;
|
|
@@ -27031,7 +27289,7 @@ async function readNodeBody(cwd, relPath) {
|
|
|
27031
27289
|
let raw;
|
|
27032
27290
|
let handle = null;
|
|
27033
27291
|
try {
|
|
27034
|
-
handle = await
|
|
27292
|
+
handle = await open2(absFile, fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW);
|
|
27035
27293
|
raw = await handle.readFile("utf-8");
|
|
27036
27294
|
} catch (err) {
|
|
27037
27295
|
if (isExpectedFsError(err)) return null;
|
|
@@ -28490,7 +28748,7 @@ var parsePatchBody5 = makeBodyValidator(PATCH_BODY_SCHEMA4, {
|
|
|
28490
28748
|
|
|
28491
28749
|
// server/routes/actions.ts
|
|
28492
28750
|
import { HTTPException as HTTPException16 } from "hono/http-exception";
|
|
28493
|
-
import { resolve as resolve41 } from "path";
|
|
28751
|
+
import { relative as relative10, resolve as resolve41 } from "path";
|
|
28494
28752
|
|
|
28495
28753
|
// server/routes/node-loader.ts
|
|
28496
28754
|
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
@@ -28622,7 +28880,18 @@ function invokeAction(action, absPath, node, body, cwd) {
|
|
|
28622
28880
|
};
|
|
28623
28881
|
return invoke(body.input ?? {}, ctx);
|
|
28624
28882
|
}
|
|
28883
|
+
function assertSidecarWritesContained(writes, cwd) {
|
|
28884
|
+
for (const w of writes ?? []) {
|
|
28885
|
+
if (w.kind !== "sidecar") continue;
|
|
28886
|
+
try {
|
|
28887
|
+
assertContained(cwd, relative10(cwd, w.path));
|
|
28888
|
+
} catch (err) {
|
|
28889
|
+
throw new HTTPException16(400, { message: formatErrorMessage(err) });
|
|
28890
|
+
}
|
|
28891
|
+
}
|
|
28892
|
+
}
|
|
28625
28893
|
async function materializeWrites(writes, body, cwd) {
|
|
28894
|
+
assertSidecarWritesContained(writes, cwd);
|
|
28626
28895
|
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
28627
28896
|
try {
|
|
28628
28897
|
for (const w of writes ?? []) {
|
|
@@ -30167,6 +30436,12 @@ function listenAsync(fetchCallback, wss, host, port) {
|
|
|
30167
30436
|
fetch: fetchCallback,
|
|
30168
30437
|
hostname: host,
|
|
30169
30438
|
port,
|
|
30439
|
+
// `wss` IS a structural `WebSocketServerLike` at runtime (created
|
|
30440
|
+
// with `{ noServer: true }` above). The cast bridges a pure
|
|
30441
|
+
// type-skew: @hono/node-server 2.0.6 declares
|
|
30442
|
+
// `WebSocketServerLike.options.noServer` as `boolean` while
|
|
30443
|
+
// @types/ws declares it `boolean | undefined`, which our
|
|
30444
|
+
// `exactOptionalPropertyTypes: true` tsconfig rejects.
|
|
30170
30445
|
websocket: { server: wss }
|
|
30171
30446
|
},
|
|
30172
30447
|
() => {
|
|
@@ -30484,7 +30759,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
30484
30759
|
);
|
|
30485
30760
|
return ExitCode.Error;
|
|
30486
30761
|
}
|
|
30487
|
-
const maxScanResult =
|
|
30762
|
+
const maxScanResult = parseMaxIntFlag(this.maxScan);
|
|
30488
30763
|
if (!maxScanResult.ok) {
|
|
30489
30764
|
this.printer.info(
|
|
30490
30765
|
tx(SERVE_TEXTS.maxScanInvalid, {
|
|
@@ -30495,7 +30770,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
30495
30770
|
);
|
|
30496
30771
|
return ExitCode.Error;
|
|
30497
30772
|
}
|
|
30498
|
-
const maxNodesResult =
|
|
30773
|
+
const maxNodesResult = parseMaxIntFlag(this.maxNodes);
|
|
30499
30774
|
if (!maxNodesResult.ok) {
|
|
30500
30775
|
this.printer.info(
|
|
30501
30776
|
tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
@@ -30624,16 +30899,10 @@ function parseDebounce(raw) {
|
|
|
30624
30899
|
if (parsed === null) return { ok: false, value: raw };
|
|
30625
30900
|
return { ok: true, value: parsed };
|
|
30626
30901
|
}
|
|
30627
|
-
function
|
|
30628
|
-
if (raw === void 0) return { ok: true, value: void 0 };
|
|
30629
|
-
const n = Number(raw);
|
|
30630
|
-
if (!Number.isInteger(n) || n < 1) return { ok: false, value: raw };
|
|
30631
|
-
return { ok: true, value: n };
|
|
30632
|
-
}
|
|
30633
|
-
function parseMaxNodes(raw) {
|
|
30902
|
+
function parseMaxIntFlag(raw) {
|
|
30634
30903
|
if (raw === void 0) return { ok: true, value: void 0 };
|
|
30635
|
-
const n =
|
|
30636
|
-
if (
|
|
30904
|
+
const n = tryParsePositiveInt(raw);
|
|
30905
|
+
if (n === null) return { ok: false, value: raw };
|
|
30637
30906
|
return { ok: true, value: n };
|
|
30638
30907
|
}
|
|
30639
30908
|
function resolveUiDist(ctx, raw) {
|
|
@@ -31930,9 +32199,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
31930
32199
|
return ExitCode.Error;
|
|
31931
32200
|
}
|
|
31932
32201
|
try {
|
|
31933
|
-
|
|
31934
|
-
mkdirSync6(dirname21(targetDir), { recursive: true });
|
|
31935
|
-
cpSync3(sourceDir, targetDir, { recursive: true });
|
|
32202
|
+
materializeSkillFolder(sourceDir, targetDir, ctx.cwd, target.marker);
|
|
31936
32203
|
} catch (err) {
|
|
31937
32204
|
this.printer.error(
|
|
31938
32205
|
tx(TUTORIAL_TEXTS.writeFailed, {
|
|
@@ -32023,6 +32290,14 @@ var TutorialCommand = class extends SmCommand {
|
|
|
32023
32290
|
return picked;
|
|
32024
32291
|
}
|
|
32025
32292
|
};
|
|
32293
|
+
function materializeSkillFolder(sourceDir, targetDir, cwd, marker) {
|
|
32294
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
32295
|
+
mkdirSync6(dirname21(targetDir), { recursive: true });
|
|
32296
|
+
cpSync3(sourceDir, targetDir, { recursive: true });
|
|
32297
|
+
if (marker !== void 0) {
|
|
32298
|
+
mkdirSync6(join21(cwd, marker), { recursive: true });
|
|
32299
|
+
}
|
|
32300
|
+
}
|
|
32026
32301
|
function toScaffoldTarget(provider, includeExperimental) {
|
|
32027
32302
|
const scaffold = provider.scaffold;
|
|
32028
32303
|
if (!scaffold || !scaffold.skillDir) return null;
|
|
@@ -32031,6 +32306,7 @@ function toScaffoldTarget(provider, includeExperimental) {
|
|
|
32031
32306
|
id: provider.id,
|
|
32032
32307
|
label: provider.presentation.label,
|
|
32033
32308
|
skillDir: scaffold.skillDir,
|
|
32309
|
+
...scaffold.marker !== void 0 ? { marker: scaffold.marker } : {},
|
|
32034
32310
|
aka: scaffold.aka ?? []
|
|
32035
32311
|
};
|
|
32036
32312
|
}
|
|
@@ -32339,4 +32615,4 @@ function resolveBareDefault() {
|
|
|
32339
32615
|
process.exit(ExitCode.Error);
|
|
32340
32616
|
}
|
|
32341
32617
|
//# sourceMappingURL=cli.js.map
|
|
32342
|
-
//# debugId=
|
|
32618
|
+
//# debugId=bde63370-f02c-51bb-92b1-0c58f46b6aee
|