@skill-map/cli 0.67.0 → 0.68.1
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 +30 -23
- 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 -4
- 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 +102 -49
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.json +168 -20
- package/dist/cli/tutorial/sm-tutorial/references/_manifest.yml +85 -19
- package/dist/cli/tutorial/sm-tutorial/references/fixtures.md +6 -7
- package/dist/cli/tutorial/sm-tutorial/references/part-authoring.md +2 -2
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-daily.md +241 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-fundamentals.md +351 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-basic-kickoff.md +285 -0
- package/dist/cli/tutorial/sm-tutorial/references/part-cli.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-daily-loop.md +62 -99
- package/dist/cli/tutorial/sm-tutorial/references/part-fundamentals.md +35 -34
- package/dist/cli/tutorial/sm-tutorial/references/part-mcp.md +3 -6
- package/dist/cli/tutorial/sm-tutorial/references/part-plugins.md +1 -1
- package/dist/cli/tutorial/sm-tutorial/references/part-project-kickoff.md +198 -26
- package/dist/cli/tutorial/sm-tutorial/references/part-settings.md +19 -15
- 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 +409 -168
- 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-22EQLC23.js +1845 -0
- package/dist/ui/chunk-3ANNEMV4.js +499 -0
- package/dist/ui/{chunk-5BJGO7GH.js → chunk-3U4QZKU2.js} +4 -4
- package/dist/ui/chunk-3ZAHOYQ7.js +1 -0
- package/dist/ui/{chunk-56CBK7LB.js → chunk-6FGV5O5J.js} +1 -1
- package/dist/ui/chunk-7WMT2LX4.js +1 -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-K3ZRQNN5.js +2 -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-TLMV4LOQ.js +3 -0
- 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-R7BIU4HU.js +4 -0
- package/dist/ui/styles-VEGETYWD.css +1 -0
- package/package.json +17 -18
- package/dist/cli/tutorial/sm-tutorial/references/part-connect-harness.md +0 -173
- package/dist/ui/chunk-34ZZDYNQ.js +0 -1
- package/dist/ui/chunk-444BFYGR.js +0 -3
- 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-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-V77F2KZX.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]="a842c024-162c-5a3a-85db-1daea4b6735f")}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.1",
|
|
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
|
}
|
|
@@ -1247,12 +1246,14 @@ var agentSkillsProvider = {
|
|
|
1247
1246
|
// Provider-owned.
|
|
1248
1247
|
detect: { markers: [".agents"] },
|
|
1249
1248
|
// Authoring target for `sm tutorial`: the open standard discovers skills
|
|
1250
|
-
// under `.agents/skills/<name>/SKILL.md`.
|
|
1251
|
-
//
|
|
1252
|
-
//
|
|
1253
|
-
//
|
|
1254
|
-
// `
|
|
1255
|
-
|
|
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"] },
|
|
1256
1257
|
read: COMMONS_READ,
|
|
1257
1258
|
kinds: COMMONS_KINDS,
|
|
1258
1259
|
resolution: COMMONS_RESOLUTION,
|
|
@@ -1473,6 +1474,12 @@ var codexProvider = {
|
|
|
1473
1474
|
// open-standard project, not necessarily a Codex one. A genuine Codex
|
|
1474
1475
|
// project is identified by `.codex/`.
|
|
1475
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" },
|
|
1476
1483
|
// Vendor provider: Codex CLI only reads its own territory (its `.codex/`
|
|
1477
1484
|
// agents plus the open `.agents/skills/` skills it adopted). Gating the
|
|
1478
1485
|
// classifier behind the active lens keeps the walker from claiming Codex
|
|
@@ -3656,7 +3663,7 @@ import { existsSync, readFileSync as readFileSync3 } from "fs";
|
|
|
3656
3663
|
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
3657
3664
|
import { createRequire as createRequire3 } from "module";
|
|
3658
3665
|
import { Ajv2020 as Ajv20203 } from "ajv/dist/2020.js";
|
|
3659
|
-
import
|
|
3666
|
+
import { load as yamlLoad, JSON_SCHEMA } from "js-yaml";
|
|
3660
3667
|
|
|
3661
3668
|
// kernel/util/strip-prototype-pollution.ts
|
|
3662
3669
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -3697,7 +3704,7 @@ function readSidecarFor(mdAbsolutePath) {
|
|
|
3697
3704
|
}
|
|
3698
3705
|
let parsedYaml;
|
|
3699
3706
|
try {
|
|
3700
|
-
parsedYaml =
|
|
3707
|
+
parsedYaml = yamlLoad(raw, { schema: JSON_SCHEMA });
|
|
3701
3708
|
} catch (err) {
|
|
3702
3709
|
return {
|
|
3703
3710
|
parsed: null,
|
|
@@ -5983,7 +5990,7 @@ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
|
5983
5990
|
import { dirname as dirname6, resolve as resolve8 } from "path";
|
|
5984
5991
|
import { createRequire as createRequire4 } from "module";
|
|
5985
5992
|
import { Ajv2020 as Ajv20204 } from "ajv/dist/2020.js";
|
|
5986
|
-
import
|
|
5993
|
+
import { dump as yamlDump, load as yamlLoad2, CORE_SCHEMA, JSON_SCHEMA as JSON_SCHEMA2 } from "js-yaml";
|
|
5987
5994
|
var FilesystemSidecarStore = class {
|
|
5988
5995
|
/**
|
|
5989
5996
|
* Path-keyed in-process lock chain. Each path maps to the tail of a
|
|
@@ -6035,11 +6042,13 @@ var FilesystemSidecarStore = class {
|
|
|
6035
6042
|
`sidecar patch produces a schema-invalid result at ${sidecarAbsPath}: ${errors}`
|
|
6036
6043
|
);
|
|
6037
6044
|
}
|
|
6038
|
-
const yamlText =
|
|
6045
|
+
const yamlText = yamlDump(merged, {
|
|
6039
6046
|
sortKeys: true,
|
|
6040
6047
|
lineWidth: -1,
|
|
6041
6048
|
noRefs: true,
|
|
6042
|
-
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
|
|
6043
6052
|
});
|
|
6044
6053
|
atomicWriteFile(sidecarAbsPath, yamlText);
|
|
6045
6054
|
}
|
|
@@ -6069,7 +6078,7 @@ function isPlainObject4(value) {
|
|
|
6069
6078
|
function readSidecarObject(sidecarAbsPath) {
|
|
6070
6079
|
if (!existsSync6(sidecarAbsPath)) return {};
|
|
6071
6080
|
const raw = readFileSync7(sidecarAbsPath, "utf8");
|
|
6072
|
-
const parsed =
|
|
6081
|
+
const parsed = yamlLoad2(raw, { schema: JSON_SCHEMA2 });
|
|
6073
6082
|
if (parsed === null || parsed === void 0) return {};
|
|
6074
6083
|
if (!isPlainObject4(parsed)) {
|
|
6075
6084
|
throw new Error(
|
|
@@ -6410,7 +6419,7 @@ var SmCommand = class extends Command {
|
|
|
6410
6419
|
};
|
|
6411
6420
|
|
|
6412
6421
|
// core/sqlite/with-sqlite.ts
|
|
6413
|
-
import { existsSync as
|
|
6422
|
+
import { existsSync as existsSync12 } from "fs";
|
|
6414
6423
|
|
|
6415
6424
|
// kernel/adapters/sqlite/storage-adapter.ts
|
|
6416
6425
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
@@ -9158,6 +9167,8 @@ function createSqliteStorage(options) {
|
|
|
9158
9167
|
}
|
|
9159
9168
|
|
|
9160
9169
|
// core/sqlite/db-version-check.ts
|
|
9170
|
+
import { existsSync as existsSync11 } from "fs";
|
|
9171
|
+
import { DatabaseSync as DatabaseSync5 } from "node:sqlite";
|
|
9161
9172
|
async function detectDbVersionSkew(db, currentVersion) {
|
|
9162
9173
|
const meta = await db.selectFrom("scan_meta").select(["scannedByVersion"]).executeTakeFirst();
|
|
9163
9174
|
if (!meta) return { kind: "no-meta" };
|
|
@@ -9187,6 +9198,20 @@ function classifyVersionSkew(dbVersion, currentVersion) {
|
|
|
9187
9198
|
}
|
|
9188
9199
|
return { kind: "warn-older", dbVersion, currentVersion };
|
|
9189
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
|
+
}
|
|
9190
9215
|
function parseVersionTriple(input) {
|
|
9191
9216
|
if (typeof input !== "string" || input.length === 0) return null;
|
|
9192
9217
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(input.trim());
|
|
@@ -9358,7 +9383,7 @@ async function withSqlite(options, fn) {
|
|
|
9358
9383
|
}
|
|
9359
9384
|
}
|
|
9360
9385
|
async function tryWithSqlite(options, fn) {
|
|
9361
|
-
if (options.databasePath !== ":memory:" && !
|
|
9386
|
+
if (options.databasePath !== ":memory:" && !existsSync12(options.databasePath)) {
|
|
9362
9387
|
return null;
|
|
9363
9388
|
}
|
|
9364
9389
|
return withSqlite(options, fn);
|
|
@@ -9962,6 +9987,15 @@ var CHECK_TEXTS = {
|
|
|
9962
9987
|
noIssues: "{{glyph}} No issues.\n",
|
|
9963
9988
|
/** Header summary line: `sm check: 10 warnings · 0 errors`. */
|
|
9964
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",
|
|
9965
9999
|
/** Section heading: one per file with at least one issue. */
|
|
9966
10000
|
fileSection: " {{file}}\n",
|
|
9967
10001
|
/**
|
|
@@ -10031,6 +10065,20 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
10031
10065
|
invalidManifestExtensionShape: "{{relEntry}}: {{errors}}. See {{docUrl}}.",
|
|
10032
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.).",
|
|
10033
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>`.",
|
|
10034
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.",
|
|
10035
10083
|
idCollision: "Plugin '{{id}}' at {{pathA}} collides with the plugin at {{pathB}}. Rename one and rerun.",
|
|
10036
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.",
|
|
@@ -10050,7 +10098,7 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
10050
10098
|
|
|
10051
10099
|
// kernel/adapters/plugin-loader/index.ts
|
|
10052
10100
|
import { createRequire as createRequire5 } from "module";
|
|
10053
|
-
import { existsSync as
|
|
10101
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
10054
10102
|
import { join as join8, resolve as resolve17 } from "path";
|
|
10055
10103
|
import { pathToFileURL } from "url";
|
|
10056
10104
|
import semver from "semver";
|
|
@@ -10153,7 +10201,7 @@ function stripFunctionsAndPluginId(input) {
|
|
|
10153
10201
|
|
|
10154
10202
|
// kernel/adapters/plugin-loader/validation.ts
|
|
10155
10203
|
import * as nodeFs from "fs";
|
|
10156
|
-
import { existsSync as
|
|
10204
|
+
import { existsSync as existsSync13 } from "fs";
|
|
10157
10205
|
import { dirname as dirname10, join as join7 } from "path";
|
|
10158
10206
|
import { Ajv2020 as Ajv20205 } from "ajv/dist/2020.js";
|
|
10159
10207
|
|
|
@@ -10279,7 +10327,7 @@ function validateActionFileConventions(pluginPath, pluginId, manifest, relEntry,
|
|
|
10279
10327
|
const reportSchemaPath = join7(actionDir, "report.schema.json");
|
|
10280
10328
|
const promptPath = join7(actionDir, "prompt.md");
|
|
10281
10329
|
const mode = isRecord(manifestView) && typeof manifestView["mode"] === "string" ? manifestView["mode"] : "deterministic";
|
|
10282
|
-
if (!
|
|
10330
|
+
if (!existsSync13(reportSchemaPath)) {
|
|
10283
10331
|
return {
|
|
10284
10332
|
...fail(
|
|
10285
10333
|
pluginPath,
|
|
@@ -10290,7 +10338,7 @@ function validateActionFileConventions(pluginPath, pluginId, manifest, relEntry,
|
|
|
10290
10338
|
manifest
|
|
10291
10339
|
};
|
|
10292
10340
|
}
|
|
10293
|
-
const promptExists =
|
|
10341
|
+
const promptExists = existsSync13(promptPath);
|
|
10294
10342
|
if (mode === "probabilistic" && !promptExists) {
|
|
10295
10343
|
return {
|
|
10296
10344
|
...fail(
|
|
@@ -10504,11 +10552,11 @@ var PluginLoader = class {
|
|
|
10504
10552
|
discoverPaths() {
|
|
10505
10553
|
const out = [];
|
|
10506
10554
|
for (const root of this.#options.searchPaths) {
|
|
10507
|
-
if (!
|
|
10555
|
+
if (!existsSync14(root)) continue;
|
|
10508
10556
|
for (const entry of readdirSync5(root, { withFileTypes: true })) {
|
|
10509
10557
|
if (!entry.isDirectory()) continue;
|
|
10510
10558
|
const candidate = join8(root, entry.name);
|
|
10511
|
-
if (
|
|
10559
|
+
if (existsSync14(join8(candidate, "plugin.json"))) {
|
|
10512
10560
|
out.push(resolve17(candidate));
|
|
10513
10561
|
}
|
|
10514
10562
|
}
|
|
@@ -10550,15 +10598,8 @@ var PluginLoader = class {
|
|
|
10550
10598
|
const manifestResult = this.#parseAndValidateManifest(pluginPath, pluginId);
|
|
10551
10599
|
if (!manifestResult.ok) return manifestResult.failure;
|
|
10552
10600
|
const manifest = manifestResult.manifest;
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
path: pluginPath,
|
|
10556
|
-
id: pluginId,
|
|
10557
|
-
status: "disabled",
|
|
10558
|
-
manifest,
|
|
10559
|
-
reason: PLUGIN_LOADER_TEXTS.disabledByConfig
|
|
10560
|
-
};
|
|
10561
|
-
}
|
|
10601
|
+
const gated = this.#preImportGate(pluginPath, pluginId, manifest);
|
|
10602
|
+
if (gated) return gated;
|
|
10562
10603
|
const loaded = [];
|
|
10563
10604
|
for (const relEntry of discoverExtensionEntries(pluginPath)) {
|
|
10564
10605
|
const result = await this.#loadAndValidateExtensionEntry(pluginPath, pluginId, manifest, relEntry);
|
|
@@ -10581,6 +10622,39 @@ var PluginLoader = class {
|
|
|
10581
10622
|
...storageSchemasResult.schemas ? { storageSchemas: storageSchemasResult.schemas } : {}
|
|
10582
10623
|
};
|
|
10583
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
|
+
}
|
|
10584
10658
|
/**
|
|
10585
10659
|
* Phase 1 of `loadOne`, read `plugin.json`, AJV-validate the manifest,
|
|
10586
10660
|
* enforce the directory-name == pluginId structural rule, and check
|
|
@@ -10669,7 +10743,7 @@ var PluginLoader = class {
|
|
|
10669
10743
|
} };
|
|
10670
10744
|
}
|
|
10671
10745
|
const abs = resolve17(pluginPath, relEntry);
|
|
10672
|
-
if (!
|
|
10746
|
+
if (!existsSync14(abs)) {
|
|
10673
10747
|
return { ok: false, failure: {
|
|
10674
10748
|
...fail(
|
|
10675
10749
|
pluginPath,
|
|
@@ -10873,7 +10947,7 @@ function discoverExtensionEntries(pluginPath) {
|
|
|
10873
10947
|
}
|
|
10874
10948
|
function collectKindEntries(pluginPath, kindDir, out) {
|
|
10875
10949
|
const kindAbs = resolve17(pluginPath, kindDir);
|
|
10876
|
-
if (!
|
|
10950
|
+
if (!existsSync14(kindAbs)) return;
|
|
10877
10951
|
let entries;
|
|
10878
10952
|
try {
|
|
10879
10953
|
entries = readdirSync5(kindAbs);
|
|
@@ -10900,7 +10974,7 @@ function isDirectorySafe2(path) {
|
|
|
10900
10974
|
}
|
|
10901
10975
|
function findIndexCandidate(entryAbs) {
|
|
10902
10976
|
for (const candidate of INDEX_CANDIDATES) {
|
|
10903
|
-
if (
|
|
10977
|
+
if (existsSync14(resolve17(entryAbs, candidate))) return candidate;
|
|
10904
10978
|
}
|
|
10905
10979
|
return null;
|
|
10906
10980
|
}
|
|
@@ -10967,6 +11041,17 @@ function resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault = tru
|
|
|
10967
11041
|
function makeEnabledResolver(cfg, dbOverrides) {
|
|
10968
11042
|
return (pluginId, installedDefault) => resolvePluginEnabled(pluginId, cfg, dbOverrides, installedDefault);
|
|
10969
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
|
+
}
|
|
10970
11055
|
|
|
10971
11056
|
// core/runtime/plugin-runtime/resolver.ts
|
|
10972
11057
|
function defaultResolveEnabled(_id, installedDefault = true) {
|
|
@@ -10984,7 +11069,7 @@ function isPluginExtensionEnabled(ext, resolveEnabled) {
|
|
|
10984
11069
|
installedDefaultEnabled(ext.stability)
|
|
10985
11070
|
);
|
|
10986
11071
|
}
|
|
10987
|
-
async function
|
|
11072
|
+
async function buildResolverInputs(ctx) {
|
|
10988
11073
|
const { effective: cfg } = loadConfig({ ...ctx });
|
|
10989
11074
|
const dbPath = resolveDbPath({
|
|
10990
11075
|
db: void 0,
|
|
@@ -10994,7 +11079,7 @@ async function buildEnabledResolver(ctx) {
|
|
|
10994
11079
|
{ databasePath: dbPath, autoBackup: false },
|
|
10995
11080
|
(adapter) => adapter.pluginConfig.loadOverrideMap()
|
|
10996
11081
|
) ?? /* @__PURE__ */ new Map();
|
|
10997
|
-
return makeEnabledResolver(cfg, dbOverrides);
|
|
11082
|
+
return { resolveEnabled: makeEnabledResolver(cfg, dbOverrides), dbOverrides };
|
|
10998
11083
|
}
|
|
10999
11084
|
|
|
11000
11085
|
// kernel/scan/walk-content.ts
|
|
@@ -11002,7 +11087,7 @@ import { readFile, readdir, lstat } from "fs/promises";
|
|
|
11002
11087
|
import { isAbsolute as isAbsolute4, join as join9, relative as relative2, resolve as resolve19, sep as sep3 } from "path";
|
|
11003
11088
|
|
|
11004
11089
|
// kernel/scan/ignore.ts
|
|
11005
|
-
import { existsSync as
|
|
11090
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
|
|
11006
11091
|
import { dirname as dirname11, resolve as resolve18 } from "path";
|
|
11007
11092
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11008
11093
|
import ignoreFactory from "ignore";
|
|
@@ -11033,7 +11118,7 @@ function loadBundledIgnoreText() {
|
|
|
11033
11118
|
}
|
|
11034
11119
|
function readIgnoreFileText(scopeRoot) {
|
|
11035
11120
|
const path = resolve18(scopeRoot, ".skillmapignore");
|
|
11036
|
-
if (!
|
|
11121
|
+
if (!existsSync15(path)) return void 0;
|
|
11037
11122
|
try {
|
|
11038
11123
|
return readFileSync14(path, "utf8");
|
|
11039
11124
|
} catch {
|
|
@@ -11068,7 +11153,7 @@ function readDefaultsFromDisk() {
|
|
|
11068
11153
|
resolve18(here, "config/defaults/skillmapignore")
|
|
11069
11154
|
];
|
|
11070
11155
|
for (const candidate of candidates) {
|
|
11071
|
-
if (
|
|
11156
|
+
if (existsSync15(candidate)) {
|
|
11072
11157
|
try {
|
|
11073
11158
|
return readFileSync14(candidate, "utf8");
|
|
11074
11159
|
} catch {
|
|
@@ -11079,7 +11164,7 @@ function readDefaultsFromDisk() {
|
|
|
11079
11164
|
}
|
|
11080
11165
|
|
|
11081
11166
|
// plugins/core/parsers/frontmatter-yaml/index.ts
|
|
11082
|
-
import
|
|
11167
|
+
import { load as yamlLoad3, JSON_SCHEMA as JSON_SCHEMA3 } from "js-yaml";
|
|
11083
11168
|
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
11084
11169
|
var frontmatterYamlParser = {
|
|
11085
11170
|
id: "frontmatter-yaml",
|
|
@@ -11091,7 +11176,7 @@ var frontmatterYamlParser = {
|
|
|
11091
11176
|
let parsed = {};
|
|
11092
11177
|
const issues = [];
|
|
11093
11178
|
try {
|
|
11094
|
-
const doc =
|
|
11179
|
+
const doc = yamlLoad3(frontmatterRaw, { schema: JSON_SCHEMA3 });
|
|
11095
11180
|
if (doc && typeof doc === "object" && !Array.isArray(doc)) {
|
|
11096
11181
|
parsed = stripPrototypePollution(doc);
|
|
11097
11182
|
}
|
|
@@ -11531,8 +11616,11 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11531
11616
|
const searchPaths = resolveSearchPaths(opts, ctx);
|
|
11532
11617
|
const validators = loadSchemaValidators();
|
|
11533
11618
|
let resolveEnabled;
|
|
11619
|
+
let dbOverrides;
|
|
11534
11620
|
try {
|
|
11535
|
-
|
|
11621
|
+
const inputs = await buildResolverInputs(ctx);
|
|
11622
|
+
resolveEnabled = inputs.resolveEnabled;
|
|
11623
|
+
dbOverrides = inputs.dbOverrides;
|
|
11536
11624
|
} catch {
|
|
11537
11625
|
}
|
|
11538
11626
|
const loaderOpts = {
|
|
@@ -11541,6 +11629,9 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11541
11629
|
specVersion: installedSpecVersion()
|
|
11542
11630
|
};
|
|
11543
11631
|
if (resolveEnabled) loaderOpts.resolveEnabled = resolveEnabled;
|
|
11632
|
+
if (!opts.pluginDir) {
|
|
11633
|
+
loaderOpts.resolveImportTrust = makeImportTrustResolver(dbOverrides ?? /* @__PURE__ */ new Map());
|
|
11634
|
+
}
|
|
11544
11635
|
const loader = createPluginLoader(loaderOpts);
|
|
11545
11636
|
const discovered = await loader.discoverAndLoadAll();
|
|
11546
11637
|
const runtime = {
|
|
@@ -11563,6 +11654,12 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
11563
11654
|
if (plugin.status === "disabled") continue;
|
|
11564
11655
|
runtime.warnings.push(formatWarning(plugin));
|
|
11565
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
|
+
}
|
|
11566
11663
|
enforceRootExclusivity(runtime.annotationContributions);
|
|
11567
11664
|
return runtime;
|
|
11568
11665
|
}
|
|
@@ -12001,15 +12098,27 @@ function groupRowsByFile(rows) {
|
|
|
12001
12098
|
function formatSummary(counts, ansi) {
|
|
12002
12099
|
const parts = [];
|
|
12003
12100
|
if (counts.error > 0) {
|
|
12004
|
-
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
|
+
);
|
|
12005
12109
|
}
|
|
12006
12110
|
if (counts.warn > 0) {
|
|
12007
12111
|
parts.push(
|
|
12008
|
-
ansi.yellow(
|
|
12112
|
+
ansi.yellow(
|
|
12113
|
+
tx(CHECK_TEXTS.summaryWarningFragment, {
|
|
12114
|
+
count: counts.warn,
|
|
12115
|
+
plural: counts.warn === 1 ? "" : "s"
|
|
12116
|
+
})
|
|
12117
|
+
)
|
|
12009
12118
|
);
|
|
12010
12119
|
}
|
|
12011
12120
|
if (counts.info > 0) {
|
|
12012
|
-
parts.push(ansi.cyan(
|
|
12121
|
+
parts.push(ansi.cyan(tx(CHECK_TEXTS.summaryInfoFragment, { count: counts.info })));
|
|
12013
12122
|
}
|
|
12014
12123
|
return parts.join(" \xB7 ");
|
|
12015
12124
|
}
|
|
@@ -12034,11 +12143,11 @@ function flattenMessage(message) {
|
|
|
12034
12143
|
}
|
|
12035
12144
|
|
|
12036
12145
|
// cli/commands/config.ts
|
|
12037
|
-
import { existsSync as
|
|
12146
|
+
import { existsSync as existsSync17 } from "fs";
|
|
12038
12147
|
import { Command as Command4, Option as Option4 } from "clipanion";
|
|
12039
12148
|
|
|
12040
12149
|
// kernel/scan/detect-providers.ts
|
|
12041
|
-
import { existsSync as
|
|
12150
|
+
import { existsSync as existsSync16 } from "fs";
|
|
12042
12151
|
import { join as join10 } from "path";
|
|
12043
12152
|
function detectProvidersFromFilesystem(cwd, providers) {
|
|
12044
12153
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -12055,7 +12164,7 @@ function isDetectableUnderCwd(cwd, provider) {
|
|
|
12055
12164
|
if (!installedDefaultEnabled(provider.stability)) return false;
|
|
12056
12165
|
const markers = provider.detect?.markers;
|
|
12057
12166
|
if (!markers || markers.length === 0) return false;
|
|
12058
|
-
return markers.some((marker) =>
|
|
12167
|
+
return markers.some((marker) => existsSync16(join10(cwd, marker)));
|
|
12059
12168
|
}
|
|
12060
12169
|
|
|
12061
12170
|
// core/config/active-provider.ts
|
|
@@ -12083,7 +12192,7 @@ function relativeIfBelow(path, cwd) {
|
|
|
12083
12192
|
}
|
|
12084
12193
|
|
|
12085
12194
|
// cli/util/scan-zone-drop.ts
|
|
12086
|
-
import { DatabaseSync as
|
|
12195
|
+
import { DatabaseSync as DatabaseSync6 } from "node:sqlite";
|
|
12087
12196
|
|
|
12088
12197
|
// cli/commands/db/shared.ts
|
|
12089
12198
|
var SAFE_SQL_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
@@ -12095,7 +12204,7 @@ function assertSafeIdentifier(name) {
|
|
|
12095
12204
|
|
|
12096
12205
|
// cli/util/scan-zone-drop.ts
|
|
12097
12206
|
function dropScanZone(dbPath) {
|
|
12098
|
-
const db = new
|
|
12207
|
+
const db = new DatabaseSync6(dbPath);
|
|
12099
12208
|
try {
|
|
12100
12209
|
const rows = db.prepare(
|
|
12101
12210
|
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'scan\\_%' ESCAPE '\\'"
|
|
@@ -12686,7 +12795,7 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
12686
12795
|
announceLensSwitch(cwd, ansi) {
|
|
12687
12796
|
const dbPath = resolveDbPath({ db: void 0, cwd });
|
|
12688
12797
|
const okGlyph = ansi.green("\u2713");
|
|
12689
|
-
if (!
|
|
12798
|
+
if (!existsSync17(dbPath)) {
|
|
12690
12799
|
this.printer.info(tx(CONFIG_TEXTS.lensSwitchedNoDb, { glyph: okGlyph }));
|
|
12691
12800
|
return;
|
|
12692
12801
|
}
|
|
@@ -12726,7 +12835,7 @@ var ConfigResetCommand = class extends SmCommand {
|
|
|
12726
12835
|
const path = targetSettingsPath2(target, ctx.cwd);
|
|
12727
12836
|
const ansi = this.ansiFor("stdout");
|
|
12728
12837
|
const okGlyph = ansi.green("\u2713");
|
|
12729
|
-
if (!
|
|
12838
|
+
if (!existsSync17(path)) {
|
|
12730
12839
|
this.printer.data(
|
|
12731
12840
|
tx(CONFIG_TEXTS.unsetNoOverride, {
|
|
12732
12841
|
glyph: okGlyph,
|
|
@@ -12801,16 +12910,17 @@ var CONFIG_COMMANDS = [
|
|
|
12801
12910
|
];
|
|
12802
12911
|
|
|
12803
12912
|
// cli/commands/conformance.ts
|
|
12804
|
-
import { existsSync as
|
|
12913
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
|
|
12805
12914
|
import { dirname as dirname13, resolve as resolve23 } from "path";
|
|
12806
12915
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12807
12916
|
import { Command as Command5, Option as Option5 } from "clipanion";
|
|
12808
12917
|
|
|
12809
12918
|
// conformance/index.ts
|
|
12810
12919
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12811
|
-
import { cpSync, existsSync as
|
|
12920
|
+
import { cpSync, existsSync as existsSync18, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync15, rmSync, statSync as statSync3 } from "fs";
|
|
12812
12921
|
import { tmpdir } from "os";
|
|
12813
12922
|
import { isAbsolute as isAbsolute6, join as join11, relative as relative3, resolve as resolve21 } from "path";
|
|
12923
|
+
import { DatabaseSync as DatabaseSync7 } from "node:sqlite";
|
|
12814
12924
|
|
|
12815
12925
|
// conformance/i18n/runner.texts.ts
|
|
12816
12926
|
var CONFORMANCE_RUNNER_TEXTS = {
|
|
@@ -12902,6 +13012,11 @@ function runConformanceCase(options) {
|
|
|
12902
13012
|
if (c.fixture) {
|
|
12903
13013
|
replaceFixture(scope, fixturesRoot, c.fixture);
|
|
12904
13014
|
}
|
|
13015
|
+
grantFixturePluginTrust(scope, options.binary, {
|
|
13016
|
+
...pickSafeEnv(process.env),
|
|
13017
|
+
...options.env,
|
|
13018
|
+
...setupEnv
|
|
13019
|
+
});
|
|
12905
13020
|
const argv = [c.invoke.verb];
|
|
12906
13021
|
if (c.invoke.sub) argv.push(c.invoke.sub);
|
|
12907
13022
|
if (c.invoke.args) argv.push(...c.invoke.args);
|
|
@@ -12971,6 +13086,40 @@ function replaceFixture(scope, fixturesRoot, fixture) {
|
|
|
12971
13086
|
const src = join11(fixturesRoot, fixture);
|
|
12972
13087
|
cpSync(src, scope, { recursive: true });
|
|
12973
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
|
+
}
|
|
12974
13123
|
function assertContained2(root, rel, label) {
|
|
12975
13124
|
if (isAbsolute6(rel)) {
|
|
12976
13125
|
throw new Error(
|
|
@@ -13005,7 +13154,7 @@ function evaluateAssertion(a, ctx) {
|
|
|
13005
13154
|
return { ok: false, type: a.type, reason: formatErrorMessage(err) };
|
|
13006
13155
|
}
|
|
13007
13156
|
const abs = resolve21(ctx.scope, a.path);
|
|
13008
|
-
return
|
|
13157
|
+
return existsSync18(abs) ? { ok: true, type: a.type } : {
|
|
13009
13158
|
ok: false,
|
|
13010
13159
|
type: a.type,
|
|
13011
13160
|
reason: tx(CONFORMANCE_RUNNER_TEXTS.fileNotFound, { path: a.path })
|
|
@@ -13020,7 +13169,7 @@ function evaluateAssertion(a, ctx) {
|
|
|
13020
13169
|
}
|
|
13021
13170
|
const fixturePath = join11(ctx.fixturesRoot, a.fixture);
|
|
13022
13171
|
const targetPath = resolve21(ctx.scope, a.path);
|
|
13023
|
-
if (!
|
|
13172
|
+
if (!existsSync18(targetPath)) {
|
|
13024
13173
|
return {
|
|
13025
13174
|
ok: false,
|
|
13026
13175
|
type: a.type,
|
|
@@ -13201,7 +13350,7 @@ var CONFORMANCE_TEXTS = {
|
|
|
13201
13350
|
};
|
|
13202
13351
|
|
|
13203
13352
|
// cli/util/conformance-scopes.ts
|
|
13204
|
-
import { existsSync as
|
|
13353
|
+
import { existsSync as existsSync19, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
|
|
13205
13354
|
import { dirname as dirname12, resolve as resolve22 } from "path";
|
|
13206
13355
|
import { createRequire as createRequire6 } from "module";
|
|
13207
13356
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -13221,7 +13370,7 @@ function resolveCliWorkspaceRoot() {
|
|
|
13221
13370
|
let cursor = here;
|
|
13222
13371
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
13223
13372
|
const candidate = resolve22(cursor, "plugins");
|
|
13224
|
-
if (
|
|
13373
|
+
if (existsSync19(candidate) && statSync4(candidate).isDirectory()) {
|
|
13225
13374
|
return cursor;
|
|
13226
13375
|
}
|
|
13227
13376
|
const parent = dirname12(cursor);
|
|
@@ -13241,7 +13390,7 @@ function collectProviderScopes(specRoot) {
|
|
|
13241
13390
|
return out;
|
|
13242
13391
|
}
|
|
13243
13392
|
const pluginsRoot = resolve22(workspaceRoot, "plugins");
|
|
13244
|
-
if (!
|
|
13393
|
+
if (!existsSync19(pluginsRoot)) return out;
|
|
13245
13394
|
for (const pluginEntry of readdirSync7(pluginsRoot)) {
|
|
13246
13395
|
const pluginDir = resolve22(pluginsRoot, pluginEntry);
|
|
13247
13396
|
if (!isDir(pluginDir)) continue;
|
|
@@ -13253,7 +13402,7 @@ function collectProviderScopes(specRoot) {
|
|
|
13253
13402
|
}
|
|
13254
13403
|
function isDir(path) {
|
|
13255
13404
|
try {
|
|
13256
|
-
return
|
|
13405
|
+
return existsSync19(path) && statSync4(path).isDirectory();
|
|
13257
13406
|
} catch {
|
|
13258
13407
|
return false;
|
|
13259
13408
|
}
|
|
@@ -13263,10 +13412,10 @@ function collectPluginProviderScopes(providersRoot, specRoot, out) {
|
|
|
13263
13412
|
const providerDir = resolve22(providersRoot, entry);
|
|
13264
13413
|
if (!isDir(providerDir)) continue;
|
|
13265
13414
|
const conformanceDir = resolve22(providerDir, "conformance");
|
|
13266
|
-
if (!
|
|
13415
|
+
if (!existsSync19(conformanceDir)) continue;
|
|
13267
13416
|
const casesDir = resolve22(conformanceDir, "cases");
|
|
13268
13417
|
const fixturesDir = resolve22(conformanceDir, "fixtures");
|
|
13269
|
-
if (!
|
|
13418
|
+
if (!existsSync19(casesDir) || !existsSync19(fixturesDir)) continue;
|
|
13270
13419
|
out.push({
|
|
13271
13420
|
id: `provider:${entry}`,
|
|
13272
13421
|
kind: "provider",
|
|
@@ -13304,7 +13453,7 @@ function selectConformanceScopes(scope) {
|
|
|
13304
13453
|
return [match];
|
|
13305
13454
|
}
|
|
13306
13455
|
function listCaseFiles(scope) {
|
|
13307
|
-
if (!
|
|
13456
|
+
if (!existsSync19(scope.casesDir)) return [];
|
|
13308
13457
|
return readdirSync7(scope.casesDir).filter((entry) => entry.endsWith(".json")).sort().map((entry) => resolve22(scope.casesDir, entry));
|
|
13309
13458
|
}
|
|
13310
13459
|
|
|
@@ -13323,7 +13472,7 @@ function resolveBinary() {
|
|
|
13323
13472
|
let cursor = here;
|
|
13324
13473
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
13325
13474
|
const candidate = resolve23(cursor, "bin", "sm.js");
|
|
13326
|
-
if (
|
|
13475
|
+
if (existsSync20(candidate)) return candidate;
|
|
13327
13476
|
const parent = dirname13(cursor);
|
|
13328
13477
|
if (parent === cursor) break;
|
|
13329
13478
|
cursor = parent;
|
|
@@ -13389,7 +13538,7 @@ var ConformanceRunCommand = class extends SmCommand {
|
|
|
13389
13538
|
return ExitCode.Error;
|
|
13390
13539
|
}
|
|
13391
13540
|
const binary = resolveBinary();
|
|
13392
|
-
if (!
|
|
13541
|
+
if (!existsSync20(binary)) {
|
|
13393
13542
|
if (this.json) {
|
|
13394
13543
|
this.#emitJsonError(
|
|
13395
13544
|
"internal",
|
|
@@ -13607,6 +13756,20 @@ var DB_TEXTS = {
|
|
|
13607
13756
|
*/
|
|
13608
13757
|
restoreSourceNotFound: "{{glyph}} Backup not found: {{sourcePath}}\n {{hint}}\n",
|
|
13609
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.",
|
|
13610
13773
|
restoreConfirm: "Restore {{sourcePath}} over {{target}}? This overwrites the current DB.",
|
|
13611
13774
|
restoreDone: "{{glyph}} Restored {{sourcePath}} \u2192 {{target}}\n",
|
|
13612
13775
|
// --- shared ----------------------------------------------------------
|
|
@@ -13734,6 +13897,39 @@ async function statOrNull(path) {
|
|
|
13734
13897
|
}
|
|
13735
13898
|
}
|
|
13736
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
|
+
|
|
13737
13933
|
// cli/commands/db/restore.ts
|
|
13738
13934
|
async function chmodOwnerOnlyBestEffort(target) {
|
|
13739
13935
|
try {
|
|
@@ -13774,19 +13970,13 @@ var DbRestoreCommand = class extends SmCommand {
|
|
|
13774
13970
|
);
|
|
13775
13971
|
return ExitCode.NotFound;
|
|
13776
13972
|
}
|
|
13973
|
+
const validation = await validateRestorableDb(sourcePath, VERSION);
|
|
13974
|
+
if (!validation.ok) {
|
|
13975
|
+
this.printValidationError(validation, sourcePath);
|
|
13976
|
+
return ExitCode.Error;
|
|
13977
|
+
}
|
|
13777
13978
|
if (this.dryRun) {
|
|
13778
|
-
this.
|
|
13779
|
-
const sourceBytes = sourceStat.size;
|
|
13780
|
-
const targetClause = await pathExists(target) ? DB_TEXTS.dryRunRestoreTargetExistsClause : DB_TEXTS.dryRunRestoreTargetMissingClause;
|
|
13781
|
-
this.printer.data(
|
|
13782
|
-
tx(DB_TEXTS.dryRunRestoreWouldOverwrite, {
|
|
13783
|
-
sourcePath,
|
|
13784
|
-
sourceBytes,
|
|
13785
|
-
target,
|
|
13786
|
-
targetClause
|
|
13787
|
-
})
|
|
13788
|
-
);
|
|
13789
|
-
return ExitCode.Ok;
|
|
13979
|
+
return this.previewRestore(sourcePath, sourceStat.size, target);
|
|
13790
13980
|
}
|
|
13791
13981
|
if (!this.yes) {
|
|
13792
13982
|
const ok = await confirm(tx(DB_TEXTS.restoreConfirm, { sourcePath, target }), {
|
|
@@ -13815,21 +14005,65 @@ var DbRestoreCommand = class extends SmCommand {
|
|
|
13815
14005
|
);
|
|
13816
14006
|
return ExitCode.Ok;
|
|
13817
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
|
+
}
|
|
13818
14052
|
};
|
|
13819
14053
|
|
|
13820
14054
|
// cli/commands/db/reset.ts
|
|
13821
|
-
import { DatabaseSync as
|
|
14055
|
+
import { DatabaseSync as DatabaseSync8 } from "node:sqlite";
|
|
13822
14056
|
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
13823
14057
|
|
|
13824
14058
|
// core/sqlite/db-files.ts
|
|
13825
|
-
import { existsSync as
|
|
14059
|
+
import { existsSync as existsSync21 } from "fs";
|
|
13826
14060
|
import { rm as rm2 } from "fs/promises";
|
|
13827
14061
|
var DB_FILE_SUFFIXES = ["", "-wal", "-shm"];
|
|
13828
14062
|
async function removeDbFiles(dbPath) {
|
|
13829
14063
|
if (dbPath === ":memory:") return;
|
|
13830
14064
|
for (const suffix of DB_FILE_SUFFIXES) {
|
|
13831
14065
|
const p = `${dbPath}${suffix}`;
|
|
13832
|
-
if (
|
|
14066
|
+
if (existsSync21(p)) await rm2(p);
|
|
13833
14067
|
}
|
|
13834
14068
|
}
|
|
13835
14069
|
|
|
@@ -13915,7 +14149,7 @@ var DbResetCommand = class extends SmCommand {
|
|
|
13915
14149
|
return ExitCode.Error;
|
|
13916
14150
|
}
|
|
13917
14151
|
}
|
|
13918
|
-
const db = new
|
|
14152
|
+
const db = new DatabaseSync8(path);
|
|
13919
14153
|
try {
|
|
13920
14154
|
const rows = db.prepare(
|
|
13921
14155
|
"SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE 'scan\\_%' ESCAPE '\\'" + (this.state ? " OR name LIKE 'state\\_%' ESCAPE '\\'" : "") + ")"
|
|
@@ -14058,7 +14292,7 @@ var DbBrowserCommand = class extends SmCommand {
|
|
|
14058
14292
|
};
|
|
14059
14293
|
|
|
14060
14294
|
// cli/commands/db/dump.ts
|
|
14061
|
-
import { DatabaseSync as
|
|
14295
|
+
import { DatabaseSync as DatabaseSync9 } from "node:sqlite";
|
|
14062
14296
|
import { Command as Command11, Option as Option10 } from "clipanion";
|
|
14063
14297
|
var DbDumpCommand = class extends SmCommand {
|
|
14064
14298
|
static paths = [["db", "dump"]];
|
|
@@ -14100,7 +14334,7 @@ var DbDumpCommand = class extends SmCommand {
|
|
|
14100
14334
|
}
|
|
14101
14335
|
};
|
|
14102
14336
|
function dumpDatabaseToStream(dbPath, out, tables) {
|
|
14103
|
-
const db = new
|
|
14337
|
+
const db = new DatabaseSync9(dbPath, { readOnly: true });
|
|
14104
14338
|
try {
|
|
14105
14339
|
out.write("PRAGMA foreign_keys=OFF;\n");
|
|
14106
14340
|
out.write("BEGIN TRANSACTION;\n");
|
|
@@ -14175,6 +14409,10 @@ function tryParseNonNegativeInt(raw) {
|
|
|
14175
14409
|
}
|
|
14176
14410
|
return parsed;
|
|
14177
14411
|
}
|
|
14412
|
+
function tryParsePositiveInt(raw) {
|
|
14413
|
+
const parsed = tryParseNonNegativeInt(raw);
|
|
14414
|
+
return parsed === null || parsed === 0 ? null : parsed;
|
|
14415
|
+
}
|
|
14178
14416
|
function parsePositiveIntegerOption(raw, label, stderr) {
|
|
14179
14417
|
const parsed = tryParseNonNegativeInt(raw);
|
|
14180
14418
|
if (parsed === null || parsed === 0) {
|
|
@@ -14435,7 +14673,7 @@ var DB_COMMANDS = [
|
|
|
14435
14673
|
];
|
|
14436
14674
|
|
|
14437
14675
|
// cli/commands/example.ts
|
|
14438
|
-
import { cpSync as cpSync2, existsSync as
|
|
14676
|
+
import { cpSync as cpSync2, existsSync as existsSync22, statSync as statSync5 } from "fs";
|
|
14439
14677
|
import { dirname as dirname16, relative as relative5, resolve as resolve27 } from "path";
|
|
14440
14678
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
14441
14679
|
import { Command as Command13, Option as Option12 } from "clipanion";
|
|
@@ -14739,7 +14977,7 @@ function resolveExampleSourceDir() {
|
|
|
14739
14977
|
resolve27(here, "../cli/example")
|
|
14740
14978
|
];
|
|
14741
14979
|
for (const candidate of candidates) {
|
|
14742
|
-
if (
|
|
14980
|
+
if (existsSync22(candidate) && statSync5(candidate).isDirectory()) {
|
|
14743
14981
|
cachedSourceDir = candidate;
|
|
14744
14982
|
return candidate;
|
|
14745
14983
|
}
|
|
@@ -14751,7 +14989,7 @@ function resolveExampleSourceDir() {
|
|
|
14751
14989
|
function isExamplePayloadEntry(sourceRoot, src) {
|
|
14752
14990
|
const rel = relative5(sourceRoot, src);
|
|
14753
14991
|
if (rel === "") return true;
|
|
14754
|
-
return rel.split(/[\\/]/)[0] !==
|
|
14992
|
+
return rel.split(/[\\/]/)[0] !== SKILL_MAP_DIR;
|
|
14755
14993
|
}
|
|
14756
14994
|
|
|
14757
14995
|
// cli/commands/export.ts
|
|
@@ -16083,7 +16321,7 @@ import { join as join16 } from "path";
|
|
|
16083
16321
|
import { Command as Command18, Option as Option17 } from "clipanion";
|
|
16084
16322
|
|
|
16085
16323
|
// kernel/orchestrator/index.ts
|
|
16086
|
-
import { existsSync as
|
|
16324
|
+
import { existsSync as existsSync25, statSync as statSync7 } from "fs";
|
|
16087
16325
|
import { isAbsolute as isAbsolute10, resolve as resolve32 } from "path";
|
|
16088
16326
|
import { Tiktoken as Tiktoken2 } from "js-tiktoken/lite";
|
|
16089
16327
|
|
|
@@ -17453,7 +17691,7 @@ function computeDriftStatus(args2) {
|
|
|
17453
17691
|
}
|
|
17454
17692
|
|
|
17455
17693
|
// kernel/sidecar/discover-orphans.ts
|
|
17456
|
-
import { existsSync as
|
|
17694
|
+
import { existsSync as existsSync23, readdirSync as readdirSync8, statSync as statSync6 } from "fs";
|
|
17457
17695
|
import { join as join13, relative as relative6, sep as sep4 } from "path";
|
|
17458
17696
|
function discoverOrphanSidecars(roots, shouldSkip) {
|
|
17459
17697
|
const out = [];
|
|
@@ -17481,7 +17719,7 @@ function walk2(root, current, shouldSkip, out) {
|
|
|
17481
17719
|
if (!entry.isFile()) continue;
|
|
17482
17720
|
if (!entry.name.endsWith(".sm")) continue;
|
|
17483
17721
|
const expectedMd = `${full.slice(0, -".sm".length)}.md`;
|
|
17484
|
-
if (
|
|
17722
|
+
if (existsSync23(expectedMd) && safeIsFile(expectedMd)) continue;
|
|
17485
17723
|
out.push({ sidecarPath: full, relativePath: rel, expectedMdPath: expectedMd });
|
|
17486
17724
|
}
|
|
17487
17725
|
}
|
|
@@ -17495,10 +17733,10 @@ function safeIsFile(path) {
|
|
|
17495
17733
|
|
|
17496
17734
|
// kernel/orchestrator/node-build.ts
|
|
17497
17735
|
import { createHash as createHash2 } from "crypto";
|
|
17498
|
-
import { existsSync as
|
|
17736
|
+
import { existsSync as existsSync24 } from "fs";
|
|
17499
17737
|
import { isAbsolute as isAbsolute8, resolve as resolvePath } from "path";
|
|
17500
17738
|
import "js-tiktoken/lite";
|
|
17501
|
-
import
|
|
17739
|
+
import { dump as yamlDump2, CORE_SCHEMA as CORE_SCHEMA2 } from "js-yaml";
|
|
17502
17740
|
|
|
17503
17741
|
// kernel/orchestrator/frontmatter.ts
|
|
17504
17742
|
function validateFrontmatter(providerFrontmatter, provider, kind, frontmatter, path, strict) {
|
|
@@ -17591,22 +17829,22 @@ function canonicalFrontmatter(parsed, raw) {
|
|
|
17591
17829
|
if (!hasParsedKeys && hasRawText) {
|
|
17592
17830
|
return raw;
|
|
17593
17831
|
}
|
|
17594
|
-
return
|
|
17832
|
+
return yamlDump2(parsed, {
|
|
17595
17833
|
sortKeys: true,
|
|
17596
17834
|
lineWidth: -1,
|
|
17597
17835
|
noRefs: true,
|
|
17598
|
-
|
|
17836
|
+
schema: CORE_SCHEMA2
|
|
17599
17837
|
});
|
|
17600
17838
|
}
|
|
17601
17839
|
function canonicalSidecarAnnotations(annotations) {
|
|
17602
17840
|
if (!annotations || typeof annotations !== "object" || Array.isArray(annotations)) {
|
|
17603
|
-
return
|
|
17841
|
+
return yamlDump2({}, { sortKeys: true, lineWidth: -1, noRefs: true, schema: CORE_SCHEMA2 });
|
|
17604
17842
|
}
|
|
17605
|
-
return
|
|
17843
|
+
return yamlDump2(annotations, {
|
|
17606
17844
|
sortKeys: true,
|
|
17607
17845
|
lineWidth: -1,
|
|
17608
17846
|
noRefs: true,
|
|
17609
|
-
|
|
17847
|
+
schema: CORE_SCHEMA2
|
|
17610
17848
|
});
|
|
17611
17849
|
}
|
|
17612
17850
|
function resolveSidecarOverlay(relativePath2, nodePathForIssue, roots, liveBodyHash, liveFrontmatterHash) {
|
|
@@ -17660,11 +17898,11 @@ function resolveSidecarOverlay(relativePath2, nodePathForIssue, roots, liveBodyH
|
|
|
17660
17898
|
}
|
|
17661
17899
|
function resolveAbsoluteMdPath(relativePath2, roots) {
|
|
17662
17900
|
if (isAbsolute8(relativePath2)) {
|
|
17663
|
-
return
|
|
17901
|
+
return existsSync24(relativePath2) ? relativePath2 : null;
|
|
17664
17902
|
}
|
|
17665
17903
|
for (const root of roots) {
|
|
17666
17904
|
const candidate = resolvePath(root, relativePath2);
|
|
17667
|
-
if (
|
|
17905
|
+
if (existsSync24(candidate)) return candidate;
|
|
17668
17906
|
}
|
|
17669
17907
|
return null;
|
|
17670
17908
|
}
|
|
@@ -18477,7 +18715,7 @@ function validateRoots(roots) {
|
|
|
18477
18715
|
throw new Error(ORCHESTRATOR_TEXTS.runScanRootEmptyArray);
|
|
18478
18716
|
}
|
|
18479
18717
|
for (const root of roots) {
|
|
18480
|
-
if (!
|
|
18718
|
+
if (!existsSync25(root) || !statSync7(root).isDirectory()) {
|
|
18481
18719
|
throw new Error(tx(ORCHESTRATOR_TEXTS.runScanRootMissing, { root }));
|
|
18482
18720
|
}
|
|
18483
18721
|
}
|
|
@@ -18486,7 +18724,7 @@ function resolveActiveProviderOption(optionValue, roots, providers) {
|
|
|
18486
18724
|
if (optionValue !== void 0) return optionValue;
|
|
18487
18725
|
for (const root of roots) {
|
|
18488
18726
|
const absRoot = isAbsolute10(root) ? root : resolve32(root);
|
|
18489
|
-
if (!
|
|
18727
|
+
if (!existsSync25(absRoot)) continue;
|
|
18490
18728
|
const detected = detectProvidersFromFilesystem(absRoot, providers)[0] ?? null;
|
|
18491
18729
|
if (detected !== null) return detected;
|
|
18492
18730
|
}
|
|
@@ -19232,9 +19470,7 @@ async function promptForLens(detected, stdin, stderr, warnGlyph) {
|
|
|
19232
19470
|
}
|
|
19233
19471
|
|
|
19234
19472
|
// core/sqlite/db-drift-reset.ts
|
|
19235
|
-
import { existsSync as existsSync25 } from "fs";
|
|
19236
19473
|
import { createInterface as createInterface5 } from "readline";
|
|
19237
|
-
import { DatabaseSync as DatabaseSync8 } from "node:sqlite";
|
|
19238
19474
|
|
|
19239
19475
|
// core/sqlite/i18n/db-drift.texts.ts
|
|
19240
19476
|
var DB_DRIFT_TEXTS = {
|
|
@@ -19283,20 +19519,6 @@ function detectDriftReason(dbPath, currentVersion) {
|
|
|
19283
19519
|
}
|
|
19284
19520
|
return classifyFingerprint(dbPath).kind === "drift" ? "schema" : null;
|
|
19285
19521
|
}
|
|
19286
|
-
function readScannedByVersion(dbPath) {
|
|
19287
|
-
if (dbPath === ":memory:" || !existsSync25(dbPath)) return null;
|
|
19288
|
-
let raw = null;
|
|
19289
|
-
try {
|
|
19290
|
-
raw = new DatabaseSync8(dbPath, { readOnly: true });
|
|
19291
|
-
const row = raw.prepare("SELECT scanned_by_version AS v FROM scan_meta LIMIT 1").get();
|
|
19292
|
-
const v = row?.v;
|
|
19293
|
-
return typeof v === "string" && v.length > 0 ? v : null;
|
|
19294
|
-
} catch {
|
|
19295
|
-
return null;
|
|
19296
|
-
} finally {
|
|
19297
|
-
raw?.close();
|
|
19298
|
-
}
|
|
19299
|
-
}
|
|
19300
19522
|
function reasonText(reason) {
|
|
19301
19523
|
return reason === "version" ? DB_DRIFT_TEXTS.driftReasonVersion : DB_DRIFT_TEXTS.driftReasonSchema;
|
|
19302
19524
|
}
|
|
@@ -25241,8 +25463,8 @@ function parseBreakerLimit(raw, stderr, noColor) {
|
|
|
25241
25463
|
}
|
|
25242
25464
|
function parseMaxScanLimit(raw, stderr, noColor) {
|
|
25243
25465
|
if (raw === void 0) return void 0;
|
|
25244
|
-
const n =
|
|
25245
|
-
if (
|
|
25466
|
+
const n = tryParsePositiveInt(raw);
|
|
25467
|
+
if (n === null) {
|
|
25246
25468
|
const stderrTty = stderr;
|
|
25247
25469
|
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
25248
25470
|
stderr.write(
|
|
@@ -25258,8 +25480,8 @@ function parseMaxScanLimit(raw, stderr, noColor) {
|
|
|
25258
25480
|
}
|
|
25259
25481
|
function parseMaxNodesLimit(raw, stderr, noColor) {
|
|
25260
25482
|
if (raw === void 0) return void 0;
|
|
25261
|
-
const n =
|
|
25262
|
-
if (
|
|
25483
|
+
const n = tryParsePositiveInt(raw);
|
|
25484
|
+
if (n === null) {
|
|
25263
25485
|
const stderrTty = stderr;
|
|
25264
25486
|
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
25265
25487
|
stderr.write(
|
|
@@ -25426,8 +25648,8 @@ var ScanCommand = class extends SmCommand {
|
|
|
25426
25648
|
*/
|
|
25427
25649
|
parseIntegerFlag(raw, invalidTemplate, invalidHint) {
|
|
25428
25650
|
if (raw === void 0) return { kind: "ok", value: void 0 };
|
|
25429
|
-
const n =
|
|
25430
|
-
if (
|
|
25651
|
+
const n = tryParsePositiveInt(raw);
|
|
25652
|
+
if (n === null) {
|
|
25431
25653
|
const ansi = this.ansiFor("stderr");
|
|
25432
25654
|
this.printer.info(
|
|
25433
25655
|
tx(invalidTemplate, {
|
|
@@ -26403,7 +26625,7 @@ function originGuarded(path) {
|
|
|
26403
26625
|
}
|
|
26404
26626
|
|
|
26405
26627
|
// server/security-headers.ts
|
|
26406
|
-
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'";
|
|
26407
26629
|
function createSecurityHeaders() {
|
|
26408
26630
|
return async (c, next) => {
|
|
26409
26631
|
await next();
|
|
@@ -27054,7 +27276,7 @@ import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
|
27054
27276
|
|
|
27055
27277
|
// server/node-body.ts
|
|
27056
27278
|
import { constants as fsConstants2 } from "fs";
|
|
27057
|
-
import { open } from "fs/promises";
|
|
27279
|
+
import { open as open2 } from "fs/promises";
|
|
27058
27280
|
import { isAbsolute as isAbsolute14, resolve as resolvePath2, relative as relativePath, sep as sep8 } from "path";
|
|
27059
27281
|
async function readNodeBody(cwd, relPath) {
|
|
27060
27282
|
if (isAbsolute14(relPath)) return null;
|
|
@@ -27067,7 +27289,7 @@ async function readNodeBody(cwd, relPath) {
|
|
|
27067
27289
|
let raw;
|
|
27068
27290
|
let handle = null;
|
|
27069
27291
|
try {
|
|
27070
|
-
handle = await
|
|
27292
|
+
handle = await open2(absFile, fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW);
|
|
27071
27293
|
raw = await handle.readFile("utf-8");
|
|
27072
27294
|
} catch (err) {
|
|
27073
27295
|
if (isExpectedFsError(err)) return null;
|
|
@@ -28526,7 +28748,7 @@ var parsePatchBody5 = makeBodyValidator(PATCH_BODY_SCHEMA4, {
|
|
|
28526
28748
|
|
|
28527
28749
|
// server/routes/actions.ts
|
|
28528
28750
|
import { HTTPException as HTTPException16 } from "hono/http-exception";
|
|
28529
|
-
import { resolve as resolve41 } from "path";
|
|
28751
|
+
import { relative as relative10, resolve as resolve41 } from "path";
|
|
28530
28752
|
|
|
28531
28753
|
// server/routes/node-loader.ts
|
|
28532
28754
|
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
@@ -28658,7 +28880,18 @@ function invokeAction(action, absPath, node, body, cwd) {
|
|
|
28658
28880
|
};
|
|
28659
28881
|
return invoke(body.input ?? {}, ctx);
|
|
28660
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
|
+
}
|
|
28661
28893
|
async function materializeWrites(writes, body, cwd) {
|
|
28894
|
+
assertSidecarWritesContained(writes, cwd);
|
|
28662
28895
|
const store = new FilesystemSidecarStore(ensureSidecarWritesAllowed);
|
|
28663
28896
|
try {
|
|
28664
28897
|
for (const w of writes ?? []) {
|
|
@@ -30203,6 +30436,12 @@ function listenAsync(fetchCallback, wss, host, port) {
|
|
|
30203
30436
|
fetch: fetchCallback,
|
|
30204
30437
|
hostname: host,
|
|
30205
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.
|
|
30206
30445
|
websocket: { server: wss }
|
|
30207
30446
|
},
|
|
30208
30447
|
() => {
|
|
@@ -30520,7 +30759,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
30520
30759
|
);
|
|
30521
30760
|
return ExitCode.Error;
|
|
30522
30761
|
}
|
|
30523
|
-
const maxScanResult =
|
|
30762
|
+
const maxScanResult = parseMaxIntFlag(this.maxScan);
|
|
30524
30763
|
if (!maxScanResult.ok) {
|
|
30525
30764
|
this.printer.info(
|
|
30526
30765
|
tx(SERVE_TEXTS.maxScanInvalid, {
|
|
@@ -30531,7 +30770,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
30531
30770
|
);
|
|
30532
30771
|
return ExitCode.Error;
|
|
30533
30772
|
}
|
|
30534
|
-
const maxNodesResult =
|
|
30773
|
+
const maxNodesResult = parseMaxIntFlag(this.maxNodes);
|
|
30535
30774
|
if (!maxNodesResult.ok) {
|
|
30536
30775
|
this.printer.info(
|
|
30537
30776
|
tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
@@ -30660,16 +30899,10 @@ function parseDebounce(raw) {
|
|
|
30660
30899
|
if (parsed === null) return { ok: false, value: raw };
|
|
30661
30900
|
return { ok: true, value: parsed };
|
|
30662
30901
|
}
|
|
30663
|
-
function
|
|
30902
|
+
function parseMaxIntFlag(raw) {
|
|
30664
30903
|
if (raw === void 0) return { ok: true, value: void 0 };
|
|
30665
|
-
const n =
|
|
30666
|
-
if (
|
|
30667
|
-
return { ok: true, value: n };
|
|
30668
|
-
}
|
|
30669
|
-
function parseMaxNodes(raw) {
|
|
30670
|
-
if (raw === void 0) return { ok: true, value: void 0 };
|
|
30671
|
-
const n = Number(raw);
|
|
30672
|
-
if (!Number.isInteger(n) || n < 1) return { ok: false, value: raw };
|
|
30904
|
+
const n = tryParsePositiveInt(raw);
|
|
30905
|
+
if (n === null) return { ok: false, value: raw };
|
|
30673
30906
|
return { ok: true, value: n };
|
|
30674
30907
|
}
|
|
30675
30908
|
function resolveUiDist(ctx, raw) {
|
|
@@ -31829,13 +32062,15 @@ var TUTORIAL_TEXTS = {
|
|
|
31829
32062
|
writtenLabelEn: "English",
|
|
31830
32063
|
writtenLabelEs: "Espa\xF1ol",
|
|
31831
32064
|
// Destination-provider prompt (interactive stdin, no `--for`). Header
|
|
31832
|
-
// uses a yellow `?` glyph; options are a numbered list of provider
|
|
31833
|
-
//
|
|
31834
|
-
// a `(default)` marker on
|
|
31835
|
-
//
|
|
31836
|
-
//
|
|
32065
|
+
// uses a yellow `?` glyph; options are a numbered list of the provider's
|
|
32066
|
+
// vendor name (for a provider with an `aka`, the aka vendor leads and the
|
|
32067
|
+
// provider label follows in parentheses), with a `(default)` marker on
|
|
32068
|
+
// the first option (Claude). The destination folder is deliberately NOT
|
|
32069
|
+
// shown: several providers share `.agents/skills`, so the folder does not
|
|
32070
|
+
// identify the lens. The input line accepts a number, a provider id, or
|
|
32071
|
+
// an empty answer (which takes the default).
|
|
31837
32072
|
promptHeader: "{{glyph}} Which agent should host the tutorial skill?",
|
|
31838
|
-
promptOption: " {{index}}) {{label}}
|
|
32073
|
+
promptOption: " {{index}}) {{label}}{{marker}}",
|
|
31839
32074
|
promptDefaultMarker: " (default)",
|
|
31840
32075
|
promptInput: " Enter the number or provider id [default {{index}}]: ",
|
|
31841
32076
|
// Prompt answer matched neither an index nor an id. Goes to stderr,
|
|
@@ -31966,9 +32201,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
31966
32201
|
return ExitCode.Error;
|
|
31967
32202
|
}
|
|
31968
32203
|
try {
|
|
31969
|
-
|
|
31970
|
-
mkdirSync6(dirname21(targetDir), { recursive: true });
|
|
31971
|
-
cpSync3(sourceDir, targetDir, { recursive: true });
|
|
32204
|
+
materializeSkillFolder(sourceDir, targetDir, ctx.cwd, target.marker);
|
|
31972
32205
|
} catch (err) {
|
|
31973
32206
|
this.printer.error(
|
|
31974
32207
|
tx(TUTORIAL_TEXTS.writeFailed, {
|
|
@@ -32059,6 +32292,14 @@ var TutorialCommand = class extends SmCommand {
|
|
|
32059
32292
|
return picked;
|
|
32060
32293
|
}
|
|
32061
32294
|
};
|
|
32295
|
+
function materializeSkillFolder(sourceDir, targetDir, cwd, marker) {
|
|
32296
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
32297
|
+
mkdirSync6(dirname21(targetDir), { recursive: true });
|
|
32298
|
+
cpSync3(sourceDir, targetDir, { recursive: true });
|
|
32299
|
+
if (marker !== void 0) {
|
|
32300
|
+
mkdirSync6(join21(cwd, marker), { recursive: true });
|
|
32301
|
+
}
|
|
32302
|
+
}
|
|
32062
32303
|
function toScaffoldTarget(provider, includeExperimental) {
|
|
32063
32304
|
const scaffold = provider.scaffold;
|
|
32064
32305
|
if (!scaffold || !scaffold.skillDir) return null;
|
|
@@ -32067,6 +32308,7 @@ function toScaffoldTarget(provider, includeExperimental) {
|
|
|
32067
32308
|
id: provider.id,
|
|
32068
32309
|
label: provider.presentation.label,
|
|
32069
32310
|
skillDir: scaffold.skillDir,
|
|
32311
|
+
...scaffold.marker !== void 0 ? { marker: scaffold.marker } : {},
|
|
32070
32312
|
aka: scaffold.aka ?? []
|
|
32071
32313
|
};
|
|
32072
32314
|
}
|
|
@@ -32079,7 +32321,7 @@ function listScaffoldTargets(includeExperimental = false) {
|
|
|
32079
32321
|
return out;
|
|
32080
32322
|
}
|
|
32081
32323
|
function labelWithAka(target) {
|
|
32082
|
-
return target.aka.length > 0 ? `${target.
|
|
32324
|
+
return target.aka.length > 0 ? `${target.aka.join(", ")} (${target.label})` : target.label;
|
|
32083
32325
|
}
|
|
32084
32326
|
function renderTargetLines(targets, def, glyph) {
|
|
32085
32327
|
const lines = [tx(TUTORIAL_TEXTS.promptHeader, { glyph })];
|
|
@@ -32089,7 +32331,6 @@ function renderTargetLines(targets, def, glyph) {
|
|
|
32089
32331
|
tx(TUTORIAL_TEXTS.promptOption, {
|
|
32090
32332
|
index: i + 1,
|
|
32091
32333
|
label: labelWithAka(t),
|
|
32092
|
-
skillDir: `${t.skillDir}/`,
|
|
32093
32334
|
marker: t.id === def.id ? TUTORIAL_TEXTS.promptDefaultMarker : ""
|
|
32094
32335
|
})
|
|
32095
32336
|
);
|
|
@@ -32375,4 +32616,4 @@ function resolveBareDefault() {
|
|
|
32375
32616
|
process.exit(ExitCode.Error);
|
|
32376
32617
|
}
|
|
32377
32618
|
//# sourceMappingURL=cli.js.map
|
|
32378
|
-
//# debugId=
|
|
32619
|
+
//# debugId=a842c024-162c-5a3a-85db-1daea4b6735f
|