@skill-map/cli 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/tutorial/sm-master/SKILL.md +29 -29
- package/dist/cli/tutorial/sm-master/references/fixture-templates.md +18 -13
- package/dist/cli/tutorial/sm-master/references/tour-authoring.md +35 -40
- package/dist/cli/tutorial/sm-master/references/tour-plugins.md +32 -32
- package/dist/cli/tutorial/sm-master/references/tour-settings.md +156 -75
- package/dist/cli/tutorial/sm-tutorial/SKILL.md +3 -3
- package/dist/cli.js +757 -452
- package/dist/conformance/index.js +4 -1
- package/dist/index.js +44 -17
- package/dist/kernel/index.d.ts +64 -9
- package/dist/kernel/index.js +44 -17
- package/dist/migrations/001_initial.sql +7 -0
- package/dist/ui/chunk-22CKFAEU.js +1 -0
- package/dist/ui/{chunk-I5AX4U2N.js → chunk-3YSNJXGB.js} +1 -1
- package/dist/ui/{chunk-MS6B7344.js → chunk-6AP364TB.js} +7 -7
- package/dist/ui/{chunk-VGPYYAVI.js → chunk-EPBUSS3I.js} +1 -1
- package/dist/ui/{chunk-IYM26L3O.js → chunk-ERUALZOV.js} +1 -1
- package/dist/ui/{chunk-5AD5ZV4I.js → chunk-EYBKZOMF.js} +1 -1
- package/dist/ui/chunk-F4RIBZ4P.js +1 -0
- package/dist/ui/chunk-HAWX5WNM.js +4 -0
- package/dist/ui/{chunk-QDUSFOBE.js → chunk-K365TVPA.js} +1 -1
- package/dist/ui/{chunk-CBI77N5U.js → chunk-L3JYFPSZ.js} +2 -2
- package/dist/ui/chunk-N3RUQDAR.js +1 -0
- package/dist/ui/{chunk-A7PRWMQD.js → chunk-P4E74ZOS.js} +1 -1
- package/dist/ui/{chunk-X227ITGS.js → chunk-RT7E4S5B.js} +1 -1
- package/dist/ui/{chunk-QNTAOR2L.js → chunk-RXQYLVSJ.js} +1 -1
- package/dist/ui/{chunk-MFLFIA7C.js → chunk-S32E6ZCZ.js} +1 -1
- package/dist/ui/{chunk-T3IVIRRJ.js → chunk-SF4FUT4U.js} +1 -1
- package/dist/ui/chunk-VNA3TMIO.js +1 -0
- package/dist/ui/{chunk-F7I6KMHX.js → chunk-VW2A6WZ3.js} +1 -1
- package/dist/ui/chunk-ZZJ7XWDX.js +1 -0
- package/dist/ui/index.html +1 -1
- package/dist/ui/main-NF5GO3JR.js +4 -0
- package/migrations/001_initial.sql +7 -0
- package/package.json +2 -2
- package/dist/cli.js.map +0 -1
- package/dist/conformance/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/kernel/index.js.map +0 -1
- package/dist/ui/chunk-27WQPOXP.js +0 -1
- package/dist/ui/chunk-555ST76V.js +0 -1
- package/dist/ui/chunk-IUZRAD7S.js +0 -1
- package/dist/ui/chunk-PZQHB7GS.js +0 -4
- package/dist/ui/main-ERCTR2PR.js +0 -3
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// cli/entry.ts
|
|
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]="7c131b78-b7ad-5f03-b19c-1f70afdfeefb")}catch(e){}}();
|
|
2
4
|
import { existsSync as existsSync32 } from "fs";
|
|
3
5
|
import { Builtins, Cli as Cli2 } from "clipanion";
|
|
4
6
|
|
|
@@ -241,6 +243,123 @@ function bucketByKind(kind, instance, bag) {
|
|
|
241
243
|
}
|
|
242
244
|
}
|
|
243
245
|
|
|
246
|
+
// package.json
|
|
247
|
+
var package_default = {
|
|
248
|
+
name: "@skill-map/cli",
|
|
249
|
+
version: "0.46.0",
|
|
250
|
+
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
251
|
+
license: "MIT",
|
|
252
|
+
type: "module",
|
|
253
|
+
homepage: "https://skill-map.ai",
|
|
254
|
+
repository: {
|
|
255
|
+
type: "git",
|
|
256
|
+
url: "git+https://github.com/crystian/skill-map.git",
|
|
257
|
+
directory: "src"
|
|
258
|
+
},
|
|
259
|
+
bugs: {
|
|
260
|
+
url: "https://github.com/crystian/skill-map/issues"
|
|
261
|
+
},
|
|
262
|
+
keywords: [
|
|
263
|
+
"skill-map",
|
|
264
|
+
"markdown",
|
|
265
|
+
"ai-agents",
|
|
266
|
+
"claude-code",
|
|
267
|
+
"graph"
|
|
268
|
+
],
|
|
269
|
+
bin: {
|
|
270
|
+
sm: "bin/sm.js",
|
|
271
|
+
"skill-map": "bin/sm.js"
|
|
272
|
+
},
|
|
273
|
+
exports: {
|
|
274
|
+
".": {
|
|
275
|
+
types: "./dist/index.d.ts",
|
|
276
|
+
import: "./dist/index.js"
|
|
277
|
+
},
|
|
278
|
+
"./kernel": {
|
|
279
|
+
types: "./dist/kernel/index.d.ts",
|
|
280
|
+
import: "./dist/kernel/index.js"
|
|
281
|
+
},
|
|
282
|
+
"./conformance": {
|
|
283
|
+
types: "./dist/conformance/index.d.ts",
|
|
284
|
+
import: "./dist/conformance/index.js"
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
files: [
|
|
288
|
+
"bin/",
|
|
289
|
+
"dist/",
|
|
290
|
+
"migrations/",
|
|
291
|
+
"README.md"
|
|
292
|
+
],
|
|
293
|
+
scripts: {
|
|
294
|
+
build: "tsup",
|
|
295
|
+
dev: "tsup --watch",
|
|
296
|
+
"dev:serve": "node scripts/dev-serve.js",
|
|
297
|
+
typecheck: "tsc --noEmit",
|
|
298
|
+
lint: "eslint .",
|
|
299
|
+
"lint:fix": "eslint . --fix",
|
|
300
|
+
"build-built-ins": "node ../scripts/generate-built-ins.js",
|
|
301
|
+
"built-ins:check": "node ../scripts/generate-built-ins.js --check",
|
|
302
|
+
prebuild: "pnpm build-built-ins",
|
|
303
|
+
validate: "pnpm validate:compile && pnpm validate:test",
|
|
304
|
+
"validate:compile": "pnpm typecheck && pnpm lint && pnpm build && pnpm built-ins:check",
|
|
305
|
+
"validate:test": "pnpm test:ci",
|
|
306
|
+
pretest: "tsup",
|
|
307
|
+
"pretest:coverage": "tsup",
|
|
308
|
+
"pretest:coverage:html": "tsup",
|
|
309
|
+
test: "tsc --noEmit && SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=./scripts/test-reporter.js --test-reporter-destination=stdout '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
310
|
+
"test:ci": "FORCE_COLOR=1 SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=./scripts/test-reporter.js --test-reporter-destination=stdout '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
311
|
+
"test:spec": "SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=spec '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
312
|
+
"test:coverage": "tsc --noEmit && SKILL_MAP_TELEMETRY=0 SKILL_MAP_SKIP_BENCHMARK=1 node --experimental-default-config-file --import tsx --test --experimental-test-coverage '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
313
|
+
"test:coverage:html": "tsc --noEmit && SKILL_MAP_TELEMETRY=0 SKILL_MAP_SKIP_BENCHMARK=1 c8 node --import tsx --test '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
314
|
+
clean: "rm -rf dist coverage"
|
|
315
|
+
},
|
|
316
|
+
dependencies: {
|
|
317
|
+
"@hono/node-server": "2.0.1",
|
|
318
|
+
"@sentry/node": "10.55.0",
|
|
319
|
+
"@skill-map/spec": "workspace:*",
|
|
320
|
+
ajv: "8.18.0",
|
|
321
|
+
"ajv-formats": "3.0.1",
|
|
322
|
+
chokidar: "5.0.0",
|
|
323
|
+
clipanion: "4.0.0-rc.4",
|
|
324
|
+
hono: "4.12.18",
|
|
325
|
+
ignore: "7.0.5",
|
|
326
|
+
"js-tiktoken": "1.0.21",
|
|
327
|
+
"js-yaml": "4.1.1",
|
|
328
|
+
kysely: "0.28.17",
|
|
329
|
+
"posthog-node": "5.35.6",
|
|
330
|
+
semver: "7.7.4",
|
|
331
|
+
"smol-toml": "1.6.1",
|
|
332
|
+
typanion: "3.14.0",
|
|
333
|
+
ws: "8.21.0"
|
|
334
|
+
},
|
|
335
|
+
devDependencies: {
|
|
336
|
+
"@eslint/js": "10.0.1",
|
|
337
|
+
"@stylistic/eslint-plugin": "5.10.0",
|
|
338
|
+
"@types/js-yaml": "4.0.9",
|
|
339
|
+
"@types/node": "24.12.2",
|
|
340
|
+
"@types/semver": "7.7.1",
|
|
341
|
+
"@types/ws": "8.18.1",
|
|
342
|
+
c8: "11.0.0",
|
|
343
|
+
eslint: "10.2.1",
|
|
344
|
+
"eslint-plugin-import-x": "4.16.2",
|
|
345
|
+
tsup: "8.5.1",
|
|
346
|
+
tsx: "4.22.3",
|
|
347
|
+
typescript: "5.9.3",
|
|
348
|
+
"typescript-eslint": "8.59.1"
|
|
349
|
+
},
|
|
350
|
+
engines: {
|
|
351
|
+
node: ">=24.0"
|
|
352
|
+
},
|
|
353
|
+
publishConfig: {
|
|
354
|
+
access: "public"
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// version.ts
|
|
359
|
+
var VERSION = package_default.version;
|
|
360
|
+
var BINARY_NAME = "sm";
|
|
361
|
+
var BINARY_LABEL = "skill-map";
|
|
362
|
+
|
|
244
363
|
// plugins/claude/providers/claude/schemas/skill.schema.json
|
|
245
364
|
var skill_schema_default = {
|
|
246
365
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -481,7 +600,7 @@ var claudeProvider = {
|
|
|
481
600
|
read: { extensions: [".md"], parser: "frontmatter-yaml" },
|
|
482
601
|
// Per spec § A.6, defaultRefreshAction values MUST be qualified action
|
|
483
602
|
// ids. The summarize-* actions are not yet implemented as registry
|
|
484
|
-
// entries (they ship later under the Claude
|
|
603
|
+
// entries (they ship later under the Claude plugin), but the qualified
|
|
485
604
|
// form is the contract: when those actions land, they will register
|
|
486
605
|
// under `claude/summarize-<kind>` and the Provider resolves them
|
|
487
606
|
// deterministically.
|
|
@@ -1192,7 +1311,7 @@ var markdown_schema_default = {
|
|
|
1192
1311
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1193
1312
|
$id: "https://skill-map.ai/providers/core/v1/frontmatter/markdown.schema.json",
|
|
1194
1313
|
title: "FrontmatterMarkdown",
|
|
1195
|
-
description: "Frontmatter shape for nodes classified as `markdown` by the built-in `core/markdown` Provider, the universal fallback for any markdown file no vendor-specific Provider claims (Claude, OpenAI Codex, agent-skills, plus the metadata-only Antigravity
|
|
1314
|
+
description: "Frontmatter shape for nodes classified as `markdown` by the built-in `core/markdown` Provider, the universal fallback for any markdown file no vendor-specific Provider claims (Claude, OpenAI Codex, agent-skills, plus the metadata-only Antigravity plugin). The kind is named after the format because the file is a generic fallback; format-named kinds apply only as the generic fallback, a TOML file that IS a Codex agent still classifies as `agent`, not `toml`. Extends the spec's universal `frontmatter/base.schema.json` via $ref-by-$id with no additional fields. Ownership relocated from the Claude Provider in spec 0.18.0, markdown is provider-agnostic and lives under `core` so adding new vendor Providers does not require choosing which one owns the universal fallback.",
|
|
1196
1315
|
allOf: [
|
|
1197
1316
|
{ $ref: "https://skill-map.ai/spec/v0/frontmatter/base.schema.json" }
|
|
1198
1317
|
],
|
|
@@ -1223,7 +1342,7 @@ var coreMarkdownProvider = {
|
|
|
1223
1342
|
read: { extensions: [".md"], parser: "frontmatter-yaml" },
|
|
1224
1343
|
// Per spec § A.6, defaultRefreshAction values MUST be qualified
|
|
1225
1344
|
// action ids. The summarize-markdown action is not yet implemented
|
|
1226
|
-
// as a registry entry (it ships later under the core
|
|
1345
|
+
// as a registry entry (it ships later under the core plugin), but
|
|
1227
1346
|
// the qualified form is the contract.
|
|
1228
1347
|
//
|
|
1229
1348
|
// UI presentation: same neutral teal that the per-vendor Providers
|
|
@@ -3957,123 +4076,6 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
3957
4076
|
availableHint: "Run `npm i -g @skill-map/cli@latest` to update."
|
|
3958
4077
|
};
|
|
3959
4078
|
|
|
3960
|
-
// package.json
|
|
3961
|
-
var package_default = {
|
|
3962
|
-
name: "@skill-map/cli",
|
|
3963
|
-
version: "0.45.0",
|
|
3964
|
-
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
3965
|
-
license: "MIT",
|
|
3966
|
-
type: "module",
|
|
3967
|
-
homepage: "https://skill-map.ai",
|
|
3968
|
-
repository: {
|
|
3969
|
-
type: "git",
|
|
3970
|
-
url: "git+https://github.com/crystian/skill-map.git",
|
|
3971
|
-
directory: "src"
|
|
3972
|
-
},
|
|
3973
|
-
bugs: {
|
|
3974
|
-
url: "https://github.com/crystian/skill-map/issues"
|
|
3975
|
-
},
|
|
3976
|
-
keywords: [
|
|
3977
|
-
"skill-map",
|
|
3978
|
-
"markdown",
|
|
3979
|
-
"ai-agents",
|
|
3980
|
-
"claude-code",
|
|
3981
|
-
"graph"
|
|
3982
|
-
],
|
|
3983
|
-
bin: {
|
|
3984
|
-
sm: "bin/sm.js",
|
|
3985
|
-
"skill-map": "bin/sm.js"
|
|
3986
|
-
},
|
|
3987
|
-
exports: {
|
|
3988
|
-
".": {
|
|
3989
|
-
types: "./dist/index.d.ts",
|
|
3990
|
-
import: "./dist/index.js"
|
|
3991
|
-
},
|
|
3992
|
-
"./kernel": {
|
|
3993
|
-
types: "./dist/kernel/index.d.ts",
|
|
3994
|
-
import: "./dist/kernel/index.js"
|
|
3995
|
-
},
|
|
3996
|
-
"./conformance": {
|
|
3997
|
-
types: "./dist/conformance/index.d.ts",
|
|
3998
|
-
import: "./dist/conformance/index.js"
|
|
3999
|
-
}
|
|
4000
|
-
},
|
|
4001
|
-
files: [
|
|
4002
|
-
"bin/",
|
|
4003
|
-
"dist/",
|
|
4004
|
-
"migrations/",
|
|
4005
|
-
"README.md"
|
|
4006
|
-
],
|
|
4007
|
-
scripts: {
|
|
4008
|
-
build: "tsup",
|
|
4009
|
-
dev: "tsup --watch",
|
|
4010
|
-
"dev:serve": "node scripts/dev-serve.js",
|
|
4011
|
-
typecheck: "tsc --noEmit",
|
|
4012
|
-
lint: "eslint .",
|
|
4013
|
-
"lint:fix": "eslint . --fix",
|
|
4014
|
-
"build-built-ins": "node ../scripts/generate-built-ins.js",
|
|
4015
|
-
"built-ins:check": "node ../scripts/generate-built-ins.js --check",
|
|
4016
|
-
prebuild: "pnpm build-built-ins",
|
|
4017
|
-
validate: "pnpm validate:compile && pnpm validate:test",
|
|
4018
|
-
"validate:compile": "pnpm typecheck && pnpm lint && pnpm build && pnpm built-ins:check",
|
|
4019
|
-
"validate:test": "pnpm test:ci",
|
|
4020
|
-
pretest: "tsup",
|
|
4021
|
-
"pretest:coverage": "tsup",
|
|
4022
|
-
"pretest:coverage:html": "tsup",
|
|
4023
|
-
test: "tsc --noEmit && SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=./scripts/test-reporter.js --test-reporter-destination=stdout '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
4024
|
-
"test:ci": "FORCE_COLOR=1 SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=./scripts/test-reporter.js --test-reporter-destination=stdout '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
4025
|
-
"test:spec": "SKILL_MAP_TELEMETRY=0 node --import tsx --test --test-reporter=spec '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
4026
|
-
"test:coverage": "tsc --noEmit && SKILL_MAP_TELEMETRY=0 SKILL_MAP_SKIP_BENCHMARK=1 node --experimental-default-config-file --import tsx --test --experimental-test-coverage '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
4027
|
-
"test:coverage:html": "tsc --noEmit && SKILL_MAP_TELEMETRY=0 SKILL_MAP_SKIP_BENCHMARK=1 c8 node --import tsx --test '__tests__/**/*.spec.ts' 'kernel/**/__tests__/**/*.spec.ts' 'cli/**/__tests__/**/*.spec.ts' 'server/**/__tests__/**/*.spec.ts' 'plugins/**/__tests__/**/*.spec.ts' 'core/**/__tests__/**/*.spec.ts' 'conformance/**/__tests__/**/*.spec.ts'",
|
|
4028
|
-
clean: "rm -rf dist coverage"
|
|
4029
|
-
},
|
|
4030
|
-
dependencies: {
|
|
4031
|
-
"@hono/node-server": "2.0.1",
|
|
4032
|
-
"@sentry/node": "10.55.0",
|
|
4033
|
-
"@skill-map/spec": "workspace:*",
|
|
4034
|
-
ajv: "8.18.0",
|
|
4035
|
-
"ajv-formats": "3.0.1",
|
|
4036
|
-
chokidar: "5.0.0",
|
|
4037
|
-
clipanion: "4.0.0-rc.4",
|
|
4038
|
-
hono: "4.12.18",
|
|
4039
|
-
ignore: "7.0.5",
|
|
4040
|
-
"js-tiktoken": "1.0.21",
|
|
4041
|
-
"js-yaml": "4.1.1",
|
|
4042
|
-
kysely: "0.28.17",
|
|
4043
|
-
"posthog-node": "5.35.6",
|
|
4044
|
-
semver: "7.7.4",
|
|
4045
|
-
"smol-toml": "1.6.1",
|
|
4046
|
-
typanion: "3.14.0",
|
|
4047
|
-
ws: "8.21.0"
|
|
4048
|
-
},
|
|
4049
|
-
devDependencies: {
|
|
4050
|
-
"@eslint/js": "10.0.1",
|
|
4051
|
-
"@stylistic/eslint-plugin": "5.10.0",
|
|
4052
|
-
"@types/js-yaml": "4.0.9",
|
|
4053
|
-
"@types/node": "24.12.2",
|
|
4054
|
-
"@types/semver": "7.7.1",
|
|
4055
|
-
"@types/ws": "8.18.1",
|
|
4056
|
-
c8: "11.0.0",
|
|
4057
|
-
eslint: "10.2.1",
|
|
4058
|
-
"eslint-plugin-import-x": "4.16.2",
|
|
4059
|
-
tsup: "8.5.1",
|
|
4060
|
-
tsx: "4.22.3",
|
|
4061
|
-
typescript: "5.9.3",
|
|
4062
|
-
"typescript-eslint": "8.59.1"
|
|
4063
|
-
},
|
|
4064
|
-
engines: {
|
|
4065
|
-
node: ">=24.0"
|
|
4066
|
-
},
|
|
4067
|
-
publishConfig: {
|
|
4068
|
-
access: "public"
|
|
4069
|
-
}
|
|
4070
|
-
};
|
|
4071
|
-
|
|
4072
|
-
// version.ts
|
|
4073
|
-
var VERSION = package_default.version;
|
|
4074
|
-
var BINARY_NAME = "sm";
|
|
4075
|
-
var BINARY_LABEL = "skill-map";
|
|
4076
|
-
|
|
4077
4079
|
// cli/util/ansi.ts
|
|
4078
4080
|
var ESC = {
|
|
4079
4081
|
reset: "\x1B[0m",
|
|
@@ -4430,41 +4432,41 @@ var updateCheckHook = {
|
|
|
4430
4432
|
};
|
|
4431
4433
|
|
|
4432
4434
|
// plugins/built-ins.ts
|
|
4433
|
-
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version:
|
|
4434
|
-
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version:
|
|
4435
|
-
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version:
|
|
4436
|
-
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version:
|
|
4437
|
-
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version:
|
|
4438
|
-
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version:
|
|
4439
|
-
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version:
|
|
4440
|
-
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version:
|
|
4441
|
-
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version:
|
|
4442
|
-
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version:
|
|
4443
|
-
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version:
|
|
4444
|
-
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version:
|
|
4445
|
-
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version:
|
|
4446
|
-
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version:
|
|
4447
|
-
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version:
|
|
4448
|
-
var contributionOrphanAnalyzer2 = { ...contributionOrphanAnalyzer, pluginId: "core", version:
|
|
4449
|
-
var issueCounterAnalyzer2 = { ...issueCounterAnalyzer, pluginId: "core", version:
|
|
4450
|
-
var jobFileOrphanAnalyzer2 = { ...jobFileOrphanAnalyzer, pluginId: "core", version:
|
|
4451
|
-
var linkConflictAnalyzer2 = { ...linkConflictAnalyzer, pluginId: "core", version:
|
|
4452
|
-
var linkCounterAnalyzer2 = { ...linkCounterAnalyzer, pluginId: "core", version:
|
|
4453
|
-
var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version:
|
|
4454
|
-
var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version:
|
|
4455
|
-
var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version:
|
|
4456
|
-
var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version:
|
|
4457
|
-
var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version:
|
|
4458
|
-
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version:
|
|
4459
|
-
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version:
|
|
4460
|
-
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version:
|
|
4461
|
-
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version:
|
|
4462
|
-
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version:
|
|
4463
|
-
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version:
|
|
4464
|
-
var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version:
|
|
4465
|
-
var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version:
|
|
4466
|
-
var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version:
|
|
4467
|
-
var
|
|
4435
|
+
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version: VERSION };
|
|
4436
|
+
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version: VERSION };
|
|
4437
|
+
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version: VERSION };
|
|
4438
|
+
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: VERSION };
|
|
4439
|
+
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: VERSION };
|
|
4440
|
+
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: VERSION };
|
|
4441
|
+
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: VERSION };
|
|
4442
|
+
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: VERSION };
|
|
4443
|
+
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: VERSION };
|
|
4444
|
+
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: VERSION };
|
|
4445
|
+
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version: VERSION };
|
|
4446
|
+
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version: VERSION };
|
|
4447
|
+
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version: VERSION };
|
|
4448
|
+
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version: VERSION };
|
|
4449
|
+
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version: VERSION };
|
|
4450
|
+
var contributionOrphanAnalyzer2 = { ...contributionOrphanAnalyzer, pluginId: "core", version: VERSION };
|
|
4451
|
+
var issueCounterAnalyzer2 = { ...issueCounterAnalyzer, pluginId: "core", version: VERSION };
|
|
4452
|
+
var jobFileOrphanAnalyzer2 = { ...jobFileOrphanAnalyzer, pluginId: "core", version: VERSION };
|
|
4453
|
+
var linkConflictAnalyzer2 = { ...linkConflictAnalyzer, pluginId: "core", version: VERSION };
|
|
4454
|
+
var linkCounterAnalyzer2 = { ...linkCounterAnalyzer, pluginId: "core", version: VERSION };
|
|
4455
|
+
var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version: VERSION };
|
|
4456
|
+
var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version: VERSION };
|
|
4457
|
+
var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version: VERSION };
|
|
4458
|
+
var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version: VERSION };
|
|
4459
|
+
var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version: VERSION };
|
|
4460
|
+
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: VERSION };
|
|
4461
|
+
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: VERSION };
|
|
4462
|
+
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version: VERSION };
|
|
4463
|
+
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version: VERSION };
|
|
4464
|
+
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version: VERSION };
|
|
4465
|
+
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: VERSION };
|
|
4466
|
+
var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version: VERSION };
|
|
4467
|
+
var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version: VERSION };
|
|
4468
|
+
var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version: VERSION };
|
|
4469
|
+
var builtInPlugins = [
|
|
4468
4470
|
{
|
|
4469
4471
|
id: "claude",
|
|
4470
4472
|
description: "Claude Code platform integration. Classifies files under `.claude/{agents,commands,skills}` and detects Claude-flavored slash commands and at-directives in their bodies.",
|
|
@@ -4539,8 +4541,8 @@ function builtIns() {
|
|
|
4539
4541
|
actions: [],
|
|
4540
4542
|
hooks: []
|
|
4541
4543
|
};
|
|
4542
|
-
for (const
|
|
4543
|
-
for (const ext of
|
|
4544
|
+
for (const plugin of builtInPlugins) {
|
|
4545
|
+
for (const ext of plugin.extensions) {
|
|
4544
4546
|
bucketBuiltIn(ext, out);
|
|
4545
4547
|
}
|
|
4546
4548
|
}
|
|
@@ -4548,8 +4550,8 @@ function builtIns() {
|
|
|
4548
4550
|
}
|
|
4549
4551
|
function listBuiltIns() {
|
|
4550
4552
|
const out = [];
|
|
4551
|
-
for (const
|
|
4552
|
-
for (const x of
|
|
4553
|
+
for (const plugin of builtInPlugins) {
|
|
4554
|
+
for (const x of plugin.extensions) {
|
|
4553
4555
|
out.push(toExtensionRow(x));
|
|
4554
4556
|
}
|
|
4555
4557
|
}
|
|
@@ -4603,6 +4605,8 @@ var ENTRY_TEXTS = {
|
|
|
4603
4605
|
parseErrorFlagSuggestion: "Did you mean '{{suggestion}}'?",
|
|
4604
4606
|
parseErrorVerbSuggestion: "Did you mean {{suggestions}}?",
|
|
4605
4607
|
parseErrorVerbHelpHint: "Run 'sm help {{verb}}' for usage.",
|
|
4608
|
+
/** Footer for the incomplete-namespace error, points at that namespace's overview. */
|
|
4609
|
+
parseErrorNamespaceHelpHint: "Run 'sm help {{name}}' to see all subcommands.",
|
|
4606
4610
|
parseErrorFooter: "Run 'sm help' to see the full command list."
|
|
4607
4611
|
};
|
|
4608
4612
|
|
|
@@ -4891,7 +4895,8 @@ function formatParseError(params) {
|
|
|
4891
4895
|
const suggestion2 = tx(ENTRY_TEXTS.parseErrorSubcommandList, {
|
|
4892
4896
|
suggestions: formatSuggestionList(subcommands)
|
|
4893
4897
|
});
|
|
4894
|
-
|
|
4898
|
+
const footer = tx(ENTRY_TEXTS.parseErrorNamespaceHelpHint, { name: firstToken });
|
|
4899
|
+
return renderError(headline, suggestion2, footer);
|
|
4895
4900
|
}
|
|
4896
4901
|
const candidates = closestVerbs(firstToken, verbPaths);
|
|
4897
4902
|
const suggestion = candidates.length > 0 ? tx(ENTRY_TEXTS.parseErrorVerbSuggestion, { suggestions: formatSuggestionList(candidates) }) : null;
|
|
@@ -4932,10 +4937,10 @@ function matchedVerbPrefix(args2, verbPaths) {
|
|
|
4932
4937
|
}
|
|
4933
4938
|
return best.join(" ");
|
|
4934
4939
|
}
|
|
4935
|
-
function renderError(headline, suggestion) {
|
|
4940
|
+
function renderError(headline, suggestion, footer = ENTRY_TEXTS.parseErrorFooter) {
|
|
4936
4941
|
const lines = [tx(ENTRY_TEXTS.parseErrorHeadline, { message: headline })];
|
|
4937
4942
|
if (suggestion) lines.push(suggestion);
|
|
4938
|
-
lines.push(
|
|
4943
|
+
lines.push(footer);
|
|
4939
4944
|
return lines.join("\n") + "\n";
|
|
4940
4945
|
}
|
|
4941
4946
|
function extractOffendingFlag(message) {
|
|
@@ -5107,7 +5112,7 @@ async function initSentryCli(version, loadSdk = () => import("@sentry/node")) {
|
|
|
5107
5112
|
const Sentry = await loadSdk();
|
|
5108
5113
|
Sentry.init({
|
|
5109
5114
|
dsn: SENTRY_DSN_NODE,
|
|
5110
|
-
release:
|
|
5115
|
+
release: `skill-map-cli@${version}`,
|
|
5111
5116
|
environment: resolveTelemetryEnv(),
|
|
5112
5117
|
// CLI and BFF share one Sentry project; the `surface` tag tells their
|
|
5113
5118
|
// events apart in the shared issue stream.
|
|
@@ -5365,16 +5370,13 @@ function kernelLocalSettingsPath(scopeRoot) {
|
|
|
5365
5370
|
// config/defaults.json
|
|
5366
5371
|
var defaults_default = {
|
|
5367
5372
|
schemaVersion: 1,
|
|
5368
|
-
autoMigrate: true,
|
|
5369
5373
|
allowEditSmFiles: false,
|
|
5370
5374
|
tokenizer: "cl100k_base",
|
|
5371
|
-
providers: [],
|
|
5372
5375
|
roots: [],
|
|
5373
5376
|
ignore: [],
|
|
5374
5377
|
scan: {
|
|
5375
5378
|
tokenize: true,
|
|
5376
5379
|
strict: false,
|
|
5377
|
-
followSymlinks: false,
|
|
5378
5380
|
maxFileSizeBytes: 1048576,
|
|
5379
5381
|
maxNodes: 256,
|
|
5380
5382
|
watch: {
|
|
@@ -5383,9 +5385,6 @@ var defaults_default = {
|
|
|
5383
5385
|
referencePaths: []
|
|
5384
5386
|
},
|
|
5385
5387
|
plugins: {},
|
|
5386
|
-
history: {
|
|
5387
|
-
share: false
|
|
5388
|
-
},
|
|
5389
5388
|
jobs: {
|
|
5390
5389
|
ttlSeconds: 3600,
|
|
5391
5390
|
graceMultiplier: 3,
|
|
@@ -5396,9 +5395,6 @@ var defaults_default = {
|
|
|
5396
5395
|
completed: 2592e3,
|
|
5397
5396
|
failed: null
|
|
5398
5397
|
}
|
|
5399
|
-
},
|
|
5400
|
-
i18n: {
|
|
5401
|
-
locale: "en"
|
|
5402
5398
|
}
|
|
5403
5399
|
};
|
|
5404
5400
|
|
|
@@ -7510,6 +7506,7 @@ async function loadScanResult(db) {
|
|
|
7510
7506
|
version: metaRow.scannedByVersion,
|
|
7511
7507
|
specVersion: metaRow.scannedBySpecVersion
|
|
7512
7508
|
};
|
|
7509
|
+
const oversizedFiles = parseJsonArray(metaRow.oversizedFilesJson);
|
|
7513
7510
|
return {
|
|
7514
7511
|
schemaVersion: 1,
|
|
7515
7512
|
scannedAt: metaRow.scannedAt,
|
|
@@ -7518,12 +7515,14 @@ async function loadScanResult(db) {
|
|
|
7518
7515
|
scannedBy,
|
|
7519
7516
|
recommendedNodeLimit: metaRow.recommendedNodeLimit,
|
|
7520
7517
|
overrideMaxNodes: metaRow.overrideMaxNodes,
|
|
7518
|
+
oversizedFiles,
|
|
7521
7519
|
nodes,
|
|
7522
7520
|
links,
|
|
7523
7521
|
issues,
|
|
7524
7522
|
stats: {
|
|
7525
7523
|
filesWalked: metaRow.statsFilesWalked,
|
|
7526
7524
|
filesSkipped: metaRow.statsFilesSkipped,
|
|
7525
|
+
filesOversized: metaRow.filesOversized,
|
|
7527
7526
|
nodesCount: nodes.length,
|
|
7528
7527
|
linksCount: links.length,
|
|
7529
7528
|
issuesCount: issues.length,
|
|
@@ -7546,12 +7545,14 @@ async function loadScanResult(db) {
|
|
|
7546
7545
|
// scan overwrites scan_meta with the live values on next run.
|
|
7547
7546
|
recommendedNodeLimit: 256,
|
|
7548
7547
|
overrideMaxNodes: null,
|
|
7548
|
+
oversizedFiles: [],
|
|
7549
7549
|
nodes,
|
|
7550
7550
|
links,
|
|
7551
7551
|
issues,
|
|
7552
7552
|
stats: {
|
|
7553
7553
|
filesWalked: 0,
|
|
7554
7554
|
filesSkipped: 0,
|
|
7555
|
+
filesOversized: 0,
|
|
7555
7556
|
nodesCount: nodes.length,
|
|
7556
7557
|
linksCount: links.length,
|
|
7557
7558
|
issuesCount: issues.length,
|
|
@@ -8128,7 +8129,15 @@ function metaToRow(result) {
|
|
|
8128
8129
|
statsFilesWalked: result.stats.filesWalked,
|
|
8129
8130
|
statsFilesSkipped: result.stats.filesSkipped,
|
|
8130
8131
|
statsDurationMs: result.stats.durationMs,
|
|
8131
|
-
...projectNodeLimitColumns(result)
|
|
8132
|
+
...projectNodeLimitColumns(result),
|
|
8133
|
+
...projectOversizedColumns(result)
|
|
8134
|
+
};
|
|
8135
|
+
}
|
|
8136
|
+
function projectOversizedColumns(result) {
|
|
8137
|
+
const oversized = result.oversizedFiles ?? [];
|
|
8138
|
+
return {
|
|
8139
|
+
filesOversized: result.stats.filesOversized ?? oversized.length,
|
|
8140
|
+
oversizedFilesJson: oversized.length > 0 ? JSON.stringify(oversized) : null
|
|
8132
8141
|
};
|
|
8133
8142
|
}
|
|
8134
8143
|
function projectNodeLimitColumns(result) {
|
|
@@ -9452,6 +9461,7 @@ var PLUGIN_LOADER_TEXTS = {
|
|
|
9452
9461
|
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.",
|
|
9453
9462
|
idCollision: "Plugin '{{id}}' at {{pathA}} collides with the plugin at {{pathB}}. Rename one and rerun.",
|
|
9454
9463
|
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.",
|
|
9464
|
+
invalidManifestRedeclaredField: "{{relEntry}}: extension manifest declares {{fields}}, derived from the folder layout (structure-as-truth) and not a manifest field. Remove it: id is the leaf folder, kind the parent folder, provider kinds the `kinds/` catalog, formatter formatId the formatter folder name.",
|
|
9455
9465
|
loadErrorStorageSchemaRead: "plugin '{{pluginId}}' failed to load schema for table '{{table}}': {{schemaPath}}: {{errDescription}}",
|
|
9456
9466
|
loadErrorStorageSchemaCompile: "plugin '{{pluginId}}' failed to compile schema for table '{{table}}': {{schemaPath}}: {{errDescription}}",
|
|
9457
9467
|
loadErrorStorageKvSchemaRead: "plugin '{{pluginId}}' failed to load KV schema: {{schemaPath}}: {{errDescription}}",
|
|
@@ -9556,7 +9566,7 @@ function extractDefault(mod) {
|
|
|
9556
9566
|
if (!isRecord(mod)) return mod;
|
|
9557
9567
|
return "default" in mod ? mod["default"] : mod;
|
|
9558
9568
|
}
|
|
9559
|
-
var LOADER_INJECTED_KEYS = /* @__PURE__ */ new Set(["pluginId"
|
|
9569
|
+
var LOADER_INJECTED_KEYS = /* @__PURE__ */ new Set(["pluginId"]);
|
|
9560
9570
|
function stripFunctionsAndPluginId(input) {
|
|
9561
9571
|
if (!isRecord(input)) return input;
|
|
9562
9572
|
const out = {};
|
|
@@ -10177,6 +10187,21 @@ var PluginLoader = class {
|
|
|
10177
10187
|
manifest
|
|
10178
10188
|
} };
|
|
10179
10189
|
}
|
|
10190
|
+
const redeclared = DERIVED_MANIFEST_KEYS.filter((field) => field in exported);
|
|
10191
|
+
if (redeclared.length > 0) {
|
|
10192
|
+
return { ok: false, failure: {
|
|
10193
|
+
...fail(
|
|
10194
|
+
pluginPath,
|
|
10195
|
+
pluginId,
|
|
10196
|
+
"invalid-manifest",
|
|
10197
|
+
tx(PLUGIN_LOADER_TEXTS.invalidManifestRedeclaredField, {
|
|
10198
|
+
relEntry,
|
|
10199
|
+
fields: redeclared.map((field) => `\`${field}\``).join(", ")
|
|
10200
|
+
})
|
|
10201
|
+
),
|
|
10202
|
+
manifest
|
|
10203
|
+
} };
|
|
10204
|
+
}
|
|
10180
10205
|
const manifestView = stripFunctionsAndPluginId(exported);
|
|
10181
10206
|
if (kind === "hook") {
|
|
10182
10207
|
const hookFailure = validateHookTriggers(pluginPath, pluginId, manifest, relEntry, exported, manifestView);
|
|
@@ -10233,8 +10258,7 @@ var PluginLoader = class {
|
|
|
10233
10258
|
const instance = { ...exported, pluginId, id: pathId2, kind };
|
|
10234
10259
|
if (kind === "formatter") instance["formatId"] = pathId2;
|
|
10235
10260
|
if (kind === "provider" && discoveredKinds) {
|
|
10236
|
-
|
|
10237
|
-
instance["kinds"] = { ...inlineKinds, ...discoveredKinds };
|
|
10261
|
+
instance["kinds"] = discoveredKinds;
|
|
10238
10262
|
}
|
|
10239
10263
|
return { ok: true, extension: {
|
|
10240
10264
|
kind,
|
|
@@ -10247,6 +10271,7 @@ var PluginLoader = class {
|
|
|
10247
10271
|
} };
|
|
10248
10272
|
}
|
|
10249
10273
|
};
|
|
10274
|
+
var DERIVED_MANIFEST_KEYS = ["id", "kind", "kinds", "formatId"];
|
|
10250
10275
|
var KIND_DIR_NAMES = [
|
|
10251
10276
|
"providers",
|
|
10252
10277
|
"extractors",
|
|
@@ -10365,11 +10390,11 @@ function makeEnabledResolver(cfg, dbOverrides) {
|
|
|
10365
10390
|
function defaultResolveEnabled(_id) {
|
|
10366
10391
|
return true;
|
|
10367
10392
|
}
|
|
10368
|
-
function isBuiltInExtensionEnabled(
|
|
10369
|
-
return
|
|
10393
|
+
function isBuiltInExtensionEnabled(plugin, ext, resolveEnabled) {
|
|
10394
|
+
return isPluginEntryEnabled(plugin, ext.id, resolveEnabled);
|
|
10370
10395
|
}
|
|
10371
|
-
function
|
|
10372
|
-
return resolveEnabled(qualifiedExtensionId(
|
|
10396
|
+
function isPluginEntryEnabled(plugin, extId, resolveEnabled) {
|
|
10397
|
+
return resolveEnabled(qualifiedExtensionId(plugin.id, extId));
|
|
10373
10398
|
}
|
|
10374
10399
|
function isPluginExtensionEnabled(ext, resolveEnabled) {
|
|
10375
10400
|
return resolveEnabled(qualifiedExtensionId(ext.pluginId, ext.id));
|
|
@@ -10568,8 +10593,9 @@ async function* walkContent(roots, options) {
|
|
|
10568
10593
|
if (!parser) throw new UnknownParserError(options.parser);
|
|
10569
10594
|
const filter = options.ignoreFilter ?? buildIgnoreFilter();
|
|
10570
10595
|
const extensions = options.extensions;
|
|
10596
|
+
const sizeLimit = buildSizeLimit(options);
|
|
10571
10597
|
for (const root of roots) {
|
|
10572
|
-
for await (const file of walkRoot(root, root, filter, extensions)) {
|
|
10598
|
+
for await (const file of walkRoot(root, root, filter, extensions, sizeLimit)) {
|
|
10573
10599
|
const relPath = relative2(root, file).split(sep3).join("/");
|
|
10574
10600
|
let raw;
|
|
10575
10601
|
try {
|
|
@@ -10592,7 +10618,15 @@ async function* walkContent(roots, options) {
|
|
|
10592
10618
|
}
|
|
10593
10619
|
}
|
|
10594
10620
|
}
|
|
10595
|
-
|
|
10621
|
+
function buildSizeLimit(options) {
|
|
10622
|
+
const sizeLimit = {};
|
|
10623
|
+
if (options.maxFileSizeBytes !== void 0) {
|
|
10624
|
+
sizeLimit.maxFileSizeBytes = options.maxFileSizeBytes;
|
|
10625
|
+
}
|
|
10626
|
+
if (options.onOversizedFile) sizeLimit.onOversizedFile = options.onOversizedFile;
|
|
10627
|
+
return sizeLimit;
|
|
10628
|
+
}
|
|
10629
|
+
async function* walkRoot(root, current, filter, extensions, sizeLimit) {
|
|
10596
10630
|
let entries;
|
|
10597
10631
|
try {
|
|
10598
10632
|
entries = await readdir(current, { withFileTypes: true, encoding: "utf8" });
|
|
@@ -10606,11 +10640,16 @@ async function* walkRoot(root, current, filter, extensions) {
|
|
|
10606
10640
|
if (filter.ignores(rel)) continue;
|
|
10607
10641
|
if (entry.isSymbolicLink()) continue;
|
|
10608
10642
|
if (entry.isDirectory()) {
|
|
10609
|
-
yield* walkRoot(root, full, filter, extensions);
|
|
10643
|
+
yield* walkRoot(root, full, filter, extensions, sizeLimit);
|
|
10610
10644
|
} else if (entry.isFile() && hasMatchingExtension(name, extensions)) {
|
|
10611
10645
|
try {
|
|
10612
10646
|
const s = await lstat(full);
|
|
10613
|
-
if (s.isFile())
|
|
10647
|
+
if (!s.isFile()) continue;
|
|
10648
|
+
if (sizeLimit.maxFileSizeBytes !== void 0 && s.size > sizeLimit.maxFileSizeBytes) {
|
|
10649
|
+
sizeLimit.onOversizedFile?.({ path: rel, bytes: s.size });
|
|
10650
|
+
continue;
|
|
10651
|
+
}
|
|
10652
|
+
yield full;
|
|
10614
10653
|
} catch {
|
|
10615
10654
|
}
|
|
10616
10655
|
}
|
|
@@ -10640,6 +10679,10 @@ function resolveProviderWalk(provider) {
|
|
|
10640
10679
|
parser: read.parser
|
|
10641
10680
|
};
|
|
10642
10681
|
if (options?.ignoreFilter) walkOptions.ignoreFilter = options.ignoreFilter;
|
|
10682
|
+
if (options?.maxFileSizeBytes !== void 0) {
|
|
10683
|
+
walkOptions.maxFileSizeBytes = options.maxFileSizeBytes;
|
|
10684
|
+
}
|
|
10685
|
+
if (options?.onOversizedFile) walkOptions.onOversizedFile = options.onOversizedFile;
|
|
10643
10686
|
return walkContent(roots, walkOptions);
|
|
10644
10687
|
};
|
|
10645
10688
|
}
|
|
@@ -10674,19 +10717,19 @@ function collectViewContributions(pluginId, extensionId, instance, out, options
|
|
|
10674
10717
|
}
|
|
10675
10718
|
|
|
10676
10719
|
// core/runtime/plugin-runtime/bucketing.ts
|
|
10677
|
-
function bucketLoaded(loaded,
|
|
10720
|
+
function bucketLoaded(loaded, runtime) {
|
|
10678
10721
|
for (const ext of loaded) {
|
|
10679
10722
|
const instance = ext.instance;
|
|
10680
10723
|
if (!isExtensionInstance(instance)) continue;
|
|
10681
10724
|
bucketByKind(ext.kind, instance, {
|
|
10682
|
-
provider:
|
|
10683
|
-
extractor:
|
|
10684
|
-
analyzer:
|
|
10685
|
-
formatter:
|
|
10686
|
-
hook:
|
|
10725
|
+
provider: runtime.extensions.providers,
|
|
10726
|
+
extractor: runtime.extensions.extractors,
|
|
10727
|
+
analyzer: runtime.extensions.analyzers,
|
|
10728
|
+
formatter: runtime.extensions.formatters,
|
|
10729
|
+
hook: runtime.extensions.hooks
|
|
10687
10730
|
// `action` intentionally absent, see docstring.
|
|
10688
10731
|
});
|
|
10689
|
-
|
|
10732
|
+
runtime.manifests.push({
|
|
10690
10733
|
id: ext.id,
|
|
10691
10734
|
pluginId: ext.pluginId,
|
|
10692
10735
|
kind: ext.kind,
|
|
@@ -10694,8 +10737,8 @@ function bucketLoaded(loaded, bundle) {
|
|
|
10694
10737
|
description: instance.description ?? "",
|
|
10695
10738
|
...ext.entryPath ? { entry: ext.entryPath } : {}
|
|
10696
10739
|
});
|
|
10697
|
-
collectAnnotationContributions(ext.pluginId, instance,
|
|
10698
|
-
collectViewContributions(ext.pluginId, ext.id, instance,
|
|
10740
|
+
collectAnnotationContributions(ext.pluginId, instance, runtime.annotationContributions);
|
|
10741
|
+
collectViewContributions(ext.pluginId, ext.id, instance, runtime.viewContributions);
|
|
10699
10742
|
}
|
|
10700
10743
|
}
|
|
10701
10744
|
function collectAnnotationContributions(pluginId, instance, out) {
|
|
@@ -10753,8 +10796,8 @@ var PLUGIN_RUNTIME_TEXTS = {
|
|
|
10753
10796
|
// core/runtime/plugin-runtime/warnings.ts
|
|
10754
10797
|
var PLUGIN_ID_DISPLAY_CAP = 200;
|
|
10755
10798
|
var PLUGIN_REASON_DISPLAY_CAP = 1e3;
|
|
10756
|
-
function emitWarnings(
|
|
10757
|
-
for (const warn of
|
|
10799
|
+
function emitWarnings(runtime, printer) {
|
|
10800
|
+
for (const warn of runtime.warnings) {
|
|
10758
10801
|
printer.warn(`${warn}
|
|
10759
10802
|
`);
|
|
10760
10803
|
}
|
|
@@ -10793,7 +10836,7 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
10793
10836
|
if (resolveEnabled) loaderOpts.resolveEnabled = resolveEnabled;
|
|
10794
10837
|
const loader = createPluginLoader(loaderOpts);
|
|
10795
10838
|
const discovered = await loader.discoverAndLoadAll();
|
|
10796
|
-
const
|
|
10839
|
+
const runtime = {
|
|
10797
10840
|
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [] },
|
|
10798
10841
|
annotationContributions: [],
|
|
10799
10842
|
viewContributions: [],
|
|
@@ -10807,14 +10850,14 @@ async function loadPluginRuntime(opts = {}) {
|
|
|
10807
10850
|
};
|
|
10808
10851
|
for (const plugin of discovered) {
|
|
10809
10852
|
if (plugin.status === "enabled") {
|
|
10810
|
-
bucketLoaded(plugin.extensions ?? [],
|
|
10853
|
+
bucketLoaded(plugin.extensions ?? [], runtime);
|
|
10811
10854
|
continue;
|
|
10812
10855
|
}
|
|
10813
10856
|
if (plugin.status === "disabled") continue;
|
|
10814
|
-
|
|
10857
|
+
runtime.warnings.push(formatWarning(plugin));
|
|
10815
10858
|
}
|
|
10816
|
-
enforceRootExclusivity(
|
|
10817
|
-
return
|
|
10859
|
+
enforceRootExclusivity(runtime.annotationContributions);
|
|
10860
|
+
return runtime;
|
|
10818
10861
|
}
|
|
10819
10862
|
var AnnotationContributionConflictError = class extends Error {
|
|
10820
10863
|
/** The colliding root-exclusive key. */
|
|
@@ -10848,7 +10891,7 @@ function enforceRootExclusivity(catalog) {
|
|
|
10848
10891
|
}
|
|
10849
10892
|
}
|
|
10850
10893
|
function emptyPluginRuntime() {
|
|
10851
|
-
const
|
|
10894
|
+
const runtime = {
|
|
10852
10895
|
extensions: { providers: [], extractors: [], analyzers: [], formatters: [], hooks: [] },
|
|
10853
10896
|
annotationContributions: [],
|
|
10854
10897
|
viewContributions: [],
|
|
@@ -10860,7 +10903,7 @@ function emptyPluginRuntime() {
|
|
|
10860
10903
|
emitWarnings(this, printer);
|
|
10861
10904
|
}
|
|
10862
10905
|
};
|
|
10863
|
-
return
|
|
10906
|
+
return runtime;
|
|
10864
10907
|
}
|
|
10865
10908
|
|
|
10866
10909
|
// core/runtime/plugin-runtime/catalogs.ts
|
|
@@ -10878,12 +10921,12 @@ function collectRegisteredContributionKeys(composed) {
|
|
|
10878
10921
|
return keys;
|
|
10879
10922
|
}
|
|
10880
10923
|
function filterBuiltInManifests(manifests, resolveEnabled) {
|
|
10881
|
-
const
|
|
10882
|
-
for (const
|
|
10924
|
+
const pluginById = /* @__PURE__ */ new Map();
|
|
10925
|
+
for (const plugin of builtInPlugins) pluginById.set(plugin.id, plugin);
|
|
10883
10926
|
return manifests.filter((m) => {
|
|
10884
|
-
const
|
|
10885
|
-
if (!
|
|
10886
|
-
return
|
|
10927
|
+
const plugin = pluginById.get(m.pluginId);
|
|
10928
|
+
if (!plugin) return true;
|
|
10929
|
+
return isPluginEntryEnabled(plugin, m.id, resolveEnabled);
|
|
10887
10930
|
});
|
|
10888
10931
|
}
|
|
10889
10932
|
|
|
@@ -10926,9 +10969,9 @@ function composeScanExtensions(opts) {
|
|
|
10926
10969
|
};
|
|
10927
10970
|
}
|
|
10928
10971
|
function accumulateBuiltInScanExtensions(buckets, resolveEnabled) {
|
|
10929
|
-
for (const
|
|
10930
|
-
for (const ext of
|
|
10931
|
-
if (!isBuiltInExtensionEnabled(
|
|
10972
|
+
for (const plugin of builtInPlugins) {
|
|
10973
|
+
for (const ext of plugin.extensions) {
|
|
10974
|
+
if (!isBuiltInExtensionEnabled(plugin, ext, resolveEnabled)) continue;
|
|
10932
10975
|
switch (ext.kind) {
|
|
10933
10976
|
case "provider":
|
|
10934
10977
|
buckets.providers.push(ext);
|
|
@@ -10959,10 +11002,10 @@ function composeFormatters(opts) {
|
|
|
10959
11002
|
const resolveEnabled = opts.resolveEnabled ?? opts.pluginRuntime.resolveEnabled;
|
|
10960
11003
|
const out = [];
|
|
10961
11004
|
if (!noBuiltIns) {
|
|
10962
|
-
for (const
|
|
10963
|
-
for (const ext of
|
|
11005
|
+
for (const plugin of builtInPlugins) {
|
|
11006
|
+
for (const ext of plugin.extensions) {
|
|
10964
11007
|
if (ext.kind !== "formatter") continue;
|
|
10965
|
-
if (!isBuiltInExtensionEnabled(
|
|
11008
|
+
if (!isBuiltInExtensionEnabled(plugin, ext, resolveEnabled)) continue;
|
|
10966
11009
|
out.push(ext);
|
|
10967
11010
|
}
|
|
10968
11011
|
}
|
|
@@ -10998,9 +11041,9 @@ function registerEnabledExtensions(kernel, pluginRuntime, options = {}) {
|
|
|
10998
11041
|
);
|
|
10999
11042
|
const merged = [...userContribs];
|
|
11000
11043
|
if (!noBuiltIns) {
|
|
11001
|
-
for (const
|
|
11002
|
-
for (const ext of
|
|
11003
|
-
if (!
|
|
11044
|
+
for (const plugin of builtInPlugins) {
|
|
11045
|
+
for (const ext of plugin.extensions) {
|
|
11046
|
+
if (!isPluginEntryEnabled(plugin, ext.id, resolveEnabled)) continue;
|
|
11004
11047
|
collectViewContributions(ext.pluginId, ext.id, ext, merged);
|
|
11005
11048
|
}
|
|
11006
11049
|
}
|
|
@@ -11408,7 +11451,6 @@ var CONFIG_TEXTS = {
|
|
|
11408
11451
|
listSectionScan: "Scan",
|
|
11409
11452
|
listSectionJobs: "Jobs",
|
|
11410
11453
|
listSectionRootsAndPlugins: "Roots & plugins",
|
|
11411
|
-
listSectionHistory: "History",
|
|
11412
11454
|
listSectionOther: "Other"
|
|
11413
11455
|
};
|
|
11414
11456
|
|
|
@@ -11525,15 +11567,14 @@ var ConfigListCommand = class extends SmCommand {
|
|
|
11525
11567
|
var SECTION_DEFS = [
|
|
11526
11568
|
{
|
|
11527
11569
|
title: CONFIG_TEXTS.listSectionGeneral,
|
|
11528
|
-
exactKeys: ["
|
|
11570
|
+
exactKeys: ["schemaVersion", "tokenizer"]
|
|
11529
11571
|
},
|
|
11530
11572
|
{ title: CONFIG_TEXTS.listSectionScan, prefix: "scan.", stripPrefix: true },
|
|
11531
11573
|
{ title: CONFIG_TEXTS.listSectionJobs, prefix: "jobs.", stripPrefix: true },
|
|
11532
11574
|
{
|
|
11533
11575
|
title: CONFIG_TEXTS.listSectionRootsAndPlugins,
|
|
11534
|
-
exactKeys: ["roots", "
|
|
11535
|
-
}
|
|
11536
|
-
{ title: CONFIG_TEXTS.listSectionHistory, prefix: "history.", stripPrefix: true }
|
|
11576
|
+
exactKeys: ["roots", "plugins", "ignore"]
|
|
11577
|
+
}
|
|
11537
11578
|
];
|
|
11538
11579
|
function renderConfigSections(rows, ansi) {
|
|
11539
11580
|
const out = [];
|
|
@@ -12451,12 +12492,12 @@ function collectProviderScopes(specRoot) {
|
|
|
12451
12492
|
}
|
|
12452
12493
|
const pluginsRoot = resolve21(workspaceRoot, "plugins");
|
|
12453
12494
|
if (!existsSync17(pluginsRoot)) return out;
|
|
12454
|
-
for (const
|
|
12455
|
-
const
|
|
12456
|
-
if (!isDir(
|
|
12457
|
-
const providersRoot = resolve21(
|
|
12495
|
+
for (const pluginEntry of readdirSync6(pluginsRoot)) {
|
|
12496
|
+
const pluginDir = resolve21(pluginsRoot, pluginEntry);
|
|
12497
|
+
if (!isDir(pluginDir)) continue;
|
|
12498
|
+
const providersRoot = resolve21(pluginDir, "providers");
|
|
12458
12499
|
if (!isDir(providersRoot)) continue;
|
|
12459
|
-
|
|
12500
|
+
collectPluginProviderScopes(providersRoot, specRoot, out);
|
|
12460
12501
|
}
|
|
12461
12502
|
return out;
|
|
12462
12503
|
}
|
|
@@ -12467,7 +12508,7 @@ function isDir(path) {
|
|
|
12467
12508
|
return false;
|
|
12468
12509
|
}
|
|
12469
12510
|
}
|
|
12470
|
-
function
|
|
12511
|
+
function collectPluginProviderScopes(providersRoot, specRoot, out) {
|
|
12471
12512
|
for (const entry of readdirSync6(providersRoot)) {
|
|
12472
12513
|
const providerDir = resolve21(providersRoot, entry);
|
|
12473
12514
|
if (!isDir(providerDir)) continue;
|
|
@@ -14214,6 +14255,22 @@ var HELP_TEXTS = {
|
|
|
14214
14255
|
/** Trailing fragment for `humanFlagRow`'s `{{required}}` slot. */
|
|
14215
14256
|
humanFlagRowRequiredFragment: " (required)",
|
|
14216
14257
|
humanFooter: "Run `sm help {{name}} --format md` for the full reference.",
|
|
14258
|
+
// --- human group renderer (sm <namespace> --help, sm help <namespace>) ---
|
|
14259
|
+
/**
|
|
14260
|
+
* USAGE row for a command namespace (a prefix that owns subcommands but
|
|
14261
|
+
* is not itself a runnable verb, e.g. `plugins`, `db`). Mirrors
|
|
14262
|
+
* `humanUsageRow` but advertises the `<command>` slot instead of
|
|
14263
|
+
* positionals.
|
|
14264
|
+
*/
|
|
14265
|
+
humanGroupUsageRow: " sm {{name}} <command> [options]",
|
|
14266
|
+
/** Section heading listing the subcommands of a namespace. */
|
|
14267
|
+
humanCommandsHeading: "COMMANDS",
|
|
14268
|
+
/** Aligned subcommand row; `{{name}}` is the subcommand relative to the namespace. */
|
|
14269
|
+
humanCommandRow: " {{name}}{{padding}} {{description}}",
|
|
14270
|
+
/** Footer for the namespace overview, points at per-subcommand help. */
|
|
14271
|
+
humanGroupFooter: "Run `sm {{name}} <command> --help` for flags and arguments.",
|
|
14272
|
+
/** Fallback header description when a namespace has no curated entry in `HELP_GROUPS`. */
|
|
14273
|
+
groupFallbackDescription: "{{category}} commands",
|
|
14217
14274
|
// --- human compact overview (sm / sm --help / sm help, no verb) ---------
|
|
14218
14275
|
/**
|
|
14219
14276
|
* Compact-overview header. Replaces the Clipanion default ANSI banner.
|
|
@@ -14244,6 +14301,40 @@ var HELP_TEXTS = {
|
|
|
14244
14301
|
compactExampleRow: " {{command}}{{padding}} {{description}}",
|
|
14245
14302
|
compactFooter: "Run `sm <command> --help` for flags and arguments."
|
|
14246
14303
|
};
|
|
14304
|
+
var HELP_GROUPS = {
|
|
14305
|
+
plugins: {
|
|
14306
|
+
description: "Discover, inspect, and toggle plugins",
|
|
14307
|
+
details: "A plugin is a directory of extensions (extractors, analyzers, actions,\nhooks, formatters, providers) discovered under the project plugins dir.\n\nUse `list` and `show` to inspect what loaded, `doctor` to diagnose load\nfailures, `enable` / `disable` to toggle extensions (persisted in the DB),\nand `create` / `upgrade` to scaffold and migrate your own."
|
|
14308
|
+
},
|
|
14309
|
+
config: {
|
|
14310
|
+
description: "Read and write project configuration",
|
|
14311
|
+
details: "Configuration is a layered merge: library defaults, the committed\n`settings.json`, the gitignored `settings.local.json`, env vars, then\nCLI flags, with later layers winning.\n\nUse `list` / `get` to read the effective values, `show --source` to see\nwhich layer set a key, and `set` / `reset` to write or revert one.\nPrivacy-sensitive keys (paths outside the project) require `--yes`."
|
|
14312
|
+
},
|
|
14313
|
+
db: {
|
|
14314
|
+
description: "Inspect and maintain the project database",
|
|
14315
|
+
details: "The project database is a single SQLite file at\n`.skill-map/skill-map.db`, holding the scan graph and plugin state.\n\nUse `backup` / `restore` around risky operations, `migrate` to apply\npending kernel and plugin migrations, `reset` to drop tables (or the\nwhole file), and `dump` / `shell` / `browser` to inspect the data."
|
|
14316
|
+
},
|
|
14317
|
+
job: {
|
|
14318
|
+
description: "Manage the background job queue",
|
|
14319
|
+
details: "Probabilistic and long-running work runs as jobs: queued, persisted in\nthe database, and resumable across restarts.\n\nUse `submit` to enqueue (or `--all` to fan out across nodes), `run` to\nexecute the claim-spawn-record loop, `status` / `list` / `show` to\ninspect, `preview` to render a job without executing it, and\n`cancel` / `prune` to clean up."
|
|
14320
|
+
},
|
|
14321
|
+
actions: {
|
|
14322
|
+
description: "Inspect the registered Action catalog",
|
|
14323
|
+
details: "An Action operates on one or more nodes and is either deterministic\n(in-process code) or probabilistic (a rendered prompt a runner executes).\n\nUse `list` for the catalog of registered action types and `show` for a\nsingle action's full manifest, including its preconditions and expected\nduration."
|
|
14324
|
+
},
|
|
14325
|
+
sidecar: {
|
|
14326
|
+
description: "Manage `.sm` annotation sidecars",
|
|
14327
|
+
details: "Skill-map's annotation layer lives in co-located `.sm` YAML sidecars\nnext to each node, leaving the vendor file untouched.\n\nUse `annotate` to scaffold an empty sidecar ready for editing, `refresh`\nto realign its drift hashes with the live node, and `prune` to delete\nsidecars whose `.md` no longer exists."
|
|
14328
|
+
},
|
|
14329
|
+
hooks: {
|
|
14330
|
+
description: "Install git hooks for sidecar drift",
|
|
14331
|
+
details: "Git hooks keep your sidecars in sync with the repo as you commit.\n\n`install` writes a pre-commit hook that auto-bumps staged sidecar drift\nbefore each commit."
|
|
14332
|
+
},
|
|
14333
|
+
conformance: {
|
|
14334
|
+
description: "Run the spec conformance suite",
|
|
14335
|
+
details: "The conformance suite checks an implementation against the spec.\n\n`run` executes the spec-owned cases plus every built-in Provider and\nreports the results."
|
|
14336
|
+
}
|
|
14337
|
+
};
|
|
14247
14338
|
|
|
14248
14339
|
// cli/commands/help.ts
|
|
14249
14340
|
var HelpCommand = class extends Command15 {
|
|
@@ -14282,18 +14373,23 @@ var HelpCommand = class extends Command15 {
|
|
|
14282
14373
|
const verb = this.verbParts.join(" ").trim();
|
|
14283
14374
|
if (verb) {
|
|
14284
14375
|
const target = verbs.find((v) => v.name === verb);
|
|
14285
|
-
if (
|
|
14286
|
-
this.context.
|
|
14287
|
-
|
|
14288
|
-
glyph: errGlyph,
|
|
14289
|
-
verb,
|
|
14290
|
-
hint: ansi.dim(HELP_TEXTS.unknownVerbHint)
|
|
14291
|
-
})
|
|
14292
|
-
);
|
|
14293
|
-
return ExitCode.NotFound;
|
|
14376
|
+
if (target) {
|
|
14377
|
+
this.context.stdout.write(renderSingle(target, format));
|
|
14378
|
+
return ExitCode.Ok;
|
|
14294
14379
|
}
|
|
14295
|
-
|
|
14296
|
-
|
|
14380
|
+
const subcommands = verbs.filter((v) => v.name.startsWith(verb + " "));
|
|
14381
|
+
if (subcommands.length > 0) {
|
|
14382
|
+
this.context.stdout.write(renderGroup(verb, subcommands, format));
|
|
14383
|
+
return ExitCode.Ok;
|
|
14384
|
+
}
|
|
14385
|
+
this.context.stderr.write(
|
|
14386
|
+
tx(HELP_TEXTS.unknownVerb, {
|
|
14387
|
+
glyph: errGlyph,
|
|
14388
|
+
verb,
|
|
14389
|
+
hint: ansi.dim(HELP_TEXTS.unknownVerbHint)
|
|
14390
|
+
})
|
|
14391
|
+
);
|
|
14392
|
+
return ExitCode.NotFound;
|
|
14297
14393
|
}
|
|
14298
14394
|
if (format === "human") {
|
|
14299
14395
|
this.context.stdout.write(renderCompactOverview(verbs));
|
|
@@ -14480,6 +14576,51 @@ function renderSingle(verb, format) {
|
|
|
14480
14576
|
}
|
|
14481
14577
|
return renderSingleHuman(verb);
|
|
14482
14578
|
}
|
|
14579
|
+
function renderGroup(group, subcommands, format) {
|
|
14580
|
+
if (format === "json" || format === "md") {
|
|
14581
|
+
const doc = {
|
|
14582
|
+
cliVersion: VERSION,
|
|
14583
|
+
specVersion: resolveSpecVersion(),
|
|
14584
|
+
globalFlags: [],
|
|
14585
|
+
verbs: subcommands
|
|
14586
|
+
};
|
|
14587
|
+
return format === "json" ? JSON.stringify(doc, null, 2) + "\n" : renderMarkdown2(doc);
|
|
14588
|
+
}
|
|
14589
|
+
return renderGroupHuman(group, subcommands);
|
|
14590
|
+
}
|
|
14591
|
+
function renderGroupHuman(group, subcommands) {
|
|
14592
|
+
const meta = HELP_GROUPS[group];
|
|
14593
|
+
const description = meta?.description ?? tx(HELP_TEXTS.groupFallbackDescription, { category: subcommands[0]?.category ?? "Other" });
|
|
14594
|
+
const out = [];
|
|
14595
|
+
out.push(tx(HELP_TEXTS.humanVerbHeader, { name: group, description }));
|
|
14596
|
+
out.push("");
|
|
14597
|
+
out.push(HELP_TEXTS.humanUsageHeading);
|
|
14598
|
+
out.push(tx(HELP_TEXTS.humanGroupUsageRow, { name: group }));
|
|
14599
|
+
if (meta?.details) out.push(...renderHumanDescription(meta.details));
|
|
14600
|
+
out.push(...renderGroupCommands(group, subcommands));
|
|
14601
|
+
out.push("");
|
|
14602
|
+
out.push(tx(HELP_TEXTS.humanGroupFooter, { name: group }));
|
|
14603
|
+
return out.join("\n") + "\n";
|
|
14604
|
+
}
|
|
14605
|
+
function renderGroupCommands(group, subcommands) {
|
|
14606
|
+
const out = ["", HELP_TEXTS.humanCommandsHeading];
|
|
14607
|
+
const sorted = [...subcommands].sort((a, b) => a.name.localeCompare(b.name));
|
|
14608
|
+
const labels = sorted.map((v) => v.name.slice(group.length + 1));
|
|
14609
|
+
const width = Math.max(...labels.map((l) => l.length));
|
|
14610
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
14611
|
+
const verb = sorted[i];
|
|
14612
|
+
const label = labels[i];
|
|
14613
|
+
const { isStub, clean } = classifyDescription(verb.description);
|
|
14614
|
+
const description = (isStub ? HELP_TEXTS.compactStubMarker : "") + firstSentence(clean);
|
|
14615
|
+
const row = tx(HELP_TEXTS.humanCommandRow, {
|
|
14616
|
+
name: label,
|
|
14617
|
+
padding: padRight("", width - label.length),
|
|
14618
|
+
description
|
|
14619
|
+
});
|
|
14620
|
+
out.push(truncate2(row, COMPACT_ROW_MAX));
|
|
14621
|
+
}
|
|
14622
|
+
return out;
|
|
14623
|
+
}
|
|
14483
14624
|
function renderSingleHuman(verb) {
|
|
14484
14625
|
const out = [];
|
|
14485
14626
|
out.push(buildHumanHeader(verb));
|
|
@@ -14611,7 +14752,7 @@ function routeHelpArgs(args2, cli2) {
|
|
|
14611
14752
|
if (!shouldRouteHelp(args2)) return args2;
|
|
14612
14753
|
const leading = leadingPositionals(args2);
|
|
14613
14754
|
if (leading.length === 0) return args2;
|
|
14614
|
-
const verbPath =
|
|
14755
|
+
const verbPath = longestVerbOrGroupPrefix(leading, registeredVerbPaths(cli2));
|
|
14615
14756
|
if (verbPath.length === 0) return args2;
|
|
14616
14757
|
return ["help", ...verbPath];
|
|
14617
14758
|
}
|
|
@@ -14630,14 +14771,15 @@ function leadingPositionals(args2) {
|
|
|
14630
14771
|
}
|
|
14631
14772
|
return out;
|
|
14632
14773
|
}
|
|
14633
|
-
function
|
|
14634
|
-
let
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14774
|
+
function longestVerbOrGroupPrefix(positionals, verbPaths) {
|
|
14775
|
+
for (let len = positionals.length; len >= 1; len--) {
|
|
14776
|
+
const prefix = positionals.slice(0, len);
|
|
14777
|
+
const matches = verbPaths.some(
|
|
14778
|
+
(path) => path.length >= len && prefix.every((tok, i) => path[i] === tok)
|
|
14779
|
+
);
|
|
14780
|
+
if (matches) return prefix;
|
|
14639
14781
|
}
|
|
14640
|
-
return
|
|
14782
|
+
return [];
|
|
14641
14783
|
}
|
|
14642
14784
|
function registeredVerbPaths(cli2) {
|
|
14643
14785
|
const rawDefs = cli2.definitions();
|
|
@@ -16157,7 +16299,18 @@ async function walkAndExtract(opts) {
|
|
|
16157
16299
|
const accum = createWalkAccumulators();
|
|
16158
16300
|
const wctx = buildWalkContext(opts);
|
|
16159
16301
|
const claimedPaths = /* @__PURE__ */ new Set();
|
|
16160
|
-
const
|
|
16302
|
+
const oversizedFiles = [];
|
|
16303
|
+
const oversizedSeen = /* @__PURE__ */ new Set();
|
|
16304
|
+
const onOversizedFile = (info) => {
|
|
16305
|
+
if (oversizedSeen.has(info.path)) return;
|
|
16306
|
+
oversizedSeen.add(info.path);
|
|
16307
|
+
oversizedFiles.push(info);
|
|
16308
|
+
};
|
|
16309
|
+
const walkOptions = {
|
|
16310
|
+
...opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {},
|
|
16311
|
+
onOversizedFile,
|
|
16312
|
+
...opts.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: opts.maxFileSizeBytes } : {}
|
|
16313
|
+
};
|
|
16161
16314
|
let filesWalked = 0;
|
|
16162
16315
|
let index = 0;
|
|
16163
16316
|
const effectiveMaxNodes = opts.overrideMaxNodes ?? opts.recommendedNodeLimit;
|
|
@@ -16190,6 +16343,7 @@ async function walkAndExtract(opts) {
|
|
|
16190
16343
|
cachedPaths: accum.cachedPaths,
|
|
16191
16344
|
frontmatterIssues: accum.frontmatterIssues,
|
|
16192
16345
|
filesWalked,
|
|
16346
|
+
oversizedFiles,
|
|
16193
16347
|
recommendedNodeLimit: opts.recommendedNodeLimit,
|
|
16194
16348
|
overrideMaxNodes: opts.overrideMaxNodes,
|
|
16195
16349
|
capReached,
|
|
@@ -16477,7 +16631,8 @@ async function runScanInternal(_kernel, options) {
|
|
|
16477
16631
|
pluginStores: options.pluginStores,
|
|
16478
16632
|
activeProvider: activeProviderId,
|
|
16479
16633
|
recommendedNodeLimit: options.recommendedNodeLimit ?? 256,
|
|
16480
|
-
overrideMaxNodes: options.overrideMaxNodes ?? null
|
|
16634
|
+
overrideMaxNodes: options.overrideMaxNodes ?? null,
|
|
16635
|
+
...options.maxFileSizeBytes !== void 0 ? { maxFileSizeBytes: options.maxFileSizeBytes } : {}
|
|
16481
16636
|
});
|
|
16482
16637
|
const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
|
|
16483
16638
|
const resolved = resolveSignals({
|
|
@@ -16636,6 +16791,7 @@ function buildScanStats(walked, issues, start) {
|
|
|
16636
16791
|
// Providers compete.
|
|
16637
16792
|
filesWalked: walked.filesWalked,
|
|
16638
16793
|
filesSkipped: 0,
|
|
16794
|
+
filesOversized: walked.oversizedFiles.length,
|
|
16639
16795
|
nodesCount: walked.nodes.length,
|
|
16640
16796
|
linksCount: walked.internalLinks.length,
|
|
16641
16797
|
issuesCount: issues.length,
|
|
@@ -16652,6 +16808,7 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
|
16652
16808
|
scannedBy: SCANNED_BY,
|
|
16653
16809
|
recommendedNodeLimit: walked.recommendedNodeLimit,
|
|
16654
16810
|
overrideMaxNodes: walked.overrideMaxNodes,
|
|
16811
|
+
oversizedFiles: walked.oversizedFiles,
|
|
16655
16812
|
nodes: walked.nodes,
|
|
16656
16813
|
links: walked.internalLinks,
|
|
16657
16814
|
issues,
|
|
@@ -17047,13 +17204,13 @@ var SCAN_RUNNER_TEXTS = {
|
|
|
17047
17204
|
activeProviderAmbiguousUnderYes: "{{glyph}} Multiple provider markers detected ({{candidates}}) and --yes is set.\n {{hint}}\n",
|
|
17048
17205
|
activeProviderAmbiguousUnderYesHint: "Set the lens explicitly with `sm config set activeProvider <id>` and re-run, or omit --yes for interactive selection.",
|
|
17049
17206
|
/**
|
|
17050
|
-
* Active lens points at a
|
|
17207
|
+
* Active lens points at a plugin the operator has disabled (via
|
|
17051
17208
|
* `sm plugins disable <id>` or the Settings UI). Classification keeps
|
|
17052
17209
|
* running because it's provider-driven, but the lens-gated extractors
|
|
17053
|
-
* for the disabled
|
|
17210
|
+
* for the disabled plugin silently no-op. Without this warning the
|
|
17054
17211
|
* graph quietly differs from what the lens implies.
|
|
17055
17212
|
*/
|
|
17056
|
-
|
|
17213
|
+
activeProviderPluginDisabledWarning: 'activeProvider = "{{id}}" but the "{{id}}" plugin is currently disabled; provider-specific extractors will not run. Re-enable the plugin with `sm plugins enable {{id}}` or switch the lens with `sm config set activeProvider <id>` to silence this warning.',
|
|
17057
17214
|
/**
|
|
17058
17215
|
* Active-provider drift: the snapshot of provider markers persisted
|
|
17059
17216
|
* when `activeProvider` was set (`activeProviderMarkers`) no longer
|
|
@@ -17222,7 +17379,6 @@ function persistActiveProvider(cwd, id, markers, printer) {
|
|
|
17222
17379
|
target: "project",
|
|
17223
17380
|
cwd
|
|
17224
17381
|
});
|
|
17225
|
-
printer.info(tx(SCAN_RUNNER_TEXTS.activeProviderAutodetected, { id }));
|
|
17226
17382
|
} catch (err) {
|
|
17227
17383
|
const message = err instanceof Error ? err.message : String(err);
|
|
17228
17384
|
printer.warn(
|
|
@@ -17279,11 +17435,11 @@ function diffMarkers(snapshot, current) {
|
|
|
17279
17435
|
}
|
|
17280
17436
|
return { added, removed };
|
|
17281
17437
|
}
|
|
17282
|
-
function
|
|
17438
|
+
function warnIfLensPluginDisabled(args2) {
|
|
17283
17439
|
if (args2.activeProvider === null) return;
|
|
17284
17440
|
if (args2.resolveEnabled(args2.activeProvider)) return;
|
|
17285
17441
|
args2.printer.warn(
|
|
17286
|
-
tx(SCAN_RUNNER_TEXTS.
|
|
17442
|
+
tx(SCAN_RUNNER_TEXTS.activeProviderPluginDisabledWarning, {
|
|
17287
17443
|
id: args2.activeProvider
|
|
17288
17444
|
})
|
|
17289
17445
|
);
|
|
@@ -17448,10 +17604,12 @@ async function runScanForCommand(opts) {
|
|
|
17448
17604
|
referenceablePaths,
|
|
17449
17605
|
ctx.cwd,
|
|
17450
17606
|
activeProvider,
|
|
17451
|
-
cfg.scan.maxNodes
|
|
17607
|
+
cfg.scan.maxNodes,
|
|
17608
|
+
cfg.scan.maxFileSizeBytes
|
|
17452
17609
|
);
|
|
17453
17610
|
const willPersist = !opts.noBuiltIns && !opts.dryRun;
|
|
17454
|
-
|
|
17611
|
+
const scanned = await (willPersist ? runPersistPath(opts, dbPath, jobsDir, strict, loadPrior, runScanWith, extensions) : runEphemeralPath(opts, dbPath, strict, loadPrior, runScanWith));
|
|
17612
|
+
return scanned.kind === "ok" ? { ...scanned, lensAutoDetected: lens.autoDetected } : scanned;
|
|
17455
17613
|
}
|
|
17456
17614
|
function detectionProviders(extensions) {
|
|
17457
17615
|
return extensions?.providers ?? [];
|
|
@@ -17480,12 +17638,20 @@ async function resolveActiveLens(opts, ctx, effectiveRoots, pluginRuntime, provi
|
|
|
17480
17638
|
})
|
|
17481
17639
|
};
|
|
17482
17640
|
}
|
|
17483
|
-
|
|
17641
|
+
warnIfLensPluginDisabled({
|
|
17484
17642
|
activeProvider: bootstrap.activeProvider,
|
|
17485
17643
|
resolveEnabled: opts.resolveEnabledOverride ?? pluginRuntime.resolveEnabled,
|
|
17486
17644
|
printer: opts.printer
|
|
17487
17645
|
});
|
|
17488
|
-
return {
|
|
17646
|
+
return {
|
|
17647
|
+
kind: "ok",
|
|
17648
|
+
activeProvider: bootstrap.activeProvider,
|
|
17649
|
+
// Only when the lens was freshly auto-detected (not read from
|
|
17650
|
+
// config) does the caller announce it. The bootstrap no longer
|
|
17651
|
+
// prints it itself, to avoid interleaving stderr with the
|
|
17652
|
+
// stdout scan summary on a tty.
|
|
17653
|
+
autoDetected: bootstrap.source === "autodetect" ? bootstrap.activeProvider : null
|
|
17654
|
+
};
|
|
17489
17655
|
}
|
|
17490
17656
|
function emitReferenceWalkAdvisory(walk3, opts) {
|
|
17491
17657
|
if (walk3.truncated) {
|
|
@@ -17553,7 +17719,7 @@ function makePriorLoader(noBuiltIns, strict) {
|
|
|
17553
17719
|
return loaded;
|
|
17554
17720
|
};
|
|
17555
17721
|
}
|
|
17556
|
-
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider, recommendedNodeLimit) {
|
|
17722
|
+
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider, recommendedNodeLimit, maxFileSizeBytes) {
|
|
17557
17723
|
return async (prior, priorExtractorRuns, orphanJobFiles) => {
|
|
17558
17724
|
if (opts.changed && prior === null) {
|
|
17559
17725
|
opts.stderr.write(SCAN_RUNNER_TEXTS.changedNoPriorWarning);
|
|
@@ -17569,6 +17735,7 @@ function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, exte
|
|
|
17569
17735
|
prior,
|
|
17570
17736
|
activeProvider,
|
|
17571
17737
|
recommendedNodeLimit,
|
|
17738
|
+
maxFileSizeBytes,
|
|
17572
17739
|
...priorExtractorRuns ? { priorExtractorRuns } : {},
|
|
17573
17740
|
...orphanJobFiles ? { orphanJobFiles } : {}
|
|
17574
17741
|
});
|
|
@@ -17590,7 +17757,8 @@ function buildRunScanOptions(args2) {
|
|
|
17590
17757
|
orphanJobFiles: orphanJobFiles ?? [],
|
|
17591
17758
|
activeProvider: args2.activeProvider,
|
|
17592
17759
|
recommendedNodeLimit: args2.recommendedNodeLimit,
|
|
17593
|
-
overrideMaxNodes: opts.maxNodes ?? null
|
|
17760
|
+
overrideMaxNodes: opts.maxNodes ?? null,
|
|
17761
|
+
maxFileSizeBytes: args2.maxFileSizeBytes
|
|
17594
17762
|
};
|
|
17595
17763
|
if (args2.extensions) runOptions.extensions = args2.extensions;
|
|
17596
17764
|
if (prior) {
|
|
@@ -17962,6 +18130,11 @@ async function runFirstScan(scopeRoot, strict, printer, stderr, stdin, ansi) {
|
|
|
17962
18130
|
return ExitCode.Ok;
|
|
17963
18131
|
}
|
|
17964
18132
|
const result = outcome.result;
|
|
18133
|
+
if (outcome.lensAutoDetected) {
|
|
18134
|
+
printer.info(
|
|
18135
|
+
tx(SCAN_RUNNER_TEXTS.activeProviderAutodetected, { id: outcome.lensAutoDetected })
|
|
18136
|
+
);
|
|
18137
|
+
}
|
|
17965
18138
|
const hasErrors = result.issues.some((i) => i.severity === "error");
|
|
17966
18139
|
printer.info(
|
|
17967
18140
|
tx(INIT_TEXTS.firstScanSummary, {
|
|
@@ -19480,10 +19653,10 @@ var PLUGINS_TEXTS = {
|
|
|
19480
19653
|
pluginNotFoundHint: "Run `sm plugins list` for discovered ids and the qualified extension ids.",
|
|
19481
19654
|
pluginLocked: '{{glyph}} Plugin "{{id}}" is locked by the host and cannot be toggled.\n {{hint}}\n',
|
|
19482
19655
|
pluginLockedHint: "Locked plugins are mandatory for correct operation. To remove the lock, edit `src/kernel/config/locked-plugins.ts`.",
|
|
19483
|
-
qualifiedIdNotFound: "{{glyph}} Qualified extension id not found: {{id}}\n The owning
|
|
19484
|
-
qualifiedIdNotFoundHint: "Run `sm plugins list` to see what each
|
|
19485
|
-
|
|
19486
|
-
|
|
19656
|
+
qualifiedIdNotFound: "{{glyph}} Qualified extension id not found: {{id}}\n The owning plugin '{{pluginId}}' does not declare an extension with id '{{extId}}'.\n {{hint}}\n",
|
|
19657
|
+
qualifiedIdNotFoundHint: "Run `sm plugins list` to see what each plugin ships.",
|
|
19658
|
+
qualifiedIdUnknownPlugin: "{{glyph}} Qualified extension id references unknown plugin: {{pluginId}}\n {{hint}}\n",
|
|
19659
|
+
qualifiedIdUnknownPluginHint: "Run `sm plugins list` for known plugin ids.",
|
|
19487
19660
|
// Spec § A.10, `applicableKinds` filter on Extractors. When an extractor
|
|
19488
19661
|
// declares a kind that no installed Provider emits, the load succeeds
|
|
19489
19662
|
// (the Provider may arrive later) but `sm plugins doctor` surfaces a
|
|
@@ -19508,7 +19681,7 @@ var PLUGINS_TEXTS = {
|
|
|
19508
19681
|
// --- doctor verb -----------------------------------------------------
|
|
19509
19682
|
/**
|
|
19510
19683
|
* One-line summary that opens the human doctor output. `enabled` is
|
|
19511
|
-
* the count of enabled extensions across every
|
|
19684
|
+
* the count of enabled extensions across every plugin (every
|
|
19512
19685
|
* extension is independently toggle-able by its qualified id); the
|
|
19513
19686
|
* value matches the row count rendered by `sm plugins list` once
|
|
19514
19687
|
* disabled extensions are filtered out.
|
|
@@ -19552,10 +19725,10 @@ var PLUGINS_TEXTS = {
|
|
|
19552
19725
|
/**
|
|
19553
19726
|
* Macro expansion summary printed on stderr before the confirm
|
|
19554
19727
|
* prompt (or before the `--yes` rejection). The block lists every
|
|
19555
|
-
* qualified extension id the bare
|
|
19728
|
+
* qualified extension id the bare plugin id resolves to, so the
|
|
19556
19729
|
* user sees the exact set that would flip.
|
|
19557
19730
|
*/
|
|
19558
|
-
bundleMacroHeader: "sm plugins {{verb}} {{
|
|
19731
|
+
bundleMacroHeader: "sm plugins {{verb}} {{pluginId}}: this will affect {{count}} extensions:\n",
|
|
19559
19732
|
bundleMacroRow: " - {{id}}\n",
|
|
19560
19733
|
/**
|
|
19561
19734
|
* Interactive prompt rendered to a TTY by the macro path. The
|
|
@@ -19575,7 +19748,7 @@ var PLUGINS_TEXTS = {
|
|
|
19575
19748
|
* the directed re-run hint.
|
|
19576
19749
|
*/
|
|
19577
19750
|
bundleMacroRequiresYes: "{{glyph}} Refusing to {{verb}} multiple extensions without confirmation.\n {{hint}}\n",
|
|
19578
|
-
bundleMacroRequiresYesHint: "Re-run with --yes to apply, or pass a qualified id `<
|
|
19751
|
+
bundleMacroRequiresYesHint: "Re-run with --yes to apply, or pass a qualified id `<plugin>/<extension>` for a single extension.",
|
|
19579
19752
|
// --- list / show renderers ------------------------------------------
|
|
19580
19753
|
rowStatusOk: "ok",
|
|
19581
19754
|
rowStatusOff: "off",
|
|
@@ -19588,18 +19761,18 @@ var PLUGINS_TEXTS = {
|
|
|
19588
19761
|
sourceBuiltIn: "built-in",
|
|
19589
19762
|
sourceUser: "user",
|
|
19590
19763
|
/**
|
|
19591
|
-
* Compact
|
|
19764
|
+
* Compact plugin row: ` GLYPH ID(pad) N ext SOURCE`.
|
|
19592
19765
|
* Padding for `id` and `count` is computed at render time so all rows
|
|
19593
19766
|
* align regardless of length. The glyph is wrapped in color before the
|
|
19594
19767
|
* template substitution.
|
|
19595
19768
|
*/
|
|
19596
|
-
|
|
19769
|
+
pluginRow: " {{glyph}} {{id}}{{count}} ext {{source}}",
|
|
19597
19770
|
/**
|
|
19598
|
-
* Indent applied to the names / reason lines under each
|
|
19771
|
+
* Indent applied to the names / reason lines under each plugin row.
|
|
19599
19772
|
* Kept as a single source of truth so the wrap math (`wrapNames`) and
|
|
19600
19773
|
* the visible output stay in sync.
|
|
19601
19774
|
*/
|
|
19602
|
-
|
|
19775
|
+
pluginSubIndent: " ",
|
|
19603
19776
|
listTipShow: "\nTip: `sm plugins show <id>` for kinds, versions, and per-extension status.\n",
|
|
19604
19777
|
/** Show command, built-in header (no version row, no path). */
|
|
19605
19778
|
detailHeaderBuiltIn: " {{glyph}} {{id}} {{source}} {{count}} extension{{plural}}\n",
|
|
@@ -19621,11 +19794,11 @@ var PLUGINS_TEXTS = {
|
|
|
19621
19794
|
/** Extensions block heading, separated from the header by a blank line. */
|
|
19622
19795
|
detailExtensionsBlock: "\n",
|
|
19623
19796
|
/**
|
|
19624
|
-
* Extension row inside the
|
|
19797
|
+
* Extension row inside the plugin detail. Every extension is
|
|
19625
19798
|
* independently toggle-able, so every row carries its own glyph
|
|
19626
19799
|
* (✓ / ✕). Padding for {{kind}} and {{name}} is computed at render
|
|
19627
19800
|
* time so columns align inside the block. `{{versionSuffix}}` is
|
|
19628
|
-
* either ` v<x.y.z>` (user plugins) or empty (built-in
|
|
19801
|
+
* either ` v<x.y.z>` (user plugins) or empty (built-in plugins,
|
|
19629
19802
|
* which inherit the CLI version and do not maintain per-extension
|
|
19630
19803
|
* versions of their own).
|
|
19631
19804
|
*/
|
|
@@ -19633,7 +19806,7 @@ var PLUGINS_TEXTS = {
|
|
|
19633
19806
|
detailVersionUnknown: "?",
|
|
19634
19807
|
detailCompatUnknown: "?",
|
|
19635
19808
|
/**
|
|
19636
|
-
* Show command, single-extension header (qualified `<
|
|
19809
|
+
* Show command, single-extension header (qualified `<plugin>/<ext>` id
|
|
19637
19810
|
* shape). Mirrors `detailHeaderBuiltIn` but the count slot is replaced
|
|
19638
19811
|
* by the kind so the reader sees at a glance whether they are looking
|
|
19639
19812
|
* at an extractor, analyzer, etc. Version moves down into the field
|
|
@@ -19680,19 +19853,19 @@ var PLUGINS_TEXTS = {
|
|
|
19680
19853
|
};
|
|
19681
19854
|
|
|
19682
19855
|
// plugins/presentation-order.ts
|
|
19683
|
-
var
|
|
19856
|
+
var BUILT_IN_PLUGIN_PRESENTATION_ORDER = [
|
|
19684
19857
|
"core",
|
|
19685
19858
|
"claude",
|
|
19686
19859
|
"antigravity",
|
|
19687
19860
|
"openai",
|
|
19688
19861
|
"agent-skills"
|
|
19689
19862
|
];
|
|
19690
|
-
function
|
|
19863
|
+
function sortPluginsForPresentation(plugins) {
|
|
19691
19864
|
const orderIndex = (id) => {
|
|
19692
|
-
const idx =
|
|
19693
|
-
return idx >= 0 ? idx :
|
|
19865
|
+
const idx = BUILT_IN_PLUGIN_PRESENTATION_ORDER.indexOf(id);
|
|
19866
|
+
return idx >= 0 ? idx : BUILT_IN_PLUGIN_PRESENTATION_ORDER.length;
|
|
19694
19867
|
};
|
|
19695
|
-
return [...
|
|
19868
|
+
return [...plugins].sort((a, b) => {
|
|
19696
19869
|
const ai = orderIndex(a.id);
|
|
19697
19870
|
const bi = orderIndex(b.id);
|
|
19698
19871
|
if (ai !== bi) return ai - bi;
|
|
@@ -19729,24 +19902,24 @@ async function loadAll(opts) {
|
|
|
19729
19902
|
return loader.discoverAndLoadAll();
|
|
19730
19903
|
}
|
|
19731
19904
|
function builtInRows(resolveEnabled) {
|
|
19732
|
-
return
|
|
19733
|
-
const extensions =
|
|
19734
|
-
const manifestSummary =
|
|
19905
|
+
return sortPluginsForPresentation(builtInPlugins).map((plugin) => {
|
|
19906
|
+
const extensions = plugin.extensions.map((ext) => extensionRowFromBuiltIn(ext, plugin, resolveEnabled));
|
|
19907
|
+
const manifestSummary = plugin.extensions.map((ext) => `${ext.kind}:${qualifiedExtensionId(plugin.id, ext.id)}@${ext.version}`).join(", ");
|
|
19735
19908
|
return {
|
|
19736
|
-
id:
|
|
19909
|
+
id: plugin.id,
|
|
19737
19910
|
enabled: extensions.some((e) => e.enabled),
|
|
19738
|
-
description:
|
|
19911
|
+
description: plugin.description,
|
|
19739
19912
|
extensions,
|
|
19740
19913
|
manifestSummary
|
|
19741
19914
|
};
|
|
19742
19915
|
});
|
|
19743
19916
|
}
|
|
19744
|
-
function extensionRowFromBuiltIn(ext,
|
|
19917
|
+
function extensionRowFromBuiltIn(ext, plugin, resolveEnabled) {
|
|
19745
19918
|
const row = {
|
|
19746
19919
|
id: ext.id,
|
|
19747
19920
|
kind: ext.kind,
|
|
19748
19921
|
version: ext.version,
|
|
19749
|
-
enabled: resolveEnabled(qualifiedExtensionId(
|
|
19922
|
+
enabled: resolveEnabled(qualifiedExtensionId(plugin.id, ext.id)),
|
|
19750
19923
|
description: ext.description ?? ""
|
|
19751
19924
|
};
|
|
19752
19925
|
if (ext.entry !== void 0) row.entry = ext.entry;
|
|
@@ -19782,7 +19955,7 @@ var PluginsListCommand = class extends SmCommand {
|
|
|
19782
19955
|
static usage = Command22.Usage({
|
|
19783
19956
|
category: "Plugins",
|
|
19784
19957
|
description: "List discovered plugins and their load status.",
|
|
19785
|
-
details: "Scans <cwd>/.skill-map/plugins (or --plugin-dir <path>). Built-in
|
|
19958
|
+
details: "Scans <cwd>/.skill-map/plugins (or --plugin-dir <path>). Built-in plugins (claude, core) are listed alongside user plugins."
|
|
19786
19959
|
});
|
|
19787
19960
|
pluginDir = Option21.String("--plugin-dir", { required: false });
|
|
19788
19961
|
async run() {
|
|
@@ -19819,14 +19992,14 @@ function renderListHuman(builtIns2, plugins, resolveEnabled, ansi) {
|
|
|
19819
19992
|
const idCol = row.id.padEnd(idWidth);
|
|
19820
19993
|
const countCol = String(row.names.length).padStart(countWidth);
|
|
19821
19994
|
lines.push(
|
|
19822
|
-
tx(PLUGINS_TEXTS.
|
|
19995
|
+
tx(PLUGINS_TEXTS.pluginRow, {
|
|
19823
19996
|
glyph,
|
|
19824
19997
|
id: idCol,
|
|
19825
19998
|
count: ` ${countCol}`,
|
|
19826
19999
|
source: ansi.dim(row.source)
|
|
19827
20000
|
})
|
|
19828
20001
|
);
|
|
19829
|
-
const indent = PLUGINS_TEXTS.
|
|
20002
|
+
const indent = PLUGINS_TEXTS.pluginSubIndent;
|
|
19830
20003
|
if (row.reason) {
|
|
19831
20004
|
lines.push(`${indent}${ansi.dim(row.reason)}`);
|
|
19832
20005
|
} else if (row.names.length > 0) {
|
|
@@ -19890,11 +20063,11 @@ var PluginsShowCommand = class extends SmCommand {
|
|
|
19890
20063
|
category: "Plugins",
|
|
19891
20064
|
description: "Show a single plugin's manifest + loaded extensions.",
|
|
19892
20065
|
details: `
|
|
19893
|
-
Accepts a
|
|
20066
|
+
Accepts a plugin id (\`core\`, \`claude\`, \`my-plugin\`)
|
|
19894
20067
|
or a qualified extension id (\`core/<ext-id>\`,
|
|
19895
20068
|
\`<plugin>/<ext-id>\`). When given a qualified id, validates the
|
|
19896
20069
|
extension exists and renders a single-extension detail block.
|
|
19897
|
-
The bare form renders the parent
|
|
20070
|
+
The bare form renders the parent plugin's detail with per-extension
|
|
19898
20071
|
status. The same id shapes \`sm plugins enable\` and
|
|
19899
20072
|
\`sm plugins disable\` accept resolve cleanly here too.
|
|
19900
20073
|
`
|
|
@@ -19911,9 +20084,9 @@ var PluginsShowCommand = class extends SmCommand {
|
|
|
19911
20084
|
this.printer.error(lookupResult.error);
|
|
19912
20085
|
return ExitCode.NotFound;
|
|
19913
20086
|
}
|
|
19914
|
-
const {
|
|
19915
|
-
const builtIn = builtIns2.find((b) => b.id ===
|
|
19916
|
-
const match = plugins.find((p) => p.id ===
|
|
20087
|
+
const { pluginId, extId } = lookupResult;
|
|
20088
|
+
const builtIn = builtIns2.find((b) => b.id === pluginId);
|
|
20089
|
+
const match = plugins.find((p) => p.id === pluginId);
|
|
19917
20090
|
if (!builtIn && !match) {
|
|
19918
20091
|
this.printer.error(
|
|
19919
20092
|
tx(PLUGINS_TEXTS.pluginNotFound, {
|
|
@@ -19925,7 +20098,7 @@ var PluginsShowCommand = class extends SmCommand {
|
|
|
19925
20098
|
return ExitCode.NotFound;
|
|
19926
20099
|
}
|
|
19927
20100
|
if (extId !== void 0) {
|
|
19928
|
-
return this.renderExtensionDetail({ extId,
|
|
20101
|
+
return this.renderExtensionDetail({ extId, pluginId, builtIn, match });
|
|
19929
20102
|
}
|
|
19930
20103
|
if (this.json) {
|
|
19931
20104
|
const payload = builtIn ?? match;
|
|
@@ -19939,23 +20112,23 @@ var PluginsShowCommand = class extends SmCommand {
|
|
|
19939
20112
|
}
|
|
19940
20113
|
/**
|
|
19941
20114
|
* Render the single-extension detail block, the path taken when the
|
|
19942
|
-
* user supplies a qualified `<
|
|
19943
|
-
* single extension row (no surrounding
|
|
20115
|
+
* user supplies a qualified `<plugin>/<ext>` id. `--json` emits the
|
|
20116
|
+
* single extension row (no surrounding plugin envelope) so tooling
|
|
19944
20117
|
* can pipe straight into `jq`; human mode renders a focused header
|
|
19945
20118
|
* plus a Kind / Version / Stability / Description / Preconditions /
|
|
19946
20119
|
* Entry field block.
|
|
19947
20120
|
*/
|
|
19948
20121
|
renderExtensionDetail(args2) {
|
|
19949
|
-
const { extId,
|
|
20122
|
+
const { extId, pluginId, builtIn, match } = args2;
|
|
19950
20123
|
const ansi = this.ansiFor("stdout");
|
|
19951
20124
|
if (builtIn) {
|
|
19952
20125
|
const ext = builtIn.extensions.find((e) => e.id === extId);
|
|
19953
20126
|
if (!ext) return ExitCode.NotFound;
|
|
19954
20127
|
if (this.json) {
|
|
19955
|
-
this.printer.data(JSON.stringify({ pluginId
|
|
20128
|
+
this.printer.data(JSON.stringify({ pluginId, ...ext }, omitModule, 2) + "\n");
|
|
19956
20129
|
return ExitCode.Ok;
|
|
19957
20130
|
}
|
|
19958
|
-
this.printer.data(renderBuiltInExtensionDetail(
|
|
20131
|
+
this.printer.data(renderBuiltInExtensionDetail(pluginId, ext, ansi));
|
|
19959
20132
|
return ExitCode.Ok;
|
|
19960
20133
|
}
|
|
19961
20134
|
const userExt = match?.extensions?.find((e) => e.id === extId);
|
|
@@ -19964,53 +20137,53 @@ var PluginsShowCommand = class extends SmCommand {
|
|
|
19964
20137
|
this.printer.data(JSON.stringify(userExt, omitModule, 2) + "\n");
|
|
19965
20138
|
return ExitCode.Ok;
|
|
19966
20139
|
}
|
|
19967
|
-
this.printer.data(renderUserExtensionDetail(
|
|
20140
|
+
this.printer.data(renderUserExtensionDetail(pluginId, userExt, ansi));
|
|
19968
20141
|
return ExitCode.Ok;
|
|
19969
20142
|
}
|
|
19970
20143
|
};
|
|
19971
20144
|
function resolveShowLookupId(id, builtIns2, plugins, ansi) {
|
|
19972
|
-
if (!id.includes("/")) return {
|
|
20145
|
+
if (!id.includes("/")) return { pluginId: id };
|
|
19973
20146
|
const parsed = parseQualifiedId(id);
|
|
19974
20147
|
if ("error" in parsed) return { error: malformedQualifiedError(id, ansi) };
|
|
19975
|
-
const {
|
|
19976
|
-
const knownExts = collectKnownExtensions(
|
|
19977
|
-
if (knownExts === null) return { error:
|
|
20148
|
+
const { pluginId, extId } = parsed;
|
|
20149
|
+
const knownExts = collectKnownExtensions(pluginId, builtIns2, plugins);
|
|
20150
|
+
if (knownExts === null) return { error: unknownPluginError(pluginId, ansi) };
|
|
19978
20151
|
if (!knownExts.includes(extId)) {
|
|
19979
|
-
return { error: unknownExtensionError(id,
|
|
20152
|
+
return { error: unknownExtensionError(id, pluginId, extId, ansi) };
|
|
19980
20153
|
}
|
|
19981
|
-
return {
|
|
20154
|
+
return { pluginId, extId };
|
|
19982
20155
|
}
|
|
19983
20156
|
function parseQualifiedId(id) {
|
|
19984
|
-
const [
|
|
19985
|
-
if (!
|
|
19986
|
-
return {
|
|
20157
|
+
const [pluginId, extId, ...rest] = id.split("/");
|
|
20158
|
+
if (!pluginId || !extId || rest.length > 0) return { error: true };
|
|
20159
|
+
return { pluginId, extId };
|
|
19987
20160
|
}
|
|
19988
|
-
function collectKnownExtensions(
|
|
19989
|
-
const builtIn = builtIns2.find((b) => b.id ===
|
|
20161
|
+
function collectKnownExtensions(pluginId, builtIns2, plugins) {
|
|
20162
|
+
const builtIn = builtIns2.find((b) => b.id === pluginId);
|
|
19990
20163
|
if (builtIn) return builtIn.extensions.map((e) => e.id);
|
|
19991
|
-
const userPlugin = plugins.find((p) => p.id ===
|
|
20164
|
+
const userPlugin = plugins.find((p) => p.id === pluginId);
|
|
19992
20165
|
if (userPlugin) return userPlugin.extensions?.map((e) => e.id) ?? [];
|
|
19993
20166
|
return null;
|
|
19994
20167
|
}
|
|
19995
20168
|
function malformedQualifiedError(id, ansi) {
|
|
19996
|
-
return tx(PLUGINS_TEXTS.
|
|
20169
|
+
return tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
19997
20170
|
glyph: ansi.red("\u2715"),
|
|
19998
|
-
|
|
19999
|
-
hint: ansi.dim(PLUGINS_TEXTS.
|
|
20171
|
+
pluginId: sanitizeForTerminal(id),
|
|
20172
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
20000
20173
|
});
|
|
20001
20174
|
}
|
|
20002
|
-
function
|
|
20003
|
-
return tx(PLUGINS_TEXTS.
|
|
20175
|
+
function unknownPluginError(pluginId, ansi) {
|
|
20176
|
+
return tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
20004
20177
|
glyph: ansi.red("\u2715"),
|
|
20005
|
-
|
|
20006
|
-
hint: ansi.dim(PLUGINS_TEXTS.
|
|
20178
|
+
pluginId: sanitizeForTerminal(pluginId),
|
|
20179
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
20007
20180
|
});
|
|
20008
20181
|
}
|
|
20009
|
-
function unknownExtensionError(id,
|
|
20182
|
+
function unknownExtensionError(id, pluginId, extId, ansi) {
|
|
20010
20183
|
return tx(PLUGINS_TEXTS.qualifiedIdNotFound, {
|
|
20011
20184
|
glyph: ansi.red("\u2715"),
|
|
20012
20185
|
id: sanitizeForTerminal(id),
|
|
20013
|
-
|
|
20186
|
+
pluginId: sanitizeForTerminal(pluginId),
|
|
20014
20187
|
extId: sanitizeForTerminal(extId),
|
|
20015
20188
|
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdNotFoundHint)
|
|
20016
20189
|
});
|
|
@@ -20101,18 +20274,18 @@ function renderPluginDetailFields(match) {
|
|
|
20101
20274
|
function collectPluginExtensionItems(match, ansi) {
|
|
20102
20275
|
const enabled = match.status === "enabled";
|
|
20103
20276
|
if (!enabled || !match.extensions) return [];
|
|
20104
|
-
const
|
|
20277
|
+
const safePluginId = sanitizeForTerminal(match.id);
|
|
20105
20278
|
const sorted = sortExtensionsCanonical(match.extensions);
|
|
20106
20279
|
return sorted.map((ext) => {
|
|
20107
20280
|
const safeExtId = sanitizeForTerminal(ext.id);
|
|
20108
20281
|
return {
|
|
20109
20282
|
// User plugins surfaced via `loadAll` already filter on the
|
|
20110
20283
|
// resolver, so a reachable extension on this surface is enabled
|
|
20111
|
-
// by construction. The disabled path goes through the
|
|
20284
|
+
// by construction. The disabled path goes through the plugin
|
|
20112
20285
|
// status header above (✕ on the row).
|
|
20113
20286
|
glyph: ansi.green(PLUGINS_TEXTS.rowGlyphOk),
|
|
20114
20287
|
kind: sanitizeForTerminal(ext.kind),
|
|
20115
|
-
name: `${
|
|
20288
|
+
name: `${safePluginId}/${safeExtId}`,
|
|
20116
20289
|
version: sanitizeForTerminal(ext.version)
|
|
20117
20290
|
};
|
|
20118
20291
|
});
|
|
@@ -20138,11 +20311,11 @@ function renderExtensionItems(items) {
|
|
|
20138
20311
|
}
|
|
20139
20312
|
return out.join("");
|
|
20140
20313
|
}
|
|
20141
|
-
function renderBuiltInExtensionDetail(
|
|
20314
|
+
function renderBuiltInExtensionDetail(pluginId, ext, ansi) {
|
|
20142
20315
|
const glyph = ext.enabled ? ansi.green(PLUGINS_TEXTS.rowGlyphOk) : ansi.red(PLUGINS_TEXTS.rowGlyphOff);
|
|
20143
20316
|
const header = tx(PLUGINS_TEXTS.detailHeaderExtensionBuiltIn, {
|
|
20144
20317
|
glyph,
|
|
20145
|
-
qualifiedId: sanitizeForTerminal(`${
|
|
20318
|
+
qualifiedId: sanitizeForTerminal(`${pluginId}/${ext.id}`),
|
|
20146
20319
|
source: ansi.dim(PLUGINS_TEXTS.sourceBuiltIn)
|
|
20147
20320
|
});
|
|
20148
20321
|
const meta = { kind: ext.kind };
|
|
@@ -20150,11 +20323,11 @@ function renderBuiltInExtensionDetail(bundleId, ext, ansi) {
|
|
|
20150
20323
|
if (ext.entry !== void 0) meta.entry = ext.entry;
|
|
20151
20324
|
return header + "\n" + renderExtensionFields(meta);
|
|
20152
20325
|
}
|
|
20153
|
-
function renderUserExtensionDetail(
|
|
20326
|
+
function renderUserExtensionDetail(pluginId, ext, ansi) {
|
|
20154
20327
|
const glyph = ansi.green(PLUGINS_TEXTS.rowGlyphOk);
|
|
20155
20328
|
const header = tx(PLUGINS_TEXTS.detailHeaderExtensionUser, {
|
|
20156
20329
|
glyph,
|
|
20157
|
-
qualifiedId: sanitizeForTerminal(`${
|
|
20330
|
+
qualifiedId: sanitizeForTerminal(`${pluginId}/${ext.id}`),
|
|
20158
20331
|
source: ansi.dim(PLUGINS_TEXTS.sourceUser)
|
|
20159
20332
|
});
|
|
20160
20333
|
const meta = readInstanceMeta(ext.instance);
|
|
@@ -20408,13 +20581,13 @@ function forEachProviderInstance(plugins, callback) {
|
|
|
20408
20581
|
forEachUserPluginProvider(plugins, callback);
|
|
20409
20582
|
}
|
|
20410
20583
|
function forEachBuiltInProvider(callback) {
|
|
20411
|
-
for (const
|
|
20412
|
-
for (const ext of
|
|
20584
|
+
for (const plugin of builtInPlugins) {
|
|
20585
|
+
for (const ext of plugin.extensions) {
|
|
20413
20586
|
if (ext.kind !== "provider") continue;
|
|
20414
20587
|
const provider = ext;
|
|
20415
20588
|
callback({
|
|
20416
20589
|
id: provider.id,
|
|
20417
|
-
pluginId:
|
|
20590
|
+
pluginId: plugin.id,
|
|
20418
20591
|
instance: provider
|
|
20419
20592
|
});
|
|
20420
20593
|
}
|
|
@@ -20457,15 +20630,15 @@ function collectApplicableKindWarnings(plugins, knownKinds) {
|
|
|
20457
20630
|
return out;
|
|
20458
20631
|
}
|
|
20459
20632
|
function collectBuiltInApplicableKindWarnings(out, knownKinds) {
|
|
20460
|
-
for (const
|
|
20461
|
-
for (const ext of
|
|
20633
|
+
for (const plugin of builtInPlugins) {
|
|
20634
|
+
for (const ext of plugin.extensions) {
|
|
20462
20635
|
if (ext.kind !== "extractor") continue;
|
|
20463
20636
|
const extractor = ext;
|
|
20464
20637
|
const kinds = extractor.precondition?.kind;
|
|
20465
20638
|
if (!kinds || kinds.length === 0) continue;
|
|
20466
20639
|
appendUnknownKindWarnings(
|
|
20467
20640
|
out,
|
|
20468
|
-
qualifiedExtensionId(
|
|
20641
|
+
qualifiedExtensionId(plugin.id, extractor.id),
|
|
20469
20642
|
kinds,
|
|
20470
20643
|
knownKinds
|
|
20471
20644
|
);
|
|
@@ -20508,11 +20681,11 @@ function collectUnknownSlotWarnings(plugins, knownSlots) {
|
|
|
20508
20681
|
return out;
|
|
20509
20682
|
}
|
|
20510
20683
|
function collectBuiltInUnknownSlotWarnings(out, knownSlots) {
|
|
20511
|
-
for (const
|
|
20512
|
-
for (const ext of
|
|
20684
|
+
for (const plugin of builtInPlugins) {
|
|
20685
|
+
for (const ext of plugin.extensions) {
|
|
20513
20686
|
const vc = ext.viewContributions;
|
|
20514
20687
|
if (!vc) continue;
|
|
20515
|
-
appendUnknownSlotWarnings(out, qualifiedExtensionId(
|
|
20688
|
+
appendUnknownSlotWarnings(out, qualifiedExtensionId(plugin.id, ext.id), vc, knownSlots);
|
|
20516
20689
|
}
|
|
20517
20690
|
}
|
|
20518
20691
|
}
|
|
@@ -20594,7 +20767,7 @@ import { Command as Command25, Option as Option24 } from "clipanion";
|
|
|
20594
20767
|
var TogglePluginsBase = class extends SmCommand {
|
|
20595
20768
|
all = Option24.Boolean("--all", false);
|
|
20596
20769
|
yes = Option24.Boolean("--yes,-y", false, {
|
|
20597
|
-
description: "Skip the interactive confirm when a bare
|
|
20770
|
+
description: "Skip the interactive confirm when a bare plugin id (or --all) fans the toggle out across multiple extensions."
|
|
20598
20771
|
});
|
|
20599
20772
|
ids = Option24.Rest({ name: "ids" });
|
|
20600
20773
|
async toggle(enabled) {
|
|
@@ -20603,7 +20776,7 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20603
20776
|
const argError = this.#validateArgs(stderrAnsi, verb);
|
|
20604
20777
|
if (argError !== null) return argError;
|
|
20605
20778
|
const plugins = await loadAll({ pluginDir: void 0 });
|
|
20606
|
-
const catalogue =
|
|
20779
|
+
const catalogue = pluginCatalogue(plugins);
|
|
20607
20780
|
const targetsResult = this.#pickTargets(catalogue, stderrAnsi);
|
|
20608
20781
|
if (typeof targetsResult === "number") return targetsResult;
|
|
20609
20782
|
let targets = targetsResult;
|
|
@@ -20661,7 +20834,7 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20661
20834
|
if (this.all) {
|
|
20662
20835
|
return catalogue.map((b) => ({
|
|
20663
20836
|
origin: "bare",
|
|
20664
|
-
|
|
20837
|
+
pluginId: b.id,
|
|
20665
20838
|
keys: b.extensionIds.map((extId) => qualifiedExtensionId(b.id, extId))
|
|
20666
20839
|
}));
|
|
20667
20840
|
}
|
|
@@ -20682,8 +20855,8 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20682
20855
|
}
|
|
20683
20856
|
/**
|
|
20684
20857
|
* Macro gate: when the request would fan a single user input out
|
|
20685
|
-
* across more than one extension (either `--all` or a bare
|
|
20686
|
-
* id whose
|
|
20858
|
+
* across more than one extension (either `--all` or a bare plugin
|
|
20859
|
+
* id whose plugin holds ≥2 extensions), confirm the intent.
|
|
20687
20860
|
*
|
|
20688
20861
|
* Resolution order:
|
|
20689
20862
|
* 1. `--yes` flag: skip the prompt entirely.
|
|
@@ -20692,7 +20865,7 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20692
20865
|
* message that names the extensions and points at `--yes`.
|
|
20693
20866
|
*
|
|
20694
20867
|
* Returns `true` when the verb should proceed, `false` when it
|
|
20695
|
-
* should abort. Single-extension targets (bare
|
|
20868
|
+
* should abort. Single-extension targets (bare plugin id mapping to
|
|
20696
20869
|
* one child, or qualified ids) skip the gate uniformly.
|
|
20697
20870
|
*/
|
|
20698
20871
|
// Cyclomatic count comes from the three-stage gate (--yes shortcut,
|
|
@@ -20706,11 +20879,11 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20706
20879
|
if (this.yes) return true;
|
|
20707
20880
|
const isTty = Boolean(this.context.stdin && "isTTY" in this.context.stdin && this.context.stdin.isTTY);
|
|
20708
20881
|
for (const target of macroTargets) {
|
|
20709
|
-
const
|
|
20882
|
+
const pluginLabel = target.origin === "bare" ? target.pluginId ?? "--all" : "--all";
|
|
20710
20883
|
this.printer.info(
|
|
20711
20884
|
tx(PLUGINS_TEXTS.bundleMacroHeader, {
|
|
20712
20885
|
verb,
|
|
20713
|
-
|
|
20886
|
+
pluginId: sanitizeForTerminal(pluginLabel),
|
|
20714
20887
|
count: target.keys.length
|
|
20715
20888
|
})
|
|
20716
20889
|
);
|
|
@@ -20766,7 +20939,7 @@ var TogglePluginsBase = class extends SmCommand {
|
|
|
20766
20939
|
* Persist every qualified id in `config_plugins`. On disable, also
|
|
20767
20940
|
* purge the plugin's `scan_contributions` rows immediately (matches
|
|
20768
20941
|
* the BFF route, see `server/routes/plugins.ts:applyChangeToAdapter`).
|
|
20769
|
-
* Every key is `<
|
|
20942
|
+
* Every key is `<plugin>/<ext>` shape so the contribution purge can
|
|
20770
20943
|
* split into `(pluginId, extensionId)` cleanly.
|
|
20771
20944
|
*/
|
|
20772
20945
|
async #persistKeys(keys, enabled) {
|
|
@@ -20829,11 +21002,11 @@ var PluginsEnableCommand = class extends TogglePluginsBase {
|
|
|
20829
21002
|
flip; sm config reset plugins.<id>.enabled drops the settings.json
|
|
20830
21003
|
baseline.
|
|
20831
21004
|
|
|
20832
|
-
Accepts qualified ids (\`claude/at-directive\`) and bare
|
|
21005
|
+
Accepts qualified ids (\`claude/at-directive\`) and bare plugin
|
|
20833
21006
|
ids (\`claude\`, which fans the toggle out across every extension
|
|
20834
|
-
inside the
|
|
21007
|
+
inside the plugin). Multi-extension plugins need --yes (or an
|
|
20835
21008
|
interactive TTY confirm) to avoid flipping 27 core extensions by
|
|
20836
|
-
accident. Single-extension
|
|
21009
|
+
accident. Single-extension plugins (openai, agent-skills,
|
|
20837
21010
|
antigravity) apply without prompting.
|
|
20838
21011
|
|
|
20839
21012
|
Batches are all-or-nothing: a single unknown id aborts before
|
|
@@ -20856,11 +21029,11 @@ var PluginsDisableCommand = class extends TogglePluginsBase {
|
|
|
20856
21029
|
sm plugins list, but with status=disabled; the kernel will not
|
|
20857
21030
|
run any of its disabled extensions.
|
|
20858
21031
|
|
|
20859
|
-
Accepts qualified ids (\`core/markdown-link\`) and bare
|
|
21032
|
+
Accepts qualified ids (\`core/markdown-link\`) and bare plugin
|
|
20860
21033
|
ids (\`core\`, which fans the toggle out across every extension
|
|
20861
|
-
inside the
|
|
21034
|
+
inside the plugin). Multi-extension plugins need --yes (or an
|
|
20862
21035
|
interactive TTY confirm) to avoid flipping 27 core extensions by
|
|
20863
|
-
accident. Single-extension
|
|
21036
|
+
accident. Single-extension plugins (openai, agent-skills,
|
|
20864
21037
|
antigravity) apply without prompting.
|
|
20865
21038
|
|
|
20866
21039
|
Batches are all-or-nothing: a single unknown id aborts before
|
|
@@ -20872,12 +21045,12 @@ var PluginsDisableCommand = class extends TogglePluginsBase {
|
|
|
20872
21045
|
return this.toggle(false);
|
|
20873
21046
|
}
|
|
20874
21047
|
};
|
|
20875
|
-
function
|
|
21048
|
+
function pluginCatalogue(plugins) {
|
|
20876
21049
|
const out = [];
|
|
20877
|
-
for (const
|
|
21050
|
+
for (const plugin of builtInPlugins) {
|
|
20878
21051
|
out.push({
|
|
20879
|
-
id:
|
|
20880
|
-
extensionIds:
|
|
21052
|
+
id: plugin.id,
|
|
21053
|
+
extensionIds: plugin.extensions.map((e) => e.id)
|
|
20881
21054
|
});
|
|
20882
21055
|
}
|
|
20883
21056
|
for (const p of plugins) {
|
|
@@ -20893,32 +21066,32 @@ function resolveToggleTarget(id, catalogue, ansi) {
|
|
|
20893
21066
|
}
|
|
20894
21067
|
function resolveQualifiedToggle(id, catalogue, ansi) {
|
|
20895
21068
|
const errGlyph = ansi.red("\u2715");
|
|
20896
|
-
const [
|
|
20897
|
-
if (!
|
|
21069
|
+
const [pluginId, extId, ...rest] = id.split("/");
|
|
21070
|
+
if (!pluginId || !extId || rest.length > 0) {
|
|
20898
21071
|
return {
|
|
20899
|
-
error: tx(PLUGINS_TEXTS.
|
|
21072
|
+
error: tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
20900
21073
|
glyph: errGlyph,
|
|
20901
|
-
|
|
20902
|
-
hint: ansi.dim(PLUGINS_TEXTS.
|
|
21074
|
+
pluginId: sanitizeForTerminal(id),
|
|
21075
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
20903
21076
|
})
|
|
20904
21077
|
};
|
|
20905
21078
|
}
|
|
20906
|
-
const
|
|
20907
|
-
if (!
|
|
21079
|
+
const plugin = catalogue.find((b) => b.id === pluginId);
|
|
21080
|
+
if (!plugin) {
|
|
20908
21081
|
return {
|
|
20909
|
-
error: tx(PLUGINS_TEXTS.
|
|
21082
|
+
error: tx(PLUGINS_TEXTS.qualifiedIdUnknownPlugin, {
|
|
20910
21083
|
glyph: errGlyph,
|
|
20911
|
-
|
|
20912
|
-
hint: ansi.dim(PLUGINS_TEXTS.
|
|
21084
|
+
pluginId: sanitizeForTerminal(pluginId),
|
|
21085
|
+
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdUnknownPluginHint)
|
|
20913
21086
|
})
|
|
20914
21087
|
};
|
|
20915
21088
|
}
|
|
20916
|
-
if (!
|
|
21089
|
+
if (!plugin.extensionIds.includes(extId)) {
|
|
20917
21090
|
return {
|
|
20918
21091
|
error: tx(PLUGINS_TEXTS.qualifiedIdNotFound, {
|
|
20919
21092
|
glyph: errGlyph,
|
|
20920
21093
|
id: sanitizeForTerminal(id),
|
|
20921
|
-
|
|
21094
|
+
pluginId: sanitizeForTerminal(pluginId),
|
|
20922
21095
|
extId: sanitizeForTerminal(extId),
|
|
20923
21096
|
hint: ansi.dim(PLUGINS_TEXTS.qualifiedIdNotFoundHint)
|
|
20924
21097
|
})
|
|
@@ -20926,12 +21099,12 @@ function resolveQualifiedToggle(id, catalogue, ansi) {
|
|
|
20926
21099
|
}
|
|
20927
21100
|
return {
|
|
20928
21101
|
origin: "qualified",
|
|
20929
|
-
keys: [qualifiedExtensionId(
|
|
21102
|
+
keys: [qualifiedExtensionId(pluginId, extId)]
|
|
20930
21103
|
};
|
|
20931
21104
|
}
|
|
20932
21105
|
function resolveBareToggle(id, catalogue) {
|
|
20933
|
-
const
|
|
20934
|
-
if (!
|
|
21106
|
+
const plugin = catalogue.find((b) => b.id === id);
|
|
21107
|
+
if (!plugin) {
|
|
20935
21108
|
return {
|
|
20936
21109
|
error: tx(PLUGINS_TEXTS.pluginNotFound, {
|
|
20937
21110
|
glyph: "\u2715",
|
|
@@ -20942,8 +21115,8 @@ function resolveBareToggle(id, catalogue) {
|
|
|
20942
21115
|
}
|
|
20943
21116
|
return {
|
|
20944
21117
|
origin: "bare",
|
|
20945
|
-
|
|
20946
|
-
keys:
|
|
21118
|
+
pluginId: plugin.id,
|
|
21119
|
+
keys: plugin.extensionIds.map((extId) => qualifiedExtensionId(plugin.id, extId))
|
|
20947
21120
|
};
|
|
20948
21121
|
}
|
|
20949
21122
|
|
|
@@ -20991,20 +21164,10 @@ var PluginsCreateCommand = class extends SmCommand {
|
|
|
20991
21164
|
mkdirSync5(join18(targetDir, "extractors", extractorName), { recursive: true });
|
|
20992
21165
|
const specVersion = installedSpecVersion();
|
|
20993
21166
|
const manifest = {
|
|
20994
|
-
id: this.pluginId,
|
|
20995
21167
|
version: "0.1.0",
|
|
20996
21168
|
specCompat: `^${specVersion}`,
|
|
20997
21169
|
catalogCompat: "^1.0.0",
|
|
20998
|
-
description: "Generated by `sm plugins create`. Edit to taste."
|
|
20999
|
-
settings: {
|
|
21000
|
-
keywords: {
|
|
21001
|
-
type: "string-list",
|
|
21002
|
-
label: "Keywords to track",
|
|
21003
|
-
description: "Words counted across each scanned node body.",
|
|
21004
|
-
default: ["TODO", "FIXME"],
|
|
21005
|
-
min: 1
|
|
21006
|
-
}
|
|
21007
|
-
}
|
|
21170
|
+
description: "Generated by `sm plugins create`. Edit to taste."
|
|
21008
21171
|
};
|
|
21009
21172
|
writeFileSync(
|
|
21010
21173
|
join18(targetDir, "plugin.json"),
|
|
@@ -21029,36 +21192,44 @@ function scaffolderExtractorStub(extractorId) {
|
|
|
21029
21192
|
* Generated by \`sm plugins create\`. Edit the extract() body.
|
|
21030
21193
|
*
|
|
21031
21194
|
* Loader contract: the plugin loader resolves the extension via the
|
|
21032
|
-
* MODULE'S DEFAULT EXPORT (\`export default { ... }\`).
|
|
21033
|
-
* splitting into a named export
|
|
21034
|
-
*
|
|
21195
|
+
* MODULE'S DEFAULT EXPORT (\`export default { ... }\`). It must be an
|
|
21196
|
+
* object literal; renaming or splitting into a named export surfaces as
|
|
21197
|
+
* a \`load-error\`.
|
|
21035
21198
|
*
|
|
21036
21199
|
* Folder convention: this file lives at
|
|
21037
|
-
* \`extractors/${extractorId}/index.js\`. The
|
|
21038
|
-
*
|
|
21039
|
-
*
|
|
21200
|
+
* \`extractors/${extractorId}/index.js\`. The folder layout is the
|
|
21201
|
+
* source of truth (structure-as-truth): the loader derives \`kind\`
|
|
21202
|
+
* (\`extractor\`) from the parent folder and the id (\`${extractorId}\`)
|
|
21203
|
+
* from the leaf folder, and injects \`pluginId\` from the plugin, so none
|
|
21204
|
+
* of them are declared here. Re-declaring \`kind\` / \`id\` is rejected as
|
|
21205
|
+
* \`invalid-manifest\`.
|
|
21040
21206
|
*
|
|
21041
|
-
* Declared view contributions (
|
|
21207
|
+
* Declared view contributions (\`ui\`):
|
|
21042
21208
|
* - 'count' \u2192 slot \`card.footer.left\` (renders as a chip
|
|
21043
21209
|
* in the left footer of the node card)
|
|
21044
21210
|
*
|
|
21045
|
-
* Declared settings:
|
|
21211
|
+
* Declared settings (\`settings\`):
|
|
21046
21212
|
* - 'keywords' (string-list) \u2192 exposed as ctx.settings.keywords
|
|
21047
21213
|
*
|
|
21048
21214
|
* See: spec/plugin-author-guide.md \xA7View contributions
|
|
21049
21215
|
* spec/view-slots.md
|
|
21050
21216
|
*/
|
|
21051
21217
|
export default {
|
|
21052
|
-
id: '${extractorId}',
|
|
21053
|
-
kind: 'extractor',
|
|
21054
21218
|
version: '0.1.0',
|
|
21055
21219
|
description: 'Counts configured keywords per node.',
|
|
21056
|
-
stability: 'experimental',
|
|
21057
|
-
emitsLinkKinds: [],
|
|
21058
|
-
defaultConfidence: 'high',
|
|
21059
21220
|
scope: 'body',
|
|
21060
21221
|
|
|
21061
|
-
|
|
21222
|
+
settings: {
|
|
21223
|
+
keywords: {
|
|
21224
|
+
type: 'string-list',
|
|
21225
|
+
label: 'Keywords to track',
|
|
21226
|
+
description: 'Words counted across each scanned node body.',
|
|
21227
|
+
default: ['TODO', 'FIXME'],
|
|
21228
|
+
min: 1,
|
|
21229
|
+
},
|
|
21230
|
+
},
|
|
21231
|
+
|
|
21232
|
+
ui: {
|
|
21062
21233
|
count: {
|
|
21063
21234
|
slot: 'card.footer.left',
|
|
21064
21235
|
icon: '\u{1F50D}',
|
|
@@ -21084,7 +21255,7 @@ export default {
|
|
|
21084
21255
|
function scaffolderReadme(pluginId) {
|
|
21085
21256
|
return `# ${pluginId}
|
|
21086
21257
|
|
|
21087
|
-
Generated by \`sm plugins create\`. Edit \`
|
|
21258
|
+
Generated by \`sm plugins create\`. Edit \`extractors/${pluginId}-extractor/index.js\` to taste.
|
|
21088
21259
|
|
|
21089
21260
|
## Verbs
|
|
21090
21261
|
|
|
@@ -21604,6 +21775,31 @@ var IntentionalFailCommand = class extends SmCommand {
|
|
|
21604
21775
|
// cli/commands/scan.ts
|
|
21605
21776
|
import { Command as Command31, Option as Option29 } from "clipanion";
|
|
21606
21777
|
|
|
21778
|
+
// kernel/util/format-bytes.ts
|
|
21779
|
+
var UNITS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"];
|
|
21780
|
+
function formatBytes(bytes) {
|
|
21781
|
+
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
21782
|
+
if (bytes < 1024) return `${Math.round(bytes)} B`;
|
|
21783
|
+
let value = bytes;
|
|
21784
|
+
let unitIndex = 0;
|
|
21785
|
+
while (value >= 1024 && unitIndex < UNITS.length - 1) {
|
|
21786
|
+
value /= 1024;
|
|
21787
|
+
unitIndex += 1;
|
|
21788
|
+
}
|
|
21789
|
+
const rounded = Math.round(value * 10) / 10;
|
|
21790
|
+
const text = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
|
|
21791
|
+
return `${text} ${UNITS[unitIndex]}`;
|
|
21792
|
+
}
|
|
21793
|
+
|
|
21794
|
+
// kernel/util/format-oversized.ts
|
|
21795
|
+
function formatOversizedFilePair(file) {
|
|
21796
|
+
return `${file.path} (${formatBytes(file.bytes)})`;
|
|
21797
|
+
}
|
|
21798
|
+
function formatOversizedFileRows(files) {
|
|
21799
|
+
return files.map((file) => ` - ${formatOversizedFilePair(file)}
|
|
21800
|
+
`);
|
|
21801
|
+
}
|
|
21802
|
+
|
|
21607
21803
|
// cli/i18n/scan.texts.ts
|
|
21608
21804
|
var SCAN_TEXTS = {
|
|
21609
21805
|
// --- scan command ----------------------------------------------------
|
|
@@ -21651,6 +21847,20 @@ var SCAN_TEXTS = {
|
|
|
21651
21847
|
*/
|
|
21652
21848
|
scanCappedNotice: "{{glyph}} Scan capped at {{limit}} nodes ({{source}}).\n {{hint}}\n",
|
|
21653
21849
|
scanCappedNoticeHint: "Trim .skillmapignore to exclude noisy paths (preferred), or re-run with --max-nodes <N> to raise the cap. Past the recommended limit the graph is hard to read and analyzer signal drops.",
|
|
21850
|
+
/**
|
|
21851
|
+
* File-size skip notice, printed (WARN, stderr) when the walker
|
|
21852
|
+
* skipped one or more files for exceeding `scan.maxFileSizeBytes`.
|
|
21853
|
+
* `{{glyph}}` is the yellow warning glyph, `{{count}}`/`{{noun}}` the
|
|
21854
|
+
* skipped-file tally, `{{files}}` the pre-rendered list of
|
|
21855
|
+
* `path (size)` rows, `{{hint}}` the dim escape-route line.
|
|
21856
|
+
*/
|
|
21857
|
+
scanSkippedFilesNotice: "{{glyph}} Skipped {{count}} {{noun}} over the size limit (scan.maxFileSizeBytes):\n{{files}} {{hint}}\n",
|
|
21858
|
+
// The per-file ` - path (size)\n` rows that fill `{{files}}` are
|
|
21859
|
+
// rendered by `kernel/util/format-oversized.ts:formatOversizedFileRows`,
|
|
21860
|
+
// shared with `sm watch` / `sm serve` so the three surfaces never drift.
|
|
21861
|
+
scanSkippedFileNounSingular: "file",
|
|
21862
|
+
scanSkippedFileNounPlural: "files",
|
|
21863
|
+
scanSkippedFilesNoticeHint: "Raise scan.maxFileSizeBytes to include these, or add them to .skillmapignore to skip them on purpose.",
|
|
21654
21864
|
/**
|
|
21655
21865
|
* Validation message for an invalid `--max-nodes` value. Surfaced as a
|
|
21656
21866
|
* §3.1b two-line block.
|
|
@@ -21829,7 +22039,8 @@ function createWatcherRuntime(opts) {
|
|
|
21829
22039
|
strict,
|
|
21830
22040
|
emitter,
|
|
21831
22041
|
recommendedNodeLimit: cfg.scan.maxNodes,
|
|
21832
|
-
overrideMaxNodes: opts.maxNodesOverride ?? null
|
|
22042
|
+
overrideMaxNodes: opts.maxNodesOverride ?? null,
|
|
22043
|
+
maxFileSizeBytes: cfg.scan.maxFileSizeBytes
|
|
21833
22044
|
};
|
|
21834
22045
|
if (cfg.scan.referencePaths.length > 0) {
|
|
21835
22046
|
const walk3 = walkReferencePaths(cfg.scan.referencePaths, cwd);
|
|
@@ -22047,7 +22258,20 @@ var WATCH_TEXTS = {
|
|
|
22047
22258
|
* §3.1b two-line block. Validation rejection for `--max-nodes`.
|
|
22048
22259
|
*/
|
|
22049
22260
|
maxNodesInvalid: "{{glyph}} sm watch: --max-nodes must be an integer >= 1 (got {{raw}}).\n {{hint}}\n",
|
|
22050
|
-
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256."
|
|
22261
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256.",
|
|
22262
|
+
/**
|
|
22263
|
+
* File-size skip WARN, emitted per batch (stderr) when the walker
|
|
22264
|
+
* skipped one or more files for exceeding `scan.maxFileSizeBytes`.
|
|
22265
|
+
* Mirrors `sm scan`'s notice. `{{files}}` is the pre-rendered list of
|
|
22266
|
+
* `path (size)` rows.
|
|
22267
|
+
*/
|
|
22268
|
+
skippedFilesNotice: "{{glyph}} Skipped {{count}} {{noun}} over the size limit (scan.maxFileSizeBytes):\n{{files}} {{hint}}\n",
|
|
22269
|
+
// The per-file ` - path (size)\n` rows that fill `{{files}}` are
|
|
22270
|
+
// rendered by `kernel/util/format-oversized.ts:formatOversizedFileRows`,
|
|
22271
|
+
// shared with `sm scan` / `sm serve` so the three surfaces never drift.
|
|
22272
|
+
skippedFileNounSingular: "file",
|
|
22273
|
+
skippedFileNounPlural: "files",
|
|
22274
|
+
skippedFilesNoticeHint: "Raise scan.maxFileSizeBytes to include these, or add them to .skillmapignore to skip them on purpose."
|
|
22051
22275
|
};
|
|
22052
22276
|
|
|
22053
22277
|
// cli/commands/watch.ts
|
|
@@ -22088,6 +22312,21 @@ async function runWatchLoop(opts) {
|
|
|
22088
22312
|
})
|
|
22089
22313
|
);
|
|
22090
22314
|
}
|
|
22315
|
+
renderOversizedWarning(result);
|
|
22316
|
+
};
|
|
22317
|
+
const renderOversizedWarning = (result) => {
|
|
22318
|
+
const oversized = result.oversizedFiles ?? [];
|
|
22319
|
+
if ((result.stats.filesOversized ?? oversized.length) <= 0) return;
|
|
22320
|
+
const files = formatOversizedFileRows(oversized).join("");
|
|
22321
|
+
context.stderr.write(
|
|
22322
|
+
tx(WATCH_TEXTS.skippedFilesNotice, {
|
|
22323
|
+
glyph: stderrAnsi.yellow("\u26A0"),
|
|
22324
|
+
count: oversized.length,
|
|
22325
|
+
noun: oversized.length === 1 ? WATCH_TEXTS.skippedFileNounSingular : WATCH_TEXTS.skippedFileNounPlural,
|
|
22326
|
+
files,
|
|
22327
|
+
hint: stderrAnsi.dim(WATCH_TEXTS.skippedFilesNoticeHint)
|
|
22328
|
+
})
|
|
22329
|
+
);
|
|
22091
22330
|
};
|
|
22092
22331
|
const runtimeOpts = {
|
|
22093
22332
|
dbPath,
|
|
@@ -22414,7 +22653,13 @@ var ScanCommand = class extends SmCommand {
|
|
|
22414
22653
|
});
|
|
22415
22654
|
if (outcome.kind === "ok") {
|
|
22416
22655
|
setScanExtensions(buildScanExtensionSet(outcome.executedExtensionIds));
|
|
22417
|
-
return this.renderOutcome(
|
|
22656
|
+
return this.renderOutcome(
|
|
22657
|
+
outcome.result,
|
|
22658
|
+
outcome.persistedTo,
|
|
22659
|
+
outcome.dbPath,
|
|
22660
|
+
outcome.strict,
|
|
22661
|
+
outcome.lensAutoDetected
|
|
22662
|
+
);
|
|
22418
22663
|
}
|
|
22419
22664
|
return this.renderFailure(outcome);
|
|
22420
22665
|
}
|
|
@@ -22523,12 +22768,13 @@ var ScanCommand = class extends SmCommand {
|
|
|
22523
22768
|
* the exit code. Exit 1 only when at least one issue is at `error`
|
|
22524
22769
|
* severity (mirrors `sm check`, per spec § Exit codes).
|
|
22525
22770
|
*/
|
|
22526
|
-
renderOutcome(result, persistedTo, dbPath, strict) {
|
|
22771
|
+
renderOutcome(result, persistedTo, dbPath, strict, lensAutoDetected) {
|
|
22527
22772
|
const exitCode2 = result.issues.some((i) => i.severity === "error") ? ExitCode.Issues : ExitCode.Ok;
|
|
22528
22773
|
if (this.json) {
|
|
22529
22774
|
return this.#renderJsonOutcome(result, exitCode2, strict);
|
|
22530
22775
|
}
|
|
22531
22776
|
const ansi = this.ansiFor("stdout");
|
|
22777
|
+
this.#announceAutoDetectedLens(lensAutoDetected);
|
|
22532
22778
|
const cwd = defaultRuntimeContext().cwd;
|
|
22533
22779
|
const hasErrors = exitCode2 === ExitCode.Issues;
|
|
22534
22780
|
const severityCounts = countBySeverity(result.issues);
|
|
@@ -22558,8 +22804,32 @@ var ScanCommand = class extends SmCommand {
|
|
|
22558
22804
|
);
|
|
22559
22805
|
}
|
|
22560
22806
|
this.maybePrintCapNotice(result, ansi);
|
|
22807
|
+
this.maybePrintSkippedFilesNotice(result, ansi);
|
|
22561
22808
|
return exitCode2;
|
|
22562
22809
|
}
|
|
22810
|
+
/**
|
|
22811
|
+
* Surface a WARN when the walker skipped one or more files for
|
|
22812
|
+
* exceeding `scan.maxFileSizeBytes`. Lists every skipped file as
|
|
22813
|
+
* `path (humanSize)` and points the user at the two levers
|
|
22814
|
+
* (`scan.maxFileSizeBytes` to raise the limit, `.skillmapignore` to
|
|
22815
|
+
* exclude the path). Routed through `printer.warn` (stderr) because a
|
|
22816
|
+
* silently dropped file is degraded state the operator should read,
|
|
22817
|
+
* not a mid-flight progress line.
|
|
22818
|
+
*/
|
|
22819
|
+
maybePrintSkippedFilesNotice(result, ansi) {
|
|
22820
|
+
const oversized = result.oversizedFiles ?? [];
|
|
22821
|
+
if ((result.stats.filesOversized ?? oversized.length) <= 0) return;
|
|
22822
|
+
const lines = formatOversizedFileRows(oversized).join("");
|
|
22823
|
+
this.printer.warn(
|
|
22824
|
+
tx(SCAN_TEXTS.scanSkippedFilesNotice, {
|
|
22825
|
+
glyph: ansi.yellow("\u26A0"),
|
|
22826
|
+
count: String(oversized.length),
|
|
22827
|
+
noun: oversized.length === 1 ? SCAN_TEXTS.scanSkippedFileNounSingular : SCAN_TEXTS.scanSkippedFileNounPlural,
|
|
22828
|
+
files: lines,
|
|
22829
|
+
hint: ansi.dim(SCAN_TEXTS.scanSkippedFilesNoticeHint)
|
|
22830
|
+
})
|
|
22831
|
+
);
|
|
22832
|
+
}
|
|
22563
22833
|
/**
|
|
22564
22834
|
* Surface the §Node cap notice when the walker actually stopped
|
|
22565
22835
|
* accepting files because of the cap. Derivation: `filesWalked >
|
|
@@ -22583,6 +22853,21 @@ var ScanCommand = class extends SmCommand {
|
|
|
22583
22853
|
})
|
|
22584
22854
|
);
|
|
22585
22855
|
}
|
|
22856
|
+
/**
|
|
22857
|
+
* Print the lens auto-detect line on stdout (the SAME stream as the
|
|
22858
|
+
* scan summary) so the two never interleave on a tty. The bootstrap
|
|
22859
|
+
* deliberately no longer prints this to stderr; the runner threads
|
|
22860
|
+
* `lensAutoDetected` through so the CLI announces it here, in order,
|
|
22861
|
+
* right before the summary. The text ends in a newline, so the
|
|
22862
|
+
* summary lands cleanly on its own line. No-op when the lens came
|
|
22863
|
+
* from config or no marker matched (`null` / `undefined`).
|
|
22864
|
+
*/
|
|
22865
|
+
#announceAutoDetectedLens(lensAutoDetected) {
|
|
22866
|
+
if (!lensAutoDetected) return;
|
|
22867
|
+
this.printer.data(
|
|
22868
|
+
tx(SCAN_RUNNER_TEXTS.activeProviderAutodetected, { id: lensAutoDetected })
|
|
22869
|
+
);
|
|
22870
|
+
}
|
|
22586
22871
|
/**
|
|
22587
22872
|
* `--json` output path. Under `--strict` (H4) self-validates the
|
|
22588
22873
|
* ScanResult against `scan-result.schema.json` before emitting it,
|
|
@@ -23055,6 +23340,12 @@ var SERVER_TEXTS = {
|
|
|
23055
23340
|
// watcher loop continues, a transient FS error must not kill the
|
|
23056
23341
|
// broadcaster.
|
|
23057
23342
|
watcherBatchFailed: "skill-map server: watcher batch failed ({{message}}).\n",
|
|
23343
|
+
// Logged on the server pane when a scan batch (initial or follow-up)
|
|
23344
|
+
// skipped one or more files for exceeding `scan.maxFileSizeBytes`.
|
|
23345
|
+
// `{{files}}` is the comma-separated `path (size)` list. The SPA
|
|
23346
|
+
// raises its own banner from the persisted `oversizedFiles`, so this
|
|
23347
|
+
// is log-only (no WS advisory).
|
|
23348
|
+
watcherFilesOversized: "skill-map server: skipped {{count}} file(s) over the size limit (scan.maxFileSizeBytes): {{files}}. Raise the limit or add them to .skillmapignore.\n",
|
|
23058
23349
|
// Logged once when the pre-1.0 schema-drift check rebuilt the DB on
|
|
23059
23350
|
// watcher boot (the on-disk cache was written by a different
|
|
23060
23351
|
// major.minor). The scan that follows repopulates it; .sm sidecars
|
|
@@ -23140,19 +23431,19 @@ var SERVER_TEXTS = {
|
|
|
23140
23431
|
// 400, cascade route rejects qualified ids: the bare-id PATCH is the
|
|
23141
23432
|
// bundle macro endpoint. Anything containing `/` needs the dedicated
|
|
23142
23433
|
// per-extension route below.
|
|
23143
|
-
pluginsCascadeRouteQualifiedRejected: 'Plugin id "{{id}}" contains "/"; toggle individual extensions via PATCH /api/plugins/<
|
|
23434
|
+
pluginsCascadeRouteQualifiedRejected: 'Plugin id "{{id}}" contains "/"; toggle individual extensions via PATCH /api/plugins/<plugin>/extensions/<extensionId>.',
|
|
23144
23435
|
// 404, unknown plugin / extension.
|
|
23145
23436
|
pluginsUnknown: 'No plugin with id "{{id}}".',
|
|
23146
|
-
pluginsExtensionUnknown: 'Plugin "{{
|
|
23437
|
+
pluginsExtensionUnknown: 'Plugin "{{pluginId}}" has no extension named "{{extensionId}}".',
|
|
23147
23438
|
// 500, DB missing on a write path. Read paths degrade to empty
|
|
23148
23439
|
// shapes, but mutations cannot persist without a DB so they fail fast.
|
|
23149
23440
|
pluginsDbMissing: "Cannot persist plugin override: project DB not found at {{path}}. Run `sm scan` first or pass --db <path>.",
|
|
23150
23441
|
// 403, host-enforced lock from `src/server/locked-plugins.ts`. The
|
|
23151
|
-
//
|
|
23442
|
+
// plugin (or qualified extension) is in the hardcoded lock-list and
|
|
23152
23443
|
// its enabled state is fixed; the UI mirrors the same rule by
|
|
23153
23444
|
// disabling the toggle.
|
|
23154
23445
|
pluginsLocked: 'Plugin "{{id}}" is locked by the host and cannot be toggled.',
|
|
23155
|
-
pluginsExtensionLocked: 'Extension "{{
|
|
23446
|
+
pluginsExtensionLocked: 'Extension "{{pluginId}}/{{extensionId}}" is locked by the host and cannot be toggled.',
|
|
23156
23447
|
// 400 envelopes specific to the bulk `PATCH /api/plugins` endpoint.
|
|
23157
23448
|
// The single-id variants above still apply for per-entry validation
|
|
23158
23449
|
// (unknown id, granularity mismatch, lock); these cover the
|
|
@@ -24219,28 +24510,28 @@ function registerPluginsRoute(app, deps) {
|
|
|
24219
24510
|
});
|
|
24220
24511
|
}
|
|
24221
24512
|
const body = await parsePatchBody(c.req.raw);
|
|
24222
|
-
const childIds =
|
|
24513
|
+
const childIds = pluginExtensionIds(handle).map((extId) => qualifiedExtensionId(id, extId));
|
|
24223
24514
|
const writable = childIds.filter((q) => !isPluginLocked(q));
|
|
24224
24515
|
return await persistManyAndProject(c, deps, writable, body.enabled);
|
|
24225
24516
|
});
|
|
24226
|
-
app.patch("/api/plugins/:
|
|
24227
|
-
const
|
|
24517
|
+
app.patch("/api/plugins/:pluginId/extensions/:extensionId", async (c) => {
|
|
24518
|
+
const pluginId = c.req.param("pluginId");
|
|
24228
24519
|
const extensionId = c.req.param("extensionId");
|
|
24229
|
-
const handle = findHandle(
|
|
24520
|
+
const handle = findHandle(pluginId, deps);
|
|
24230
24521
|
if (!handle) {
|
|
24231
24522
|
throw new HTTPException9(404, {
|
|
24232
|
-
message: tx(SERVER_TEXTS.pluginsUnknown, { id:
|
|
24523
|
+
message: tx(SERVER_TEXTS.pluginsUnknown, { id: pluginId })
|
|
24233
24524
|
});
|
|
24234
24525
|
}
|
|
24235
24526
|
if (!hasExtension(handle, extensionId)) {
|
|
24236
24527
|
throw new HTTPException9(404, {
|
|
24237
|
-
message: tx(SERVER_TEXTS.pluginsExtensionUnknown, {
|
|
24528
|
+
message: tx(SERVER_TEXTS.pluginsExtensionUnknown, { pluginId, extensionId })
|
|
24238
24529
|
});
|
|
24239
24530
|
}
|
|
24240
|
-
const qualified = qualifiedExtensionId(
|
|
24241
|
-
if (isPluginLocked(qualified) || isPluginLocked(
|
|
24531
|
+
const qualified = qualifiedExtensionId(pluginId, extensionId);
|
|
24532
|
+
if (isPluginLocked(qualified) || isPluginLocked(pluginId)) {
|
|
24242
24533
|
throw new HTTPException9(403, {
|
|
24243
|
-
message: tx(SERVER_TEXTS.pluginsExtensionLocked, {
|
|
24534
|
+
message: tx(SERVER_TEXTS.pluginsExtensionLocked, { pluginId, extensionId })
|
|
24244
24535
|
});
|
|
24245
24536
|
}
|
|
24246
24537
|
const body = await parsePatchBody(c.req.raw);
|
|
@@ -24269,11 +24560,11 @@ function listItems(deps, resolveEnabled) {
|
|
|
24269
24560
|
];
|
|
24270
24561
|
}
|
|
24271
24562
|
function buildBuiltInItems(resolveEnabled) {
|
|
24272
|
-
return
|
|
24273
|
-
const
|
|
24274
|
-
const extensions =
|
|
24275
|
-
const qualified = qualifiedExtensionId(
|
|
24276
|
-
const extLocked =
|
|
24563
|
+
return sortPluginsForPresentation(builtInPlugins).map((plugin) => {
|
|
24564
|
+
const pluginLocked = isPluginLocked(plugin.id);
|
|
24565
|
+
const extensions = plugin.extensions.map((ext) => {
|
|
24566
|
+
const qualified = qualifiedExtensionId(plugin.id, ext.id);
|
|
24567
|
+
const extLocked = pluginLocked || isPluginLocked(qualified);
|
|
24277
24568
|
return {
|
|
24278
24569
|
id: ext.id,
|
|
24279
24570
|
kind: ext.kind,
|
|
@@ -24283,17 +24574,17 @@ function buildBuiltInItems(resolveEnabled) {
|
|
|
24283
24574
|
...extLocked ? { locked: true } : {}
|
|
24284
24575
|
};
|
|
24285
24576
|
});
|
|
24286
|
-
const
|
|
24577
|
+
const pluginEnabled = extensions.some((e) => e.enabled);
|
|
24287
24578
|
return {
|
|
24288
|
-
id:
|
|
24289
|
-
version: firstVersion(
|
|
24290
|
-
kinds: uniqueKinds(
|
|
24291
|
-
status:
|
|
24579
|
+
id: plugin.id,
|
|
24580
|
+
version: firstVersion(plugin.extensions),
|
|
24581
|
+
kinds: uniqueKinds(plugin.extensions.map((e) => e.kind)),
|
|
24582
|
+
status: pluginEnabled ? "enabled" : "disabled",
|
|
24292
24583
|
reason: null,
|
|
24293
24584
|
source: "built-in",
|
|
24294
|
-
description:
|
|
24585
|
+
description: plugin.description,
|
|
24295
24586
|
...extensions.length > 0 ? { extensions } : {},
|
|
24296
|
-
...
|
|
24587
|
+
...pluginLocked ? { locked: true } : {}
|
|
24297
24588
|
};
|
|
24298
24589
|
});
|
|
24299
24590
|
}
|
|
@@ -24301,8 +24592,8 @@ function buildDiscoveredItems(discovered, deps, resolveEnabled) {
|
|
|
24301
24592
|
return discovered.map((plugin) => buildDiscoveredItem(plugin, deps, resolveEnabled));
|
|
24302
24593
|
}
|
|
24303
24594
|
function buildDiscoveredItem(plugin, deps, resolveEnabled) {
|
|
24304
|
-
const
|
|
24305
|
-
const extensions = projectExtensionRows(plugin, resolveEnabled,
|
|
24595
|
+
const pluginLocked = isPluginLocked(plugin.id);
|
|
24596
|
+
const extensions = projectExtensionRows(plugin, resolveEnabled, pluginLocked);
|
|
24306
24597
|
const optional = optionalDiscoveredFields(plugin, extensions);
|
|
24307
24598
|
return {
|
|
24308
24599
|
id: plugin.id,
|
|
@@ -24312,7 +24603,7 @@ function buildDiscoveredItem(plugin, deps, resolveEnabled) {
|
|
|
24312
24603
|
reason: plugin.reason ?? null,
|
|
24313
24604
|
source: classifyPluginSource(plugin.path, deps),
|
|
24314
24605
|
...optional,
|
|
24315
|
-
...
|
|
24606
|
+
...pluginLocked ? { locked: true } : {},
|
|
24316
24607
|
...plugin.status === "disabled" ? { startsAsDisabled: true } : {}
|
|
24317
24608
|
};
|
|
24318
24609
|
}
|
|
@@ -24323,12 +24614,12 @@ function optionalDiscoveredFields(plugin, extensions) {
|
|
|
24323
24614
|
if (extensions) out.extensions = extensions;
|
|
24324
24615
|
return out;
|
|
24325
24616
|
}
|
|
24326
|
-
function projectExtensionRows(plugin, resolveEnabled,
|
|
24617
|
+
function projectExtensionRows(plugin, resolveEnabled, pluginLocked) {
|
|
24327
24618
|
if (!plugin.extensions || plugin.extensions.length === 0) return void 0;
|
|
24328
24619
|
return plugin.extensions.map((ext) => {
|
|
24329
24620
|
const description = readInstanceDescription(ext.instance);
|
|
24330
24621
|
const qualified = qualifiedExtensionId(plugin.id, ext.id);
|
|
24331
|
-
const extLocked =
|
|
24622
|
+
const extLocked = pluginLocked || isPluginLocked(qualified);
|
|
24332
24623
|
return {
|
|
24333
24624
|
id: ext.id,
|
|
24334
24625
|
kind: ext.kind,
|
|
@@ -24437,28 +24728,28 @@ function validateBulkChange(change, deps) {
|
|
|
24437
24728
|
}
|
|
24438
24729
|
return null;
|
|
24439
24730
|
}
|
|
24440
|
-
const
|
|
24731
|
+
const pluginId = change.id.slice(0, slash);
|
|
24441
24732
|
const extensionId = change.id.slice(slash + 1);
|
|
24442
|
-
const handle = findHandle(
|
|
24733
|
+
const handle = findHandle(pluginId, deps);
|
|
24443
24734
|
if (!handle) {
|
|
24444
24735
|
return {
|
|
24445
24736
|
status: 404,
|
|
24446
24737
|
code: "not-found",
|
|
24447
|
-
message: tx(SERVER_TEXTS.pluginsUnknown, { id:
|
|
24738
|
+
message: tx(SERVER_TEXTS.pluginsUnknown, { id: pluginId })
|
|
24448
24739
|
};
|
|
24449
24740
|
}
|
|
24450
24741
|
if (!hasExtension(handle, extensionId)) {
|
|
24451
24742
|
return {
|
|
24452
24743
|
status: 404,
|
|
24453
24744
|
code: "not-found",
|
|
24454
|
-
message: tx(SERVER_TEXTS.pluginsExtensionUnknown, {
|
|
24745
|
+
message: tx(SERVER_TEXTS.pluginsExtensionUnknown, { pluginId, extensionId })
|
|
24455
24746
|
};
|
|
24456
24747
|
}
|
|
24457
|
-
if (isPluginLocked(change.id) || isPluginLocked(
|
|
24748
|
+
if (isPluginLocked(change.id) || isPluginLocked(pluginId)) {
|
|
24458
24749
|
return {
|
|
24459
24750
|
status: 403,
|
|
24460
24751
|
code: "locked",
|
|
24461
|
-
message: tx(SERVER_TEXTS.pluginsExtensionLocked, {
|
|
24752
|
+
message: tx(SERVER_TEXTS.pluginsExtensionLocked, { pluginId, extensionId })
|
|
24462
24753
|
};
|
|
24463
24754
|
}
|
|
24464
24755
|
return null;
|
|
@@ -24482,7 +24773,7 @@ function expandBulkChangeKeys(change, deps) {
|
|
|
24482
24773
|
if (change.id.includes("/")) return [change.id];
|
|
24483
24774
|
const handle = findHandle(change.id, deps);
|
|
24484
24775
|
if (!handle) return [];
|
|
24485
|
-
return
|
|
24776
|
+
return pluginExtensionIds(handle).map((extId) => qualifiedExtensionId(change.id, extId)).filter((q) => !isPluginLocked(q));
|
|
24486
24777
|
}
|
|
24487
24778
|
async function buildFreshResolver2(deps) {
|
|
24488
24779
|
return buildFreshResolver({
|
|
@@ -24495,21 +24786,21 @@ function composeResolver2(deps, overrides) {
|
|
|
24495
24786
|
return composeResolver(deps.configService.effective(), overrides);
|
|
24496
24787
|
}
|
|
24497
24788
|
function findHandle(id, deps) {
|
|
24498
|
-
const builtIn =
|
|
24499
|
-
if (builtIn) return { kind: "built-in",
|
|
24789
|
+
const builtIn = builtInPlugins.find((b) => b.id === id);
|
|
24790
|
+
if (builtIn) return { kind: "built-in", plugin: builtIn };
|
|
24500
24791
|
const discovered = deps.pluginRuntime.discovered.find((p) => p.id === id);
|
|
24501
24792
|
if (discovered) return { kind: "discovered", plugin: discovered };
|
|
24502
24793
|
return null;
|
|
24503
24794
|
}
|
|
24504
|
-
function
|
|
24795
|
+
function pluginExtensionIds(handle) {
|
|
24505
24796
|
if (handle.kind === "built-in") {
|
|
24506
|
-
return handle.
|
|
24797
|
+
return handle.plugin.extensions.map((e) => e.id);
|
|
24507
24798
|
}
|
|
24508
24799
|
return (handle.plugin.extensions ?? []).map((e) => e.id);
|
|
24509
24800
|
}
|
|
24510
24801
|
function hasExtension(handle, extensionId) {
|
|
24511
24802
|
if (handle.kind === "built-in") {
|
|
24512
|
-
return handle.
|
|
24803
|
+
return handle.plugin.extensions.some((e) => e.id === extensionId);
|
|
24513
24804
|
}
|
|
24514
24805
|
return (handle.plugin.extensions ?? []).some((e) => e.id === extensionId);
|
|
24515
24806
|
}
|
|
@@ -25116,7 +25407,9 @@ function createWatcherService(opts) {
|
|
|
25116
25407
|
message: sanitizeForTerminal(outcome.message)
|
|
25117
25408
|
})
|
|
25118
25409
|
);
|
|
25410
|
+
return;
|
|
25119
25411
|
}
|
|
25412
|
+
warnOversizedFiles(outcome.result);
|
|
25120
25413
|
},
|
|
25121
25414
|
onWatcherError: (message) => {
|
|
25122
25415
|
log.warn(
|
|
@@ -25179,6 +25472,17 @@ function createWatcherService(opts) {
|
|
|
25179
25472
|
}
|
|
25180
25473
|
};
|
|
25181
25474
|
}
|
|
25475
|
+
function warnOversizedFiles(result) {
|
|
25476
|
+
const oversized = result.oversizedFiles ?? [];
|
|
25477
|
+
if ((result.stats.filesOversized ?? oversized.length) <= 0) return;
|
|
25478
|
+
const files = oversized.map((f) => formatOversizedFilePair({ path: sanitizeForTerminal(f.path), bytes: f.bytes })).join(", ");
|
|
25479
|
+
log.warn(
|
|
25480
|
+
tx(SERVER_TEXTS.watcherFilesOversized, {
|
|
25481
|
+
count: String(oversized.length),
|
|
25482
|
+
files
|
|
25483
|
+
})
|
|
25484
|
+
);
|
|
25485
|
+
}
|
|
25182
25486
|
function buildBroadcasterEmitter(broadcaster) {
|
|
25183
25487
|
return {
|
|
25184
25488
|
emit(event) {
|
|
@@ -26354,8 +26658,8 @@ function assembleKernel(pluginRuntime, noBuiltIns) {
|
|
|
26354
26658
|
(c) => `${c.pluginId}/${c.extensionId}/${c.contributionId}`
|
|
26355
26659
|
)
|
|
26356
26660
|
);
|
|
26357
|
-
for (const
|
|
26358
|
-
for (const ext of
|
|
26661
|
+
for (const plugin of builtInPlugins) {
|
|
26662
|
+
for (const ext of plugin.extensions) {
|
|
26359
26663
|
collectViewContributions(ext.pluginId, ext.id, ext, mergedViewContributions, {
|
|
26360
26664
|
excludeQualifiedIds: userKey
|
|
26361
26665
|
});
|
|
@@ -26368,8 +26672,8 @@ function assembleKernel(pluginRuntime, noBuiltIns) {
|
|
|
26368
26672
|
}
|
|
26369
26673
|
function collectBuiltInProviders() {
|
|
26370
26674
|
const out = [];
|
|
26371
|
-
for (const
|
|
26372
|
-
for (const ext of
|
|
26675
|
+
for (const plugin of builtInPlugins) {
|
|
26676
|
+
for (const ext of plugin.extensions) {
|
|
26373
26677
|
if (ext.kind === "provider") {
|
|
26374
26678
|
out.push(ext);
|
|
26375
26679
|
}
|
|
@@ -28615,4 +28919,5 @@ function resolveBareDefault() {
|
|
|
28615
28919
|
);
|
|
28616
28920
|
process.exit(ExitCode.Error);
|
|
28617
28921
|
}
|
|
28618
|
-
//# sourceMappingURL=cli.js.map
|
|
28922
|
+
//# sourceMappingURL=cli.js.map
|
|
28923
|
+
//# debugId=7c131b78-b7ad-5f03-b19c-1f70afdfeefb
|