@skill-map/cli 0.40.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/tutorial/sm-tutorial/SKILL.md +10 -1
- package/dist/cli.js +429 -95
- package/dist/cli.js.map +1 -1
- package/dist/index.js +39 -29
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +101 -0
- package/dist/kernel/index.js +39 -29
- package/dist/kernel/index.js.map +1 -1
- package/dist/migrations/001_initial.sql +8 -0
- package/dist/ui/chunk-5GD2GBPS.js +2190 -0
- package/dist/ui/{chunk-4HTOYDCM.js → chunk-5WJRN3LD.js} +1 -1
- package/dist/ui/{chunk-3SI3TVER.js → chunk-C2YUQODZ.js} +2 -2
- package/dist/ui/{chunk-NGIFGXW7.js → chunk-CFJBTDAA.js} +1 -1
- package/dist/ui/{chunk-YWWD62BR.js → chunk-HEJCH7BA.js} +1 -1
- package/dist/ui/chunk-HFPA56IM.js +1 -0
- package/dist/ui/chunk-HHPSCDLM.js +315 -0
- package/dist/ui/chunk-HP375T2O.js +2 -0
- package/dist/ui/chunk-HWP3HM55.js +123 -0
- package/dist/ui/{chunk-ZAEGBMF7.js → chunk-IUDL3NDH.js} +1 -1
- package/dist/ui/{chunk-Z3C2OSRL.js → chunk-JPYAASHN.js} +1 -1
- package/dist/ui/chunk-PZ6Q5AOT.js +1 -0
- package/dist/ui/chunk-XJL4DZ4M.js +1 -0
- package/dist/ui/{chunk-W2JMLJCF.js → chunk-XOHD5XWA.js} +1 -1
- package/dist/ui/chunk-YL6SWAFJ.js +1024 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/main-7VYTTJP7.js +3 -0
- package/dist/ui/{styles-6H4GSOHY.css → styles-HI4A6IWA.css} +1 -1
- package/migrations/001_initial.sql +8 -0
- package/package.json +2 -2
- package/dist/ui/chunk-4X4GYACU.js +0 -123
- package/dist/ui/chunk-7Q3IO77R.js +0 -317
- package/dist/ui/chunk-FL6RV2IG.js +0 -2
- package/dist/ui/chunk-HGNE4UVQ.js +0 -1
- package/dist/ui/chunk-IS5ULQSF.js +0 -1
- package/dist/ui/chunk-KVWYVO6I.js +0 -1
- package/dist/ui/chunk-N4XX4WPE.js +0 -2190
- package/dist/ui/chunk-P7TXZKUX.js +0 -2
- package/dist/ui/chunk-UVVXMEZT.js +0 -1025
- package/dist/ui/main-F7N5RV4Y.js +0 -3
package/dist/cli.js
CHANGED
|
@@ -442,6 +442,19 @@ var claudeProvider = {
|
|
|
442
442
|
pluginId: CLAUDE_PLUGIN_ID,
|
|
443
443
|
kind: "provider",
|
|
444
444
|
description: "Classifies files under `.claude/{agents,commands,skills}` as Claude Code agents, commands, and skills.",
|
|
445
|
+
// Provider identity for the active-lens dropdown, the topbar lens chip,
|
|
446
|
+
// and the per-node provider chip. Anthropic brand terracotta; the dark
|
|
447
|
+
// variant lifts luminosity for dark mode. Verbatim from the previous
|
|
448
|
+
// static UI catalog (`ui/src/services/provider-ui.ts`).
|
|
449
|
+
presentation: {
|
|
450
|
+
label: "Claude",
|
|
451
|
+
color: "#cc785c",
|
|
452
|
+
colorDark: "#e89270"
|
|
453
|
+
},
|
|
454
|
+
// Auto-detect marker: a `.claude/` directory under the scope root marks
|
|
455
|
+
// a Claude Code project. Provider-owned (replaces the old central
|
|
456
|
+
// detection table in `src/core/config/active-provider.ts`).
|
|
457
|
+
detect: { markers: [".claude"] },
|
|
445
458
|
// Vendor provider: Claude Code only reads its own `.claude/` territory
|
|
446
459
|
// and ignores `.codex/` / Antigravity layouts at runtime. Gating the
|
|
447
460
|
// classifier behind the active lens prevents the walker from inventing
|
|
@@ -863,6 +876,18 @@ var antigravityProvider = {
|
|
|
863
876
|
pluginId: ANTIGRAVITY_PLUGIN_ID,
|
|
864
877
|
kind: "provider",
|
|
865
878
|
description: "Declares the Google Antigravity runtime and its reserved built-in names.",
|
|
879
|
+
// Provider identity for the active-lens dropdown, the topbar lens chip,
|
|
880
|
+
// and the per-node provider chip. Antigravity violet, distinct from the
|
|
881
|
+
// other vendor palettes.
|
|
882
|
+
presentation: {
|
|
883
|
+
label: "Antigravity",
|
|
884
|
+
color: "#7c3aed",
|
|
885
|
+
colorDark: "#a78bfa"
|
|
886
|
+
},
|
|
887
|
+
// No `detect` block: Antigravity has no vendor-specific workspace marker
|
|
888
|
+
// (it adopted the open-standard `.agents/`, owned by `agent-skills`), so
|
|
889
|
+
// it is never auto-suggested. The lens is set manually via
|
|
890
|
+
// `sm config set activeProvider antigravity`.
|
|
866
891
|
// Vendor provider: marked gated for the day Antigravity grows its own
|
|
867
892
|
// on-disk kind beyond the open standard. Today `kinds: {}` and
|
|
868
893
|
// `classify` returns `null` for every path, so the flag is inert; the
|
|
@@ -1011,6 +1036,18 @@ var openaiProvider = {
|
|
|
1011
1036
|
pluginId: OPENAI_PLUGIN_ID,
|
|
1012
1037
|
kind: "provider",
|
|
1013
1038
|
description: "Classifies files under `.codex/agents/*.toml` as OpenAI Codex CLI sub-agents.",
|
|
1039
|
+
// Provider identity for the active-lens dropdown, the topbar lens chip,
|
|
1040
|
+
// and the per-node provider chip. Codex green, distinct from the Claude
|
|
1041
|
+
// palette so the chip reads at a glance.
|
|
1042
|
+
presentation: {
|
|
1043
|
+
label: "OpenAI Codex",
|
|
1044
|
+
color: "#22c55e",
|
|
1045
|
+
colorDark: "#4ade80"
|
|
1046
|
+
},
|
|
1047
|
+
// Auto-detect markers: a `.codex/` directory or a root `AGENTS.md` marks
|
|
1048
|
+
// a Codex CLI project. Provider-owned (replaces the old central
|
|
1049
|
+
// detection table in `src/core/config/active-provider.ts`).
|
|
1050
|
+
detect: { markers: [".codex", "AGENTS.md"] },
|
|
1014
1051
|
// Vendor provider: Codex CLI only reads its own `.codex/` territory.
|
|
1015
1052
|
// Gating the classifier behind the active lens keeps the walker from
|
|
1016
1053
|
// claiming Codex agents under a `claude` (or any other) lens, where
|
|
@@ -1068,6 +1105,20 @@ var agentSkillsProvider = {
|
|
|
1068
1105
|
pluginId: AGENT_SKILLS_PLUGIN_ID,
|
|
1069
1106
|
kind: "provider",
|
|
1070
1107
|
description: "Classifies files under `.agents/skills/<name>/SKILL.md` as Agent Skills.",
|
|
1108
|
+
// Provider identity for the active-lens dropdown, the topbar lens chip,
|
|
1109
|
+
// and the per-node provider chip. Neutral slate (this is the
|
|
1110
|
+
// vendor-agnostic open-standard Provider, not a brand). Verbatim from
|
|
1111
|
+
// the previous static UI catalog (`ui/src/services/provider-ui.ts`).
|
|
1112
|
+
presentation: {
|
|
1113
|
+
label: "Open Skills",
|
|
1114
|
+
color: "#64748b",
|
|
1115
|
+
colorDark: "#94a3b8"
|
|
1116
|
+
},
|
|
1117
|
+
// Auto-detect marker: a `.agents/` directory marks an open-standard
|
|
1118
|
+
// project. This is also the marker a Google/Antigravity project carries
|
|
1119
|
+
// (Antigravity adopted the open standard), so such projects auto-detect
|
|
1120
|
+
// as this universal lens. Provider-owned.
|
|
1121
|
+
detect: { markers: [".agents"] },
|
|
1071
1122
|
read: { extensions: [".md"], parser: "frontmatter-yaml" },
|
|
1072
1123
|
kinds: {
|
|
1073
1124
|
skill: {
|
|
@@ -1115,6 +1166,20 @@ var coreMarkdownProvider = {
|
|
|
1115
1166
|
pluginId: CORE_PLUGIN_ID,
|
|
1116
1167
|
kind: "provider",
|
|
1117
1168
|
description: "Universal `.md` fallback. Claims any markdown file that no vendor-specific provider has classified.",
|
|
1169
|
+
// Provider identity. `hideChip: true` suppresses the per-card provider
|
|
1170
|
+
// chip: this fallback carries the majority of nodes in any project, so
|
|
1171
|
+
// badging every generic `.md` would be noise and dilute the chip's
|
|
1172
|
+
// purpose (signalling a NON-default platform). The Provider still shows
|
|
1173
|
+
// in the active-lens dropdown and the topbar lens chip with this label.
|
|
1174
|
+
presentation: {
|
|
1175
|
+
label: "Markdown",
|
|
1176
|
+
color: "#9ca3af",
|
|
1177
|
+
colorDark: "#6b7280",
|
|
1178
|
+
hideChip: true
|
|
1179
|
+
},
|
|
1180
|
+
// No `detect` block: the universal fallback is never auto-suggested as a
|
|
1181
|
+
// lens (selecting it would gate out every vendor Provider). Operators
|
|
1182
|
+
// pick it manually if they want an open-standard-only view.
|
|
1118
1183
|
read: { extensions: [".md"], parser: "frontmatter-yaml" },
|
|
1119
1184
|
// Per spec § A.6, defaultRefreshAction values MUST be qualified
|
|
1120
1185
|
// action ids. The summarize-markdown action is not yet implemented
|
|
@@ -3855,7 +3920,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
3855
3920
|
// package.json
|
|
3856
3921
|
var package_default = {
|
|
3857
3922
|
name: "@skill-map/cli",
|
|
3858
|
-
version: "0.
|
|
3923
|
+
version: "0.42.0",
|
|
3859
3924
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
3860
3925
|
license: "MIT",
|
|
3861
3926
|
type: "module",
|
|
@@ -4287,40 +4352,40 @@ var updateCheckHook = {
|
|
|
4287
4352
|
};
|
|
4288
4353
|
|
|
4289
4354
|
// plugins/built-ins.ts
|
|
4290
|
-
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version: "0.
|
|
4291
|
-
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version: "0.
|
|
4292
|
-
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version: "0.
|
|
4293
|
-
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: "0.
|
|
4294
|
-
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: "0.
|
|
4295
|
-
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: "0.
|
|
4296
|
-
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: "0.
|
|
4297
|
-
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: "0.
|
|
4298
|
-
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: "0.
|
|
4299
|
-
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: "0.
|
|
4300
|
-
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version: "0.
|
|
4301
|
-
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version: "0.
|
|
4302
|
-
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version: "0.
|
|
4303
|
-
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version: "0.
|
|
4304
|
-
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version: "0.
|
|
4305
|
-
var contributionOrphanAnalyzer2 = { ...contributionOrphanAnalyzer, pluginId: "core", version: "0.
|
|
4306
|
-
var issueCounterAnalyzer2 = { ...issueCounterAnalyzer, pluginId: "core", version: "0.
|
|
4307
|
-
var jobFileOrphanAnalyzer2 = { ...jobFileOrphanAnalyzer, pluginId: "core", version: "0.
|
|
4308
|
-
var linkConflictAnalyzer2 = { ...linkConflictAnalyzer, pluginId: "core", version: "0.
|
|
4309
|
-
var linkCounterAnalyzer2 = { ...linkCounterAnalyzer, pluginId: "core", version: "0.
|
|
4310
|
-
var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version: "0.
|
|
4311
|
-
var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version: "0.
|
|
4312
|
-
var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version: "0.
|
|
4313
|
-
var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version: "0.
|
|
4314
|
-
var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version: "0.
|
|
4315
|
-
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: "0.
|
|
4316
|
-
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: "0.
|
|
4317
|
-
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version: "0.
|
|
4318
|
-
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version: "0.
|
|
4319
|
-
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version: "0.
|
|
4320
|
-
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: "0.
|
|
4321
|
-
var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version: "0.
|
|
4322
|
-
var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version: "0.
|
|
4323
|
-
var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version: "0.
|
|
4355
|
+
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version: "0.42.0" };
|
|
4356
|
+
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version: "0.42.0" };
|
|
4357
|
+
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version: "0.42.0" };
|
|
4358
|
+
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: "0.42.0" };
|
|
4359
|
+
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: "0.42.0" };
|
|
4360
|
+
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: "0.42.0" };
|
|
4361
|
+
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: "0.42.0" };
|
|
4362
|
+
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: "0.42.0" };
|
|
4363
|
+
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: "0.42.0" };
|
|
4364
|
+
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: "0.42.0" };
|
|
4365
|
+
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version: "0.42.0" };
|
|
4366
|
+
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version: "0.42.0" };
|
|
4367
|
+
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4368
|
+
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4369
|
+
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4370
|
+
var contributionOrphanAnalyzer2 = { ...contributionOrphanAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4371
|
+
var issueCounterAnalyzer2 = { ...issueCounterAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4372
|
+
var jobFileOrphanAnalyzer2 = { ...jobFileOrphanAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4373
|
+
var linkConflictAnalyzer2 = { ...linkConflictAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4374
|
+
var linkCounterAnalyzer2 = { ...linkCounterAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4375
|
+
var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4376
|
+
var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4377
|
+
var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4378
|
+
var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4379
|
+
var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4380
|
+
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4381
|
+
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4382
|
+
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4383
|
+
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version: "0.42.0" };
|
|
4384
|
+
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version: "0.42.0" };
|
|
4385
|
+
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: "0.42.0" };
|
|
4386
|
+
var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version: "0.42.0" };
|
|
4387
|
+
var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version: "0.42.0" };
|
|
4388
|
+
var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version: "0.42.0" };
|
|
4324
4389
|
var builtInBundles = [
|
|
4325
4390
|
{
|
|
4326
4391
|
id: "claude",
|
|
@@ -4898,6 +4963,7 @@ var defaults_default = {
|
|
|
4898
4963
|
strict: false,
|
|
4899
4964
|
followSymlinks: false,
|
|
4900
4965
|
maxFileSizeBytes: 1048576,
|
|
4966
|
+
maxNodes: 256,
|
|
4901
4967
|
watch: {
|
|
4902
4968
|
debounceMs: 300
|
|
4903
4969
|
},
|
|
@@ -7037,6 +7103,8 @@ async function loadScanResult(db) {
|
|
|
7037
7103
|
roots: parseJsonArray(metaRow.rootsJson),
|
|
7038
7104
|
providers: parseJsonArray(metaRow.providersJson),
|
|
7039
7105
|
scannedBy,
|
|
7106
|
+
recommendedNodeLimit: metaRow.recommendedNodeLimit,
|
|
7107
|
+
overrideMaxNodes: metaRow.overrideMaxNodes,
|
|
7040
7108
|
nodes,
|
|
7041
7109
|
links,
|
|
7042
7110
|
issues,
|
|
@@ -7060,6 +7128,11 @@ async function loadScanResult(db) {
|
|
|
7060
7128
|
scannedAt,
|
|
7061
7129
|
roots: ["."],
|
|
7062
7130
|
providers: [],
|
|
7131
|
+
// Synthetic envelope, default to the design cap (256) so SPA reads
|
|
7132
|
+
// the same shape across cold-boot and pre-cap-aware DBs. A real
|
|
7133
|
+
// scan overwrites scan_meta with the live values on next run.
|
|
7134
|
+
recommendedNodeLimit: 256,
|
|
7135
|
+
overrideMaxNodes: null,
|
|
7063
7136
|
nodes,
|
|
7064
7137
|
links,
|
|
7065
7138
|
issues,
|
|
@@ -7645,7 +7718,14 @@ function metaToRow(result) {
|
|
|
7645
7718
|
providersJson: JSON.stringify(result.providers),
|
|
7646
7719
|
statsFilesWalked: result.stats.filesWalked,
|
|
7647
7720
|
statsFilesSkipped: result.stats.filesSkipped,
|
|
7648
|
-
statsDurationMs: result.stats.durationMs
|
|
7721
|
+
statsDurationMs: result.stats.durationMs,
|
|
7722
|
+
...projectNodeLimitColumns(result)
|
|
7723
|
+
};
|
|
7724
|
+
}
|
|
7725
|
+
function projectNodeLimitColumns(result) {
|
|
7726
|
+
return {
|
|
7727
|
+
recommendedNodeLimit: result.recommendedNodeLimit ?? 256,
|
|
7728
|
+
overrideMaxNodes: result.overrideMaxNodes ?? null
|
|
7649
7729
|
};
|
|
7650
7730
|
}
|
|
7651
7731
|
function extractorRunToRow(record) {
|
|
@@ -10766,21 +10846,8 @@ import { Command as Command4, Option as Option4 } from "clipanion";
|
|
|
10766
10846
|
// core/config/active-provider.ts
|
|
10767
10847
|
import { existsSync as existsSync14 } from "fs";
|
|
10768
10848
|
import { join as join10 } from "path";
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
// `gemini` retired 2026-05-22: Google replaced the Gemini CLI with the
|
|
10772
|
-
// Antigravity CLI (released 2026-05-19; Gemini CLI sunsets 2026-06-18).
|
|
10773
|
-
// Antigravity adopted the open-standard `.agents/` instead of a
|
|
10774
|
-
// vendor-specific directory, so detection of a Google CLI project
|
|
10775
|
-
// falls through to the universal `agent-skills` lens (`.agents/`
|
|
10776
|
-
// already classifies via that neutral provider). The lens can still
|
|
10777
|
-
// be set manually via `sm config set activeProvider antigravity`.
|
|
10778
|
-
{ providerId: "openai", marker: ".codex" },
|
|
10779
|
-
{ providerId: "openai", marker: "AGENTS.md" },
|
|
10780
|
-
{ providerId: "cursor", marker: ".cursor" }
|
|
10781
|
-
];
|
|
10782
|
-
function resolveActiveProvider(cwd) {
|
|
10783
|
-
const detected = detectProvidersFromFilesystem(cwd);
|
|
10849
|
+
function resolveActiveProvider(cwd, providers = []) {
|
|
10850
|
+
const detected = detectProvidersFromFilesystem(cwd, providers);
|
|
10784
10851
|
const fromConfig = readConfigValue("activeProvider", { cwd });
|
|
10785
10852
|
if (typeof fromConfig === "string" && fromConfig.length > 0) {
|
|
10786
10853
|
return { resolved: fromConfig, source: "config", detected };
|
|
@@ -10790,14 +10857,16 @@ function resolveActiveProvider(cwd) {
|
|
|
10790
10857
|
}
|
|
10791
10858
|
return { resolved: null, source: "none", detected };
|
|
10792
10859
|
}
|
|
10793
|
-
function detectProvidersFromFilesystem(cwd) {
|
|
10860
|
+
function detectProvidersFromFilesystem(cwd, providers) {
|
|
10794
10861
|
const seen = /* @__PURE__ */ new Set();
|
|
10795
10862
|
const out = [];
|
|
10796
|
-
for (const
|
|
10797
|
-
if (seen.has(
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10863
|
+
for (const provider of providers) {
|
|
10864
|
+
if (seen.has(provider.id)) continue;
|
|
10865
|
+
const markers = provider.detect?.markers;
|
|
10866
|
+
if (!markers || markers.length === 0) continue;
|
|
10867
|
+
if (!markers.some((marker) => existsSync14(join10(cwd, marker)))) continue;
|
|
10868
|
+
seen.add(provider.id);
|
|
10869
|
+
out.push(provider.id);
|
|
10801
10870
|
}
|
|
10802
10871
|
return out;
|
|
10803
10872
|
}
|
|
@@ -10952,7 +11021,7 @@ function suggestConfigKey(effective, typed, ansi) {
|
|
|
10952
11021
|
});
|
|
10953
11022
|
}
|
|
10954
11023
|
var KNOWN_DEFAULTLESS_KEY_RESOLVERS = {
|
|
10955
|
-
activeProvider: (cwd) => resolveActiveProvider(cwd).resolved
|
|
11024
|
+
activeProvider: (cwd) => resolveActiveProvider(cwd, builtIns().providers).resolved
|
|
10956
11025
|
};
|
|
10957
11026
|
function parseCliValue(raw) {
|
|
10958
11027
|
try {
|
|
@@ -11349,7 +11418,7 @@ var ConfigSetCommand = class extends SmCommand {
|
|
|
11349
11418
|
cwd: ctx.cwd
|
|
11350
11419
|
});
|
|
11351
11420
|
if (this.key === "activeProvider" && typeof value === "string") {
|
|
11352
|
-
const detected = resolveActiveProvider(ctx.cwd).detected;
|
|
11421
|
+
const detected = resolveActiveProvider(ctx.cwd, builtIns().providers).detected;
|
|
11353
11422
|
writeConfigValue("activeProviderMarkers", [...detected], {
|
|
11354
11423
|
target,
|
|
11355
11424
|
cwd: ctx.cwd
|
|
@@ -15673,17 +15742,26 @@ async function walkAndExtract(opts) {
|
|
|
15673
15742
|
const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
|
|
15674
15743
|
let filesWalked = 0;
|
|
15675
15744
|
let index = 0;
|
|
15745
|
+
const effectiveMaxNodes = opts.overrideMaxNodes ?? opts.recommendedNodeLimit;
|
|
15746
|
+
let capReached = false;
|
|
15676
15747
|
const activeProviders = opts.providers.filter((provider) => {
|
|
15677
15748
|
if (!provider.gatedByActiveLens) return true;
|
|
15678
15749
|
if (opts.activeProvider === null) return true;
|
|
15679
15750
|
return provider.id === opts.activeProvider;
|
|
15680
15751
|
});
|
|
15681
|
-
|
|
15752
|
+
const advance = async (raw, provider) => {
|
|
15753
|
+
const advanced = await processRawNode(raw, provider, wctx, accum, claimedPaths, index + 1);
|
|
15754
|
+
if (advanced) index += 1;
|
|
15755
|
+
};
|
|
15756
|
+
outer: for (const provider of activeProviders) {
|
|
15682
15757
|
for await (const raw of resolveProviderWalk(provider)(opts.roots, walkOptions)) {
|
|
15683
15758
|
filesWalked += 1;
|
|
15684
15759
|
if (claimedPaths.has(raw.path)) continue;
|
|
15685
|
-
|
|
15686
|
-
|
|
15760
|
+
if (accum.nodes.length >= effectiveMaxNodes) {
|
|
15761
|
+
capReached = true;
|
|
15762
|
+
break outer;
|
|
15763
|
+
}
|
|
15764
|
+
await advance(raw, provider);
|
|
15687
15765
|
}
|
|
15688
15766
|
}
|
|
15689
15767
|
const orphanSidecars = discoverOrphanSidecars(opts.roots);
|
|
@@ -15694,6 +15772,9 @@ async function walkAndExtract(opts) {
|
|
|
15694
15772
|
cachedPaths: accum.cachedPaths,
|
|
15695
15773
|
frontmatterIssues: accum.frontmatterIssues,
|
|
15696
15774
|
filesWalked,
|
|
15775
|
+
recommendedNodeLimit: opts.recommendedNodeLimit,
|
|
15776
|
+
overrideMaxNodes: opts.overrideMaxNodes,
|
|
15777
|
+
capReached,
|
|
15697
15778
|
enrichments: [...accum.enrichmentBuffer.values()],
|
|
15698
15779
|
extractorRuns: accum.extractorRuns,
|
|
15699
15780
|
contributions: accum.contributionsBuffer,
|
|
@@ -15957,7 +16038,11 @@ async function runScanInternal(_kernel, options) {
|
|
|
15957
16038
|
const scanStartedEvent = makeEvent("scan.started", { roots: options.roots });
|
|
15958
16039
|
emitter.emit(scanStartedEvent);
|
|
15959
16040
|
await hookDispatcher.dispatch("scan.started", scanStartedEvent);
|
|
15960
|
-
const activeProviderId = resolveActiveProviderOption(
|
|
16041
|
+
const activeProviderId = resolveActiveProviderOption(
|
|
16042
|
+
options.activeProvider,
|
|
16043
|
+
options.roots,
|
|
16044
|
+
exts.providers
|
|
16045
|
+
);
|
|
15961
16046
|
const walked = await walkAndExtract({
|
|
15962
16047
|
providers: exts.providers,
|
|
15963
16048
|
extractors: exts.extractors,
|
|
@@ -15972,7 +16057,9 @@ async function runScanInternal(_kernel, options) {
|
|
|
15972
16057
|
priorExtractorRuns: setup.priorExtractorRuns,
|
|
15973
16058
|
providerFrontmatter: setup.providerFrontmatter,
|
|
15974
16059
|
pluginStores: options.pluginStores,
|
|
15975
|
-
activeProvider: activeProviderId
|
|
16060
|
+
activeProvider: activeProviderId,
|
|
16061
|
+
recommendedNodeLimit: options.recommendedNodeLimit ?? 256,
|
|
16062
|
+
overrideMaxNodes: options.overrideMaxNodes ?? null
|
|
15976
16063
|
});
|
|
15977
16064
|
const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
|
|
15978
16065
|
const resolved = resolveSignals({
|
|
@@ -16140,6 +16227,8 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
|
16140
16227
|
roots: options.roots,
|
|
16141
16228
|
providers: setup.exts.providers.map((a) => a.id),
|
|
16142
16229
|
scannedBy: SCANNED_BY,
|
|
16230
|
+
recommendedNodeLimit: walked.recommendedNodeLimit,
|
|
16231
|
+
overrideMaxNodes: walked.overrideMaxNodes,
|
|
16143
16232
|
nodes: walked.nodes,
|
|
16144
16233
|
links: walked.internalLinks,
|
|
16145
16234
|
issues,
|
|
@@ -16162,12 +16251,12 @@ function validateRoots(roots) {
|
|
|
16162
16251
|
}
|
|
16163
16252
|
}
|
|
16164
16253
|
}
|
|
16165
|
-
function resolveActiveProviderOption(optionValue, roots) {
|
|
16254
|
+
function resolveActiveProviderOption(optionValue, roots, providers) {
|
|
16166
16255
|
if (optionValue !== void 0) return optionValue;
|
|
16167
16256
|
for (const root of roots) {
|
|
16168
16257
|
const absRoot = isAbsolute7(root) ? root : resolve28(root);
|
|
16169
16258
|
if (!existsSync21(absRoot)) continue;
|
|
16170
|
-
const detected = resolveActiveProvider(absRoot).resolved;
|
|
16259
|
+
const detected = resolveActiveProvider(absRoot, providers).resolved;
|
|
16171
16260
|
if (detected !== null) return detected;
|
|
16172
16261
|
}
|
|
16173
16262
|
return null;
|
|
@@ -16636,17 +16725,23 @@ function safeStat(path) {
|
|
|
16636
16725
|
import { createInterface as createInterface2 } from "readline";
|
|
16637
16726
|
import { isAbsolute as isAbsolute9, join as join16 } from "path";
|
|
16638
16727
|
async function bootstrapActiveProvider(opts) {
|
|
16639
|
-
const fromCwd = resolveActiveProvider(opts.cwd);
|
|
16728
|
+
const fromCwd = resolveActiveProvider(opts.cwd, opts.providers);
|
|
16640
16729
|
if (fromCwd.source === "config") {
|
|
16641
16730
|
const currentMarkers = aggregateDetected(
|
|
16642
16731
|
opts.cwd,
|
|
16643
16732
|
opts.effectiveRoots,
|
|
16644
|
-
fromCwd.detected
|
|
16733
|
+
fromCwd.detected,
|
|
16734
|
+
opts.providers
|
|
16645
16735
|
);
|
|
16646
16736
|
handleDrift(opts, fromCwd.resolved, currentMarkers);
|
|
16647
16737
|
return { kind: "ok", activeProvider: fromCwd.resolved, source: "config" };
|
|
16648
16738
|
}
|
|
16649
|
-
const detected = aggregateDetected(
|
|
16739
|
+
const detected = aggregateDetected(
|
|
16740
|
+
opts.cwd,
|
|
16741
|
+
opts.effectiveRoots,
|
|
16742
|
+
fromCwd.detected,
|
|
16743
|
+
opts.providers
|
|
16744
|
+
);
|
|
16650
16745
|
if (detected.length === 0) {
|
|
16651
16746
|
const warnGlyph = opts.style?.warnGlyph ?? "\u26A0";
|
|
16652
16747
|
const dim = opts.style?.dim ?? ((s) => s);
|
|
@@ -16678,7 +16773,7 @@ async function bootstrapActiveProvider(opts) {
|
|
|
16678
16773
|
persistActiveProvider(opts.cwd, picked, detected, opts.printer);
|
|
16679
16774
|
return { kind: "ok", activeProvider: picked, source: "autodetect" };
|
|
16680
16775
|
}
|
|
16681
|
-
function aggregateDetected(cwd, effectiveRoots, cwdDetected) {
|
|
16776
|
+
function aggregateDetected(cwd, effectiveRoots, cwdDetected, providers) {
|
|
16682
16777
|
const out = [];
|
|
16683
16778
|
const seen = /* @__PURE__ */ new Set();
|
|
16684
16779
|
for (const id of cwdDetected) {
|
|
@@ -16688,7 +16783,7 @@ function aggregateDetected(cwd, effectiveRoots, cwdDetected) {
|
|
|
16688
16783
|
}
|
|
16689
16784
|
for (const root of effectiveRoots) {
|
|
16690
16785
|
const absRoot = isAbsolute9(root) ? root : join16(cwd, root);
|
|
16691
|
-
const r = resolveActiveProvider(absRoot);
|
|
16786
|
+
const r = resolveActiveProvider(absRoot, providers);
|
|
16692
16787
|
for (const id of r.detected) {
|
|
16693
16788
|
if (seen.has(id)) continue;
|
|
16694
16789
|
seen.add(id);
|
|
@@ -16818,7 +16913,13 @@ async function runScanForCommand(opts) {
|
|
|
16818
16913
|
}
|
|
16819
16914
|
const loadPrior = makePriorLoader(opts.noBuiltIns, strict);
|
|
16820
16915
|
const jobsDir = defaultProjectJobsDir(ctx);
|
|
16821
|
-
const lens = await resolveActiveLens(
|
|
16916
|
+
const lens = await resolveActiveLens(
|
|
16917
|
+
opts,
|
|
16918
|
+
ctx,
|
|
16919
|
+
effectiveRoots,
|
|
16920
|
+
pluginRuntime,
|
|
16921
|
+
detectionProviders(extensions)
|
|
16922
|
+
);
|
|
16822
16923
|
if (lens.kind === "ambiguous-provider") return lens;
|
|
16823
16924
|
const activeProvider = lens.activeProvider;
|
|
16824
16925
|
const runScanWith = makeScanRunner(
|
|
@@ -16830,15 +16931,20 @@ async function runScanForCommand(opts) {
|
|
|
16830
16931
|
extensions,
|
|
16831
16932
|
referenceablePaths,
|
|
16832
16933
|
ctx.cwd,
|
|
16833
|
-
activeProvider
|
|
16934
|
+
activeProvider,
|
|
16935
|
+
cfg.scan.maxNodes
|
|
16834
16936
|
);
|
|
16835
16937
|
const willPersist = !opts.noBuiltIns && !opts.dryRun;
|
|
16836
16938
|
return willPersist ? runPersistPath(opts, dbPath, jobsDir, strict, loadPrior, runScanWith, extensions) : runEphemeralPath(opts, dbPath, strict, loadPrior, runScanWith);
|
|
16837
16939
|
}
|
|
16838
|
-
|
|
16940
|
+
function detectionProviders(extensions) {
|
|
16941
|
+
return extensions?.providers ?? [];
|
|
16942
|
+
}
|
|
16943
|
+
async function resolveActiveLens(opts, ctx, effectiveRoots, pluginRuntime, providers) {
|
|
16839
16944
|
const bootstrap = await bootstrapActiveProvider({
|
|
16840
16945
|
cwd: ctx.cwd,
|
|
16841
16946
|
effectiveRoots,
|
|
16947
|
+
providers,
|
|
16842
16948
|
yes: opts.yes ?? false,
|
|
16843
16949
|
stdin: opts.stdin ?? process.stdin,
|
|
16844
16950
|
stderr: opts.stderr,
|
|
@@ -16931,7 +17037,7 @@ function makePriorLoader(noBuiltIns, strict) {
|
|
|
16931
17037
|
return loaded;
|
|
16932
17038
|
};
|
|
16933
17039
|
}
|
|
16934
|
-
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider) {
|
|
17040
|
+
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider, recommendedNodeLimit) {
|
|
16935
17041
|
return async (prior, priorExtractorRuns, orphanJobFiles) => {
|
|
16936
17042
|
if (opts.changed && prior === null) {
|
|
16937
17043
|
opts.stderr.write(SCAN_RUNNER_TEXTS.changedNoPriorWarning);
|
|
@@ -16946,6 +17052,7 @@ function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, exte
|
|
|
16946
17052
|
cwd: scanCwd,
|
|
16947
17053
|
prior,
|
|
16948
17054
|
activeProvider,
|
|
17055
|
+
recommendedNodeLimit,
|
|
16949
17056
|
...priorExtractorRuns ? { priorExtractorRuns } : {},
|
|
16950
17057
|
...orphanJobFiles ? { orphanJobFiles } : {}
|
|
16951
17058
|
});
|
|
@@ -16959,15 +17066,15 @@ function buildRunScanOptions(args2) {
|
|
|
16959
17066
|
tokenize: !opts.noTokens,
|
|
16960
17067
|
ignoreFilter: args2.ignoreFilter,
|
|
16961
17068
|
strict: args2.strict,
|
|
16962
|
-
emitter: opts
|
|
16963
|
-
colorEnabled: opts.colorEnabled === true
|
|
16964
|
-
}),
|
|
17069
|
+
emitter: buildRunScanEmitter(opts),
|
|
16965
17070
|
// Orphan job-file detection, empty list means "no orphans
|
|
16966
17071
|
// visible from this caller" (legacy behaviour). The orchestrator
|
|
16967
17072
|
// defaults to `[]` when the field is absent; we always pass the
|
|
16968
17073
|
// array (possibly empty) to keep the wiring uniform.
|
|
16969
17074
|
orphanJobFiles: orphanJobFiles ?? [],
|
|
16970
|
-
activeProvider: args2.activeProvider
|
|
17075
|
+
activeProvider: args2.activeProvider,
|
|
17076
|
+
recommendedNodeLimit: args2.recommendedNodeLimit,
|
|
17077
|
+
overrideMaxNodes: opts.maxNodes ?? null
|
|
16971
17078
|
};
|
|
16972
17079
|
if (args2.extensions) runOptions.extensions = args2.extensions;
|
|
16973
17080
|
if (prior) {
|
|
@@ -16979,6 +17086,12 @@ function buildRunScanOptions(args2) {
|
|
|
16979
17086
|
runOptions.cwd = args2.cwd;
|
|
16980
17087
|
return runOptions;
|
|
16981
17088
|
}
|
|
17089
|
+
function buildRunScanEmitter(opts) {
|
|
17090
|
+
if (opts.emitterFactory) return opts.emitterFactory();
|
|
17091
|
+
return createStderrProgressEmitter(opts.stderr, {
|
|
17092
|
+
colorEnabled: opts.colorEnabled === true
|
|
17093
|
+
});
|
|
17094
|
+
}
|
|
16982
17095
|
async function runPersistPath(opts, dbPath, jobsDir, strict, loadPrior, runScanWith, extensions) {
|
|
16983
17096
|
let outcome;
|
|
16984
17097
|
try {
|
|
@@ -21004,6 +21117,22 @@ var SCAN_TEXTS = {
|
|
|
21004
21117
|
persistedTo: " {{dbPath}}\n",
|
|
21005
21118
|
/** Body line for dry-run mode, same indent, marker tail. */
|
|
21006
21119
|
wouldPersist: " would persist to {{dbPath}} (dry-run)\n",
|
|
21120
|
+
/**
|
|
21121
|
+
* Cap-hit notice, printed when the walker stopped accepting nodes
|
|
21122
|
+
* because `--max-nodes` (or the `scan.maxNodes` setting) was reached.
|
|
21123
|
+
* `{{glyph}}` is the yellow warning glyph, `{{limit}}` the effective
|
|
21124
|
+
* cap, `{{source}}` either `--max-nodes` or `scan.maxNodes`. The hint
|
|
21125
|
+
* names both escape routes the user has: trimming `.skillmapignore`
|
|
21126
|
+
* (preferred) or raising the cap with `--max-nodes <N>`.
|
|
21127
|
+
*/
|
|
21128
|
+
scanCappedNotice: "{{glyph}} Scan capped at {{limit}} nodes ({{source}}).\n {{hint}}\n",
|
|
21129
|
+
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.",
|
|
21130
|
+
/**
|
|
21131
|
+
* Validation message for an invalid `--max-nodes` value. Surfaced as a
|
|
21132
|
+
* §3.1b two-line block.
|
|
21133
|
+
*/
|
|
21134
|
+
maxNodesInvalid: "{{glyph}} --max-nodes must be an integer >= 1 (got `{{value}}`).\n {{hint}}\n",
|
|
21135
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256.",
|
|
21007
21136
|
// --- scan compare-with sub-verb --------------------------------------
|
|
21008
21137
|
compareErrorPrefix: "sm scan compare-with: {{message}}\n",
|
|
21009
21138
|
compareDumpNotFound: "dump file not found: {{path}}",
|
|
@@ -21167,7 +21296,9 @@ function createWatcherRuntime(opts) {
|
|
|
21167
21296
|
tokenize,
|
|
21168
21297
|
ignoreFilter,
|
|
21169
21298
|
strict,
|
|
21170
|
-
emitter
|
|
21299
|
+
emitter,
|
|
21300
|
+
recommendedNodeLimit: cfg.scan.maxNodes,
|
|
21301
|
+
overrideMaxNodes: opts.maxNodesOverride ?? null
|
|
21171
21302
|
};
|
|
21172
21303
|
if (cfg.scan.referencePaths.length > 0) {
|
|
21173
21304
|
const walk2 = walkReferencePaths(cfg.scan.referencePaths, cwd);
|
|
@@ -21380,7 +21511,12 @@ var WATCH_TEXTS = {
|
|
|
21380
21511
|
* accepted shape so the operator can re-run without `--help`.
|
|
21381
21512
|
*/
|
|
21382
21513
|
maxConsecutiveFailuresInvalid: "{{glyph}} sm watch: --max-consecutive-failures must be a non-negative integer (got {{raw}}).\n {{hint}}\n",
|
|
21383
|
-
maxConsecutiveFailuresInvalidHint: "Pass an integer >= 0 (0 disables the circuit-breaker; the default is 5)."
|
|
21514
|
+
maxConsecutiveFailuresInvalidHint: "Pass an integer >= 0 (0 disables the circuit-breaker; the default is 5).",
|
|
21515
|
+
/**
|
|
21516
|
+
* §3.1b two-line block. Validation rejection for `--max-nodes`.
|
|
21517
|
+
*/
|
|
21518
|
+
maxNodesInvalid: "{{glyph}} sm watch: --max-nodes must be an integer >= 1 (got {{raw}}).\n {{hint}}\n",
|
|
21519
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256."
|
|
21384
21520
|
};
|
|
21385
21521
|
|
|
21386
21522
|
// cli/commands/watch.ts
|
|
@@ -21443,6 +21579,7 @@ async function runWatchLoop(opts) {
|
|
|
21443
21579
|
circuitBreaker: { maxConsecutiveFailures: breakerLimit },
|
|
21444
21580
|
killSwitches: readConformanceKillSwitches(),
|
|
21445
21581
|
...opts.maxBatches !== void 0 ? { maxBatches: opts.maxBatches } : {},
|
|
21582
|
+
...opts.maxNodes !== void 0 ? { maxNodesOverride: opts.maxNodes } : {},
|
|
21446
21583
|
events: {
|
|
21447
21584
|
onBatch: (outcome) => {
|
|
21448
21585
|
if (outcome.kind === "ok") {
|
|
@@ -21556,6 +21693,10 @@ var WatchCommand = class extends SmCommand {
|
|
|
21556
21693
|
required: false,
|
|
21557
21694
|
description: "Shut down with exit 2 after N consecutive batch failures (default 5; 0 disables the breaker)."
|
|
21558
21695
|
});
|
|
21696
|
+
maxNodes = Option28.String("--max-nodes", {
|
|
21697
|
+
required: false,
|
|
21698
|
+
description: "Per-batch override of scan.maxNodes (default 256). Bidirectional: raises OR lowers the recommended cap on classified nodes. When a batch hits the cap, additional files are dropped and the UI surfaces the persistent oversized banner. Validation: integer >= 1."
|
|
21699
|
+
});
|
|
21559
21700
|
// Long-running verb, the watcher prints its own "stopped" line on
|
|
21560
21701
|
// SIGINT / SIGTERM. Adding `done in <…>` after that would be noise.
|
|
21561
21702
|
emitElapsed = false;
|
|
@@ -21563,6 +21704,8 @@ var WatchCommand = class extends SmCommand {
|
|
|
21563
21704
|
const roots = this.roots.length > 0 ? this.roots : ["."];
|
|
21564
21705
|
const breaker = parseBreakerLimit(this.maxConsecutiveFailures, this.context.stderr, this.noColor);
|
|
21565
21706
|
if (breaker === null) return ExitCode.Error;
|
|
21707
|
+
const maxNodes = parseMaxNodesLimit(this.maxNodes, this.context.stderr, this.noColor);
|
|
21708
|
+
if (maxNodes === null) return ExitCode.Error;
|
|
21566
21709
|
const watchOpts = {
|
|
21567
21710
|
roots,
|
|
21568
21711
|
json: this.json,
|
|
@@ -21575,6 +21718,7 @@ var WatchCommand = class extends SmCommand {
|
|
|
21575
21718
|
printer: this.printer
|
|
21576
21719
|
};
|
|
21577
21720
|
if (breaker !== void 0) watchOpts.maxConsecutiveFailures = breaker;
|
|
21721
|
+
if (maxNodes !== void 0) watchOpts.maxNodes = maxNodes;
|
|
21578
21722
|
return runWatchLoop(watchOpts);
|
|
21579
21723
|
}
|
|
21580
21724
|
};
|
|
@@ -21595,6 +21739,23 @@ function parseBreakerLimit(raw, stderr, noColor) {
|
|
|
21595
21739
|
}
|
|
21596
21740
|
return parsed;
|
|
21597
21741
|
}
|
|
21742
|
+
function parseMaxNodesLimit(raw, stderr, noColor) {
|
|
21743
|
+
if (raw === void 0) return void 0;
|
|
21744
|
+
const n = Number(raw);
|
|
21745
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
21746
|
+
const stderrTty = stderr;
|
|
21747
|
+
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
21748
|
+
stderr.write(
|
|
21749
|
+
tx(WATCH_TEXTS.maxNodesInvalid, {
|
|
21750
|
+
glyph: ansi.red("\u2715"),
|
|
21751
|
+
raw,
|
|
21752
|
+
hint: ansi.dim(WATCH_TEXTS.maxNodesInvalidHint)
|
|
21753
|
+
})
|
|
21754
|
+
);
|
|
21755
|
+
return null;
|
|
21756
|
+
}
|
|
21757
|
+
return n;
|
|
21758
|
+
}
|
|
21598
21759
|
|
|
21599
21760
|
// cli/commands/scan.ts
|
|
21600
21761
|
var ScanCommand = class extends SmCommand {
|
|
@@ -21662,10 +21823,16 @@ var ScanCommand = class extends SmCommand {
|
|
|
21662
21823
|
yes = Option29.Boolean("--yes", false, {
|
|
21663
21824
|
description: "Non-interactive mode for ambiguous activeProvider auto-detect. With `--yes`, multiple provider markers (.claude/, .codex/, AGENTS.md, .cursor/) under the scan tree exit non-zero instead of prompting the operator. Set the lens manually via `sm config set activeProvider <id>` and re-run."
|
|
21664
21825
|
});
|
|
21826
|
+
maxNodes = Option29.String("--max-nodes", {
|
|
21827
|
+
required: false,
|
|
21828
|
+
description: "Per-invocation override of `scan.maxNodes` (default 256). Bidirectional: raises OR lowers the recommended cap on classified nodes. When the walker hits the cap, additional files are dropped and the scan is marked oversized in scan_meta (the UI raises a persistent banner pointing at the .skillmapignore editor in Settings \u2192 Project). Validation: integer >= 1."
|
|
21829
|
+
});
|
|
21665
21830
|
// Each branch in the orchestrator maps to one validation gate
|
|
21666
21831
|
// (--watch alias / --changed mutex / -g mutex / dispatch).
|
|
21667
21832
|
// Splitting per branch scatters the gate from the value it gates.
|
|
21668
21833
|
async run() {
|
|
21834
|
+
const parsedMaxNodes = this.parseMaxNodesFlag();
|
|
21835
|
+
if (parsedMaxNodes.kind === "error") return parsedMaxNodes.exit;
|
|
21669
21836
|
if (this.watch) return this.runWatchAlias();
|
|
21670
21837
|
if (this.changed && this.noBuiltIns) {
|
|
21671
21838
|
const ansi = this.ansiFor("stderr");
|
|
@@ -21701,10 +21868,33 @@ var ScanCommand = class extends SmCommand {
|
|
|
21701
21868
|
killSwitches: readConformanceKillSwitches(),
|
|
21702
21869
|
colorEnabled,
|
|
21703
21870
|
yes: this.yes,
|
|
21704
|
-
style
|
|
21871
|
+
style,
|
|
21872
|
+
...parsedMaxNodes.value !== void 0 ? { maxNodes: parsedMaxNodes.value } : {}
|
|
21705
21873
|
});
|
|
21706
21874
|
return outcome.kind === "ok" ? this.renderOutcome(outcome.result, outcome.persistedTo, outcome.dbPath, outcome.strict) : this.renderFailure(outcome);
|
|
21707
21875
|
}
|
|
21876
|
+
/**
|
|
21877
|
+
* Parse `--max-nodes <N>`. Returns either the integer value (or
|
|
21878
|
+
* `undefined` when the flag was omitted) or an error sentinel after
|
|
21879
|
+
* printing the validation block. Invalid (non-integer, < 1) exits 2
|
|
21880
|
+
* per spec/cli-contract.md §Node cap.
|
|
21881
|
+
*/
|
|
21882
|
+
parseMaxNodesFlag() {
|
|
21883
|
+
if (this.maxNodes === void 0) return { kind: "ok", value: void 0 };
|
|
21884
|
+
const n = Number(this.maxNodes);
|
|
21885
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
21886
|
+
const ansi = this.ansiFor("stderr");
|
|
21887
|
+
this.printer.info(
|
|
21888
|
+
tx(SCAN_TEXTS.maxNodesInvalid, {
|
|
21889
|
+
glyph: ansi.red("\u2715"),
|
|
21890
|
+
value: this.maxNodes,
|
|
21891
|
+
hint: ansi.dim(SCAN_TEXTS.maxNodesInvalidHint)
|
|
21892
|
+
})
|
|
21893
|
+
);
|
|
21894
|
+
return { kind: "error", exit: ExitCode.Error };
|
|
21895
|
+
}
|
|
21896
|
+
return { kind: "ok", value: n };
|
|
21897
|
+
}
|
|
21708
21898
|
/**
|
|
21709
21899
|
* `--watch` is a thin alias for the `sm watch` verb. Combining
|
|
21710
21900
|
* `--watch` with one-shot-only flags is incoherent, the watcher
|
|
@@ -21724,6 +21914,7 @@ var ScanCommand = class extends SmCommand {
|
|
|
21724
21914
|
}
|
|
21725
21915
|
this.emitElapsed = false;
|
|
21726
21916
|
const roots = this.roots.length > 0 ? this.roots : ["."];
|
|
21917
|
+
const parsedMaxNodes = this.parseMaxNodesFlag();
|
|
21727
21918
|
return runWatchLoop({
|
|
21728
21919
|
roots,
|
|
21729
21920
|
json: this.json,
|
|
@@ -21733,7 +21924,8 @@ var ScanCommand = class extends SmCommand {
|
|
|
21733
21924
|
db: this.db,
|
|
21734
21925
|
noPlugins: this.noPlugins,
|
|
21735
21926
|
context: this.context,
|
|
21736
|
-
printer: this.printer
|
|
21927
|
+
printer: this.printer,
|
|
21928
|
+
...parsedMaxNodes.kind === "ok" && parsedMaxNodes.value !== void 0 ? { maxNodes: parsedMaxNodes.value } : {}
|
|
21737
21929
|
});
|
|
21738
21930
|
}
|
|
21739
21931
|
/**
|
|
@@ -21820,8 +22012,32 @@ var ScanCommand = class extends SmCommand {
|
|
|
21820
22012
|
})
|
|
21821
22013
|
);
|
|
21822
22014
|
}
|
|
22015
|
+
this.maybePrintCapNotice(result, ansi);
|
|
21823
22016
|
return exitCode2;
|
|
21824
22017
|
}
|
|
22018
|
+
/**
|
|
22019
|
+
* Surface the §Node cap notice when the walker actually stopped
|
|
22020
|
+
* accepting files because of the cap. Derivation: `filesWalked >
|
|
22021
|
+
* effectiveLimit` means the walker incremented past the cap at least
|
|
22022
|
+
* once (i.e. classified the (limit+1)-th raw before breaking). When
|
|
22023
|
+
* the project has EXACTLY the cap many files the loop ends naturally
|
|
22024
|
+
* without ever firing the break, so the notice stays silent.
|
|
22025
|
+
*/
|
|
22026
|
+
maybePrintCapNotice(result, ansi) {
|
|
22027
|
+
const recommended = result.recommendedNodeLimit;
|
|
22028
|
+
if (recommended === void 0) return;
|
|
22029
|
+
const override = result.overrideMaxNodes ?? null;
|
|
22030
|
+
const effectiveLimit = override ?? recommended;
|
|
22031
|
+
if (result.stats.filesWalked <= effectiveLimit) return;
|
|
22032
|
+
this.printer.info(
|
|
22033
|
+
tx(SCAN_TEXTS.scanCappedNotice, {
|
|
22034
|
+
glyph: ansi.yellow("\u26A0"),
|
|
22035
|
+
limit: String(effectiveLimit),
|
|
22036
|
+
source: override !== null ? "--max-nodes" : "scan.maxNodes",
|
|
22037
|
+
hint: ansi.dim(SCAN_TEXTS.scanCappedNoticeHint)
|
|
22038
|
+
})
|
|
22039
|
+
);
|
|
22040
|
+
}
|
|
21825
22041
|
/**
|
|
21826
22042
|
* `--json` output path. Under `--strict` (H4) self-validates the
|
|
21827
22043
|
* ScanResult against `scan-result.schema.json` before emitting it,
|
|
@@ -22706,15 +22922,17 @@ function buildListEnvelope(opts) {
|
|
|
22706
22922
|
filters: opts.filters,
|
|
22707
22923
|
counts,
|
|
22708
22924
|
kindRegistry: opts.kindRegistry,
|
|
22925
|
+
providerRegistry: opts.providerRegistry,
|
|
22709
22926
|
contributionsRegistry: opts.contributionsRegistry
|
|
22710
22927
|
};
|
|
22711
22928
|
}
|
|
22712
|
-
function buildValueEnvelope(kind, value, kindRegistry, contributionsRegistry) {
|
|
22929
|
+
function buildValueEnvelope(kind, value, kindRegistry, providerRegistry, contributionsRegistry) {
|
|
22713
22930
|
return {
|
|
22714
22931
|
schemaVersion: REST_ENVELOPE_SCHEMA_VERSION,
|
|
22715
22932
|
kind,
|
|
22716
22933
|
value,
|
|
22717
22934
|
kindRegistry,
|
|
22935
|
+
providerRegistry,
|
|
22718
22936
|
contributionsRegistry
|
|
22719
22937
|
};
|
|
22720
22938
|
}
|
|
@@ -22731,7 +22949,15 @@ function registerConfigRoute(app, deps) {
|
|
|
22731
22949
|
for (const warn of loaded.warnings) {
|
|
22732
22950
|
log.warn(sanitizeForTerminal(warn));
|
|
22733
22951
|
}
|
|
22734
|
-
return c.json(
|
|
22952
|
+
return c.json(
|
|
22953
|
+
buildValueEnvelope(
|
|
22954
|
+
"config",
|
|
22955
|
+
loaded.effective,
|
|
22956
|
+
deps.kindRegistry,
|
|
22957
|
+
deps.providerRegistry,
|
|
22958
|
+
deps.contributionsRegistry
|
|
22959
|
+
)
|
|
22960
|
+
);
|
|
22735
22961
|
});
|
|
22736
22962
|
}
|
|
22737
22963
|
|
|
@@ -22929,6 +23155,7 @@ function registerIssuesRoute(app, deps) {
|
|
|
22929
23155
|
total: result?.total ?? 0,
|
|
22930
23156
|
page: { offset: inputs.filter.offset, limit: inputs.filter.limit },
|
|
22931
23157
|
kindRegistry: deps.kindRegistry,
|
|
23158
|
+
providerRegistry: deps.providerRegistry,
|
|
22932
23159
|
contributionsRegistry: deps.contributionsRegistry
|
|
22933
23160
|
})
|
|
22934
23161
|
);
|
|
@@ -22991,6 +23218,7 @@ function registerLinksRoute(app, deps) {
|
|
|
22991
23218
|
},
|
|
22992
23219
|
total: filtered.length,
|
|
22993
23220
|
kindRegistry: deps.kindRegistry,
|
|
23221
|
+
providerRegistry: deps.providerRegistry,
|
|
22994
23222
|
contributionsRegistry: deps.contributionsRegistry
|
|
22995
23223
|
})
|
|
22996
23224
|
);
|
|
@@ -23155,6 +23383,7 @@ function registerNodesRoutes(app, deps) {
|
|
|
23155
23383
|
links: { incoming: bundle.linksIn, outgoing: bundle.linksOut },
|
|
23156
23384
|
issues: bundle.issues,
|
|
23157
23385
|
kindRegistry: deps.kindRegistry,
|
|
23386
|
+
providerRegistry: deps.providerRegistry,
|
|
23158
23387
|
contributionsRegistry: deps.contributionsRegistry
|
|
23159
23388
|
});
|
|
23160
23389
|
});
|
|
@@ -23219,6 +23448,7 @@ function registerNodesRoutes(app, deps) {
|
|
|
23219
23448
|
total,
|
|
23220
23449
|
page: { offset, limit },
|
|
23221
23450
|
kindRegistry: deps.kindRegistry,
|
|
23451
|
+
providerRegistry: deps.providerRegistry,
|
|
23222
23452
|
contributionsRegistry: deps.contributionsRegistry
|
|
23223
23453
|
})
|
|
23224
23454
|
);
|
|
@@ -23373,6 +23603,7 @@ function registerPluginsRoute(app, deps) {
|
|
|
23373
23603
|
filters: {},
|
|
23374
23604
|
total: items.length,
|
|
23375
23605
|
kindRegistry: deps.kindRegistry,
|
|
23606
|
+
providerRegistry: deps.providerRegistry,
|
|
23376
23607
|
contributionsRegistry: deps.contributionsRegistry
|
|
23377
23608
|
})
|
|
23378
23609
|
);
|
|
@@ -23589,6 +23820,7 @@ function projectListResponse(c, deps, overrides) {
|
|
|
23589
23820
|
filters: {},
|
|
23590
23821
|
total: items.length,
|
|
23591
23822
|
kindRegistry: deps.kindRegistry,
|
|
23823
|
+
providerRegistry: deps.providerRegistry,
|
|
23592
23824
|
contributionsRegistry: deps.contributionsRegistry
|
|
23593
23825
|
})
|
|
23594
23826
|
);
|
|
@@ -24129,7 +24361,7 @@ function registerActiveProviderRoute(app, deps) {
|
|
|
24129
24361
|
});
|
|
24130
24362
|
}
|
|
24131
24363
|
function buildEnvelope4(deps) {
|
|
24132
|
-
const r = resolveActiveProvider(deps.runtimeContext.cwd);
|
|
24364
|
+
const r = resolveActiveProvider(deps.runtimeContext.cwd, deps.providers);
|
|
24133
24365
|
return {
|
|
24134
24366
|
activeProvider: r.resolved,
|
|
24135
24367
|
detected: r.detected,
|
|
@@ -24285,6 +24517,9 @@ function createWatcherService(opts) {
|
|
|
24285
24517
|
if (opts.debounceMsOverride !== void 0) {
|
|
24286
24518
|
runtimeOpts.debounceMsOverride = opts.debounceMsOverride;
|
|
24287
24519
|
}
|
|
24520
|
+
if (opts.options.maxNodes !== void 0) {
|
|
24521
|
+
runtimeOpts.maxNodesOverride = opts.options.maxNodes;
|
|
24522
|
+
}
|
|
24288
24523
|
return runtimeOpts;
|
|
24289
24524
|
};
|
|
24290
24525
|
return {
|
|
@@ -24362,7 +24597,11 @@ async function runPersistedScan(c, deps) {
|
|
|
24362
24597
|
// BFF has no TTY; ambiguous activeProvider must be resolved by
|
|
24363
24598
|
// the operator via the Settings UI (PATCH /api/active-provider)
|
|
24364
24599
|
// before the scan, not via interactive prompt here.
|
|
24365
|
-
yes: true
|
|
24600
|
+
yes: true,
|
|
24601
|
+
// `--max-nodes` from the `sm serve` invocation (or the bare
|
|
24602
|
+
// `sm --max-nodes <N>` shortcut) flows through to every scan
|
|
24603
|
+
// the BFF runs so the override is honoured end-to-end.
|
|
24604
|
+
...deps.options.maxNodes !== void 0 ? { maxNodes: deps.options.maxNodes } : {}
|
|
24366
24605
|
});
|
|
24367
24606
|
if (outcome.kind !== "ok") {
|
|
24368
24607
|
throw new HTTPException13(500, {
|
|
@@ -24466,7 +24705,10 @@ async function runFreshScan(deps) {
|
|
|
24466
24705
|
printer: bffScanRunnerPrinter,
|
|
24467
24706
|
// BFF has no TTY; ambiguous activeProvider is the operator's
|
|
24468
24707
|
// problem to resolve via the Settings UI, not via prompt here.
|
|
24469
|
-
yes: true
|
|
24708
|
+
yes: true,
|
|
24709
|
+
// Carry `--max-nodes` from `sm serve` into the fresh-scan path
|
|
24710
|
+
// too so a UI-driven refresh honours the same cap as the watcher.
|
|
24711
|
+
...deps.options.maxNodes !== void 0 ? { maxNodes: deps.options.maxNodes } : {}
|
|
24470
24712
|
});
|
|
24471
24713
|
if (outcome.kind !== "ok") {
|
|
24472
24714
|
throw new HTTPException13(500, {
|
|
@@ -24488,6 +24730,12 @@ function emptyScanResult() {
|
|
|
24488
24730
|
scannedAt: Date.now(),
|
|
24489
24731
|
roots: ["."],
|
|
24490
24732
|
providers: [],
|
|
24733
|
+
// Surface the design default so the SPA reads the same field shape
|
|
24734
|
+
// on cold boot as on populated DBs. 256 mirrors `scan.maxNodes`
|
|
24735
|
+
// from `src/config/defaults.json`; the temporary testing default
|
|
24736
|
+
// (2) only applies after a real scan walks through the kernel.
|
|
24737
|
+
recommendedNodeLimit: 256,
|
|
24738
|
+
overrideMaxNodes: null,
|
|
24491
24739
|
nodes: [],
|
|
24492
24740
|
links: [],
|
|
24493
24741
|
issues: [],
|
|
@@ -24861,6 +25109,8 @@ function createApp(deps) {
|
|
|
24861
25109
|
options: deps.options,
|
|
24862
25110
|
runtimeContext: deps.runtimeContext,
|
|
24863
25111
|
kindRegistry: deps.kindRegistry,
|
|
25112
|
+
providerRegistry: deps.providerRegistry,
|
|
25113
|
+
providers: deps.providers,
|
|
24864
25114
|
contributionsRegistry: deps.contributionsRegistry,
|
|
24865
25115
|
pluginRuntime: deps.pluginRuntime,
|
|
24866
25116
|
configService,
|
|
@@ -25156,6 +25406,25 @@ function buildKindRegistry(providers) {
|
|
|
25156
25406
|
return registry;
|
|
25157
25407
|
}
|
|
25158
25408
|
|
|
25409
|
+
// server/provider-registry.ts
|
|
25410
|
+
function buildProviderRegistry(providers) {
|
|
25411
|
+
const registry = {};
|
|
25412
|
+
for (const provider of providers) {
|
|
25413
|
+
const ui = provider.presentation;
|
|
25414
|
+
if (!ui) continue;
|
|
25415
|
+
const entry = {
|
|
25416
|
+
label: ui.label,
|
|
25417
|
+
color: ui.color
|
|
25418
|
+
};
|
|
25419
|
+
if (ui.colorDark !== void 0) entry.colorDark = ui.colorDark;
|
|
25420
|
+
if (ui.emoji !== void 0) entry.emoji = ui.emoji;
|
|
25421
|
+
if (ui.icon !== void 0) entry.icon = ui.icon;
|
|
25422
|
+
if (ui.hideChip !== void 0) entry.hideChip = ui.hideChip;
|
|
25423
|
+
registry[provider.id] = entry;
|
|
25424
|
+
}
|
|
25425
|
+
return registry;
|
|
25426
|
+
}
|
|
25427
|
+
|
|
25159
25428
|
// server/contributions-registry.ts
|
|
25160
25429
|
function buildContributionsRegistry(kernel) {
|
|
25161
25430
|
const registry = {};
|
|
@@ -25200,6 +25469,8 @@ function validateServerOptions(input) {
|
|
|
25200
25469
|
if (watcherError !== null) return { ok: false, error: watcherError };
|
|
25201
25470
|
const debounceError = validateWatcherDebounce(input.watcherDebounceMs);
|
|
25202
25471
|
if (debounceError !== null) return { ok: false, error: debounceError };
|
|
25472
|
+
const maxNodesError = validateMaxNodes(input.maxNodes);
|
|
25473
|
+
if (maxNodesError !== null) return { ok: false, error: maxNodesError };
|
|
25203
25474
|
const noUiError = validateNoUi(filled.noUi, filled.uiDist);
|
|
25204
25475
|
if (noUiError !== null) return { ok: false, error: noUiError };
|
|
25205
25476
|
const options = {
|
|
@@ -25217,6 +25488,9 @@ function validateServerOptions(input) {
|
|
|
25217
25488
|
if (input.watcherDebounceMs !== void 0) {
|
|
25218
25489
|
options.watcherDebounceMs = input.watcherDebounceMs;
|
|
25219
25490
|
}
|
|
25491
|
+
if (input.maxNodes !== void 0) {
|
|
25492
|
+
options.maxNodes = input.maxNodes;
|
|
25493
|
+
}
|
|
25220
25494
|
return { ok: true, options };
|
|
25221
25495
|
}
|
|
25222
25496
|
function applyDefaults(input) {
|
|
@@ -25277,6 +25551,17 @@ function validateWatcherDebounce(value) {
|
|
|
25277
25551
|
}
|
|
25278
25552
|
return null;
|
|
25279
25553
|
}
|
|
25554
|
+
function validateMaxNodes(value) {
|
|
25555
|
+
if (value === void 0) return null;
|
|
25556
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
25557
|
+
return {
|
|
25558
|
+
code: "max-nodes-invalid",
|
|
25559
|
+
message: `--max-nodes must be an integer >= 1 (got ${value})`,
|
|
25560
|
+
value: String(value)
|
|
25561
|
+
};
|
|
25562
|
+
}
|
|
25563
|
+
return null;
|
|
25564
|
+
}
|
|
25280
25565
|
function validateNoUi(noUi, uiDist) {
|
|
25281
25566
|
if (noUi && uiDist !== null) {
|
|
25282
25567
|
return {
|
|
@@ -25351,7 +25636,7 @@ async function createServer(options, extra = {}) {
|
|
|
25351
25636
|
const specVersion = await resolveSpecVersion2();
|
|
25352
25637
|
const runtimeContext = extra.runtimeContext ?? defaultRuntimeContext();
|
|
25353
25638
|
const broadcaster = new WsBroadcaster();
|
|
25354
|
-
const { pluginRuntime, kindRegistry } = await assemblePluginRuntime(options, runtimeContext);
|
|
25639
|
+
const { pluginRuntime, kindRegistry, providerRegistry, providers } = await assemblePluginRuntime(options, runtimeContext);
|
|
25355
25640
|
const { kernel, contributionsRegistry } = assembleKernel(pluginRuntime, options.noBuiltIns);
|
|
25356
25641
|
const watcherHolder = { current: null };
|
|
25357
25642
|
const app = createApp({
|
|
@@ -25360,6 +25645,8 @@ async function createServer(options, extra = {}) {
|
|
|
25360
25645
|
broadcaster,
|
|
25361
25646
|
runtimeContext,
|
|
25362
25647
|
kindRegistry,
|
|
25648
|
+
providerRegistry,
|
|
25649
|
+
providers,
|
|
25363
25650
|
contributionsRegistry,
|
|
25364
25651
|
pluginRuntime,
|
|
25365
25652
|
watcherHolder,
|
|
@@ -25418,11 +25705,10 @@ async function assemblePluginRuntime(options, runtimeContext) {
|
|
|
25418
25705
|
log.warn(sanitizeForTerminal(warn));
|
|
25419
25706
|
}
|
|
25420
25707
|
const builtInProviders = options.noBuiltIns ? [] : collectBuiltInProviders();
|
|
25421
|
-
const
|
|
25422
|
-
|
|
25423
|
-
|
|
25424
|
-
|
|
25425
|
-
return { pluginRuntime, kindRegistry };
|
|
25708
|
+
const allProviders = [...builtInProviders, ...pluginRuntime.extensions.providers];
|
|
25709
|
+
const kindRegistry = buildKindRegistry(allProviders);
|
|
25710
|
+
const providerRegistry = buildProviderRegistry(allProviders);
|
|
25711
|
+
return { pluginRuntime, kindRegistry, providerRegistry, providers: allProviders };
|
|
25426
25712
|
}
|
|
25427
25713
|
function assembleKernel(pluginRuntime, noBuiltIns) {
|
|
25428
25714
|
const kernel = createKernel();
|
|
@@ -25556,6 +25842,12 @@ var SERVE_TEXTS = {
|
|
|
25556
25842
|
*/
|
|
25557
25843
|
watcherDebounceInvalid: "{{glyph}} sm serve: --watcher-debounce-ms must be a non-negative integer (got {{value}}).\n {{hint}}\n",
|
|
25558
25844
|
watcherDebounceInvalidHint: "Pass an integer >= 0 (e.g. 250).",
|
|
25845
|
+
/**
|
|
25846
|
+
* §3.1b error block for an invalid `--max-nodes <N>`. Same shape as
|
|
25847
|
+
* the watcher-debounce template family.
|
|
25848
|
+
*/
|
|
25849
|
+
maxNodesInvalid: "{{glyph}} sm serve: --max-nodes must be an integer >= 1 (got {{value}}).\n {{hint}}\n",
|
|
25850
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256.",
|
|
25559
25851
|
// --- --no-ui flag-validation failures (ExitCode.Error) ------------------
|
|
25560
25852
|
/**
|
|
25561
25853
|
* §3.1b error block when `--no-ui` is paired with an explicit
|
|
@@ -25825,6 +26117,10 @@ var ServeCommand = class extends SmCommand {
|
|
|
25825
26117
|
// who want to tighten / relax the watcher's batching window without
|
|
25826
26118
|
// editing settings.json. Hidden flag, the Usage block omits it.
|
|
25827
26119
|
watcherDebounceMs = Option31.String("--watcher-debounce-ms", { required: false, hidden: true });
|
|
26120
|
+
maxNodes = Option31.String("--max-nodes", {
|
|
26121
|
+
required: false,
|
|
26122
|
+
description: "Per-invocation override of scan.maxNodes (default 256). Bidirectional: raises OR lowers the recommended cap on classified nodes. Applies to every scan the server runs (initial watcher pass, debounced batches, POST /api/scan, GET /api/scan?fresh=1). Same flag is honoured on the bare `sm` invocation, which routes to `sm serve`."
|
|
26123
|
+
});
|
|
25828
26124
|
// Long-running daemon, `done in <…>` after a graceful shutdown is
|
|
25829
26125
|
// noise. Mirrors `sm watch`'s opt-out.
|
|
25830
26126
|
emitElapsed = false;
|
|
@@ -25903,6 +26199,17 @@ var ServeCommand = class extends SmCommand {
|
|
|
25903
26199
|
);
|
|
25904
26200
|
return ExitCode.Error;
|
|
25905
26201
|
}
|
|
26202
|
+
const maxNodesResult = parseMaxNodes(this.maxNodes);
|
|
26203
|
+
if (!maxNodesResult.ok) {
|
|
26204
|
+
this.printer.info(
|
|
26205
|
+
tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
26206
|
+
glyph: errGlyph,
|
|
26207
|
+
value: sanitizeForTerminal(maxNodesResult.value),
|
|
26208
|
+
hint: stderrAnsi.dim(SERVE_TEXTS.maxNodesInvalidHint)
|
|
26209
|
+
})
|
|
26210
|
+
);
|
|
26211
|
+
return ExitCode.Error;
|
|
26212
|
+
}
|
|
25906
26213
|
const input = {
|
|
25907
26214
|
dbPath,
|
|
25908
26215
|
uiDist: resolvedUiDist,
|
|
@@ -25916,6 +26223,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
25916
26223
|
if (portResult.port !== void 0) input.port = portResult.port;
|
|
25917
26224
|
if (this.host !== void 0) input.host = this.host;
|
|
25918
26225
|
if (debounceResult.value !== void 0) input.watcherDebounceMs = debounceResult.value;
|
|
26226
|
+
if (maxNodesResult.value !== void 0) input.maxNodes = maxNodesResult.value;
|
|
25919
26227
|
const validation = validateServerOptions(input);
|
|
25920
26228
|
if (!validation.ok) {
|
|
25921
26229
|
this.printer.info(formatValidationError(validation.error, stderrAnsi));
|
|
@@ -25985,6 +26293,12 @@ function parseDebounce(raw) {
|
|
|
25985
26293
|
if (parsed === null) return { ok: false, value: raw };
|
|
25986
26294
|
return { ok: true, value: parsed };
|
|
25987
26295
|
}
|
|
26296
|
+
function parseMaxNodes(raw) {
|
|
26297
|
+
if (raw === void 0) return { ok: true, value: void 0 };
|
|
26298
|
+
const n = Number(raw);
|
|
26299
|
+
if (!Number.isInteger(n) || n < 1) return { ok: false, value: raw };
|
|
26300
|
+
return { ok: true, value: n };
|
|
26301
|
+
}
|
|
25988
26302
|
function resolveUiDist(ctx, raw) {
|
|
25989
26303
|
if (raw === void 0) {
|
|
25990
26304
|
return { ok: true, uiDist: resolveDefaultUiDist(ctx) };
|
|
@@ -26031,6 +26345,12 @@ function formatValidationError(err, ansi) {
|
|
|
26031
26345
|
value: sanitizeForTerminal(err.value),
|
|
26032
26346
|
hint: ansi.dim(SERVE_TEXTS.watcherDebounceInvalidHint)
|
|
26033
26347
|
});
|
|
26348
|
+
case "max-nodes-invalid":
|
|
26349
|
+
return tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
26350
|
+
glyph: errGlyph,
|
|
26351
|
+
value: sanitizeForTerminal(err.value),
|
|
26352
|
+
hint: ansi.dim(SERVE_TEXTS.maxNodesInvalidHint)
|
|
26353
|
+
});
|
|
26034
26354
|
case "no-ui-conflicts-ui-dist":
|
|
26035
26355
|
return tx(SERVE_TEXTS.noUiConflictsUiDist, {
|
|
26036
26356
|
glyph: errGlyph,
|
|
@@ -27409,7 +27729,7 @@ var logLevel = resolveLogLevel({
|
|
|
27409
27729
|
errStream: process.stderr
|
|
27410
27730
|
});
|
|
27411
27731
|
configureLogger(new Logger({ level: logLevel, stream: process.stderr }));
|
|
27412
|
-
var bareArgs = args
|
|
27732
|
+
var bareArgs = resolveBareInvocation(args);
|
|
27413
27733
|
var routedArgs = routeHelpArgs(bareArgs ?? args, cli);
|
|
27414
27734
|
var lifecycleDispatcher = makeHookDispatcher(
|
|
27415
27735
|
builtIns().hooks ?? [],
|
|
@@ -27452,6 +27772,20 @@ await lifecycleDispatcher.dispatch(
|
|
|
27452
27772
|
makeEvent("shutdown", { exitCode })
|
|
27453
27773
|
);
|
|
27454
27774
|
process.exit(exitCode);
|
|
27775
|
+
function resolveBareInvocation(rawArgs) {
|
|
27776
|
+
if (rawArgs.length === 0) return resolveBareDefault();
|
|
27777
|
+
const first = rawArgs[0];
|
|
27778
|
+
const passthrough = /* @__PURE__ */ new Set(["--help", "-h", "--version", "-V", "-v"]);
|
|
27779
|
+
if (first !== void 0 && first.startsWith("-") && !passthrough.has(first)) {
|
|
27780
|
+
const isSingleDashLong = !first.startsWith("--") && first.length > 2;
|
|
27781
|
+
if (isSingleDashLong) return null;
|
|
27782
|
+
if (existsSync30(defaultProjectDbPath(defaultRuntimeContext()))) {
|
|
27783
|
+
return ["serve", ...rawArgs];
|
|
27784
|
+
}
|
|
27785
|
+
return resolveBareDefault();
|
|
27786
|
+
}
|
|
27787
|
+
return null;
|
|
27788
|
+
}
|
|
27455
27789
|
function resolveBareDefault() {
|
|
27456
27790
|
const ctx = defaultRuntimeContext();
|
|
27457
27791
|
if (existsSync30(defaultProjectDbPath(ctx))) {
|