@skill-map/cli 0.40.0 → 0.41.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 +275 -53
- package/dist/cli.js.map +1 -1
- package/dist/index.js +22 -5
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.d.ts +30 -0
- package/dist/kernel/index.js +22 -5
- 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-5WJRN3LD.js +809 -0
- 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-DQ45L4EV.js +123 -0
- package/dist/ui/{chunk-3FPS5OIY.js → chunk-HEJCH7BA.js} +1 -1
- package/dist/ui/chunk-HFPA56IM.js +1 -0
- package/dist/ui/chunk-HP375T2O.js +2 -0
- package/dist/ui/{chunk-WQ42JTZB.js → chunk-IUDL3NDH.js} +1 -1
- package/dist/ui/{chunk-ASCTZSBZ.js → chunk-JPYAASHN.js} +1 -1
- package/dist/ui/chunk-JWI3M5RV.js +1 -0
- package/dist/ui/chunk-XJL4DZ4M.js +1 -0
- package/dist/ui/{chunk-GSTYLDCL.js → chunk-XOHD5XWA.js} +1 -1
- package/dist/ui/chunk-YL6SWAFJ.js +1024 -0
- package/dist/ui/chunk-ZVGHYOKP.js +315 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/main-JCF6OBGZ.js +3 -0
- package/dist/ui/{styles-2WO3KNOY.css → styles-6H4GSOHY.css} +1 -1
- package/migrations/001_initial.sql +8 -0
- package/package.json +2 -2
- package/dist/ui/chunk-2W6BCESO.js +0 -2589
- package/dist/ui/chunk-4KQGLZV2.js +0 -123
- package/dist/ui/chunk-MHEKCBIR.js +0 -317
- package/dist/ui/chunk-PFA2CVPN.js +0 -61
- package/dist/ui/chunk-PURF7B6R.js +0 -411
- package/dist/ui/chunk-UFCOGNZX.js +0 -1
- package/dist/ui/chunk-XEWWXGNE.js +0 -1
- package/dist/ui/chunk-YXFKPYK3.js +0 -965
- package/dist/ui/main-WLCA4YLM.js +0 -3
|
@@ -919,6 +919,11 @@ Tell the tester:
|
|
|
919
919
|
> the field you'll edit next, so leave the card open and the
|
|
920
920
|
> change will be obvious.
|
|
921
921
|
>
|
|
922
|
+
> ⚠ Heads-up: the inspector header shows a few action buttons
|
|
923
|
+
> (Bump, Close, etc). **Don't click any of them yet** , some of
|
|
924
|
+
> them write files to your project and we cover that flow
|
|
925
|
+
> deliberately in step 13. For now, just look.
|
|
926
|
+
>
|
|
922
927
|
> Now open `.claude/agents/demo-agent.md` in your editor of
|
|
923
928
|
> choice. In the **frontmatter** at the top of the file, change
|
|
924
929
|
> the `description:` field to any text you want, the actual
|
|
@@ -1409,9 +1414,13 @@ permission. After you say yes, the choice persists per-checkout
|
|
|
1409
1414
|
(gitignored) and the prompt never appears again.
|
|
1410
1415
|
|
|
1411
1416
|
We'll demonstrate by creating an empty annotation scaffold for
|
|
1412
|
-
`notes/todo.md`.
|
|
1417
|
+
`notes/todo.md`. **Reset any prior consent state first** so the
|
|
1418
|
+
prompt actually appears (an earlier step may have flipped the flag
|
|
1419
|
+
without you noticing, in which case `sm sidecar annotate` would
|
|
1420
|
+
skip straight past the prompt and the lesson would not land):
|
|
1413
1421
|
|
|
1414
1422
|
```bash
|
|
1423
|
+
rm -f notes/todo.sm .skill-map/settings.local.json
|
|
1415
1424
|
sm sidecar annotate notes/todo.md
|
|
1416
1425
|
```
|
|
1417
1426
|
|
package/dist/cli.js
CHANGED
|
@@ -3855,7 +3855,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
3855
3855
|
// package.json
|
|
3856
3856
|
var package_default = {
|
|
3857
3857
|
name: "@skill-map/cli",
|
|
3858
|
-
version: "0.
|
|
3858
|
+
version: "0.41.0",
|
|
3859
3859
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
3860
3860
|
license: "MIT",
|
|
3861
3861
|
type: "module",
|
|
@@ -4287,40 +4287,40 @@ var updateCheckHook = {
|
|
|
4287
4287
|
};
|
|
4288
4288
|
|
|
4289
4289
|
// 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.
|
|
4290
|
+
var claudeProvider2 = { ...claudeProvider, pluginId: "claude", version: "0.41.0" };
|
|
4291
|
+
var atDirectiveExtractor2 = { ...atDirectiveExtractor, pluginId: "claude", version: "0.41.0" };
|
|
4292
|
+
var slashCommandExtractor2 = { ...slashCommandExtractor, pluginId: "claude", version: "0.41.0" };
|
|
4293
|
+
var antigravityProvider2 = { ...antigravityProvider, pluginId: "antigravity", version: "0.41.0" };
|
|
4294
|
+
var openaiProvider2 = { ...openaiProvider, pluginId: "openai", version: "0.41.0" };
|
|
4295
|
+
var agentSkillsProvider2 = { ...agentSkillsProvider, pluginId: "agent-skills", version: "0.41.0" };
|
|
4296
|
+
var coreMarkdownProvider2 = { ...coreMarkdownProvider, pluginId: "core", version: "0.41.0" };
|
|
4297
|
+
var annotationsExtractor2 = { ...annotationsExtractor, pluginId: "core", version: "0.41.0" };
|
|
4298
|
+
var externalUrlCounterExtractor2 = { ...externalUrlCounterExtractor, pluginId: "core", version: "0.41.0" };
|
|
4299
|
+
var markdownLinkExtractor2 = { ...markdownLinkExtractor, pluginId: "core", version: "0.41.0" };
|
|
4300
|
+
var mcpToolsExtractor2 = { ...mcpToolsExtractor, pluginId: "core", version: "0.41.0" };
|
|
4301
|
+
var toolsCounterExtractor2 = { ...toolsCounterExtractor, pluginId: "core", version: "0.41.0" };
|
|
4302
|
+
var annotationFieldUnknownAnalyzer2 = { ...annotationFieldUnknownAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4303
|
+
var annotationOrphanAnalyzer2 = { ...annotationOrphanAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4304
|
+
var annotationStaleAnalyzer2 = { ...annotationStaleAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4305
|
+
var contributionOrphanAnalyzer2 = { ...contributionOrphanAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4306
|
+
var issueCounterAnalyzer2 = { ...issueCounterAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4307
|
+
var jobFileOrphanAnalyzer2 = { ...jobFileOrphanAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4308
|
+
var linkConflictAnalyzer2 = { ...linkConflictAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4309
|
+
var linkCounterAnalyzer2 = { ...linkCounterAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4310
|
+
var linkSelfLoopAnalyzer2 = { ...linkSelfLoopAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4311
|
+
var nameReservedAnalyzer2 = { ...nameReservedAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4312
|
+
var nodeStabilityAnalyzer2 = { ...nodeStabilityAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4313
|
+
var nodeSupersededAnalyzer2 = { ...nodeSupersededAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4314
|
+
var referenceBrokenAnalyzer2 = { ...referenceBrokenAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4315
|
+
var referenceRedundantAnalyzer2 = { ...referenceRedundantAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4316
|
+
var schemaViolationAnalyzer2 = { ...schemaViolationAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4317
|
+
var signalCollisionAnalyzer2 = { ...signalCollisionAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4318
|
+
var triggerCollisionAnalyzer2 = { ...triggerCollisionAnalyzer, pluginId: "core", version: "0.41.0" };
|
|
4319
|
+
var asciiFormatter2 = { ...asciiFormatter, pluginId: "core", version: "0.41.0" };
|
|
4320
|
+
var jsonFormatter2 = { ...jsonFormatter, pluginId: "core", version: "0.41.0" };
|
|
4321
|
+
var nodeBumpAction2 = { ...nodeBumpAction, pluginId: "core", version: "0.41.0" };
|
|
4322
|
+
var nodeSupersedeAction2 = { ...nodeSupersedeAction, pluginId: "core", version: "0.41.0" };
|
|
4323
|
+
var updateCheckHook2 = { ...updateCheckHook, pluginId: "core", version: "0.41.0" };
|
|
4324
4324
|
var builtInBundles = [
|
|
4325
4325
|
{
|
|
4326
4326
|
id: "claude",
|
|
@@ -4898,6 +4898,7 @@ var defaults_default = {
|
|
|
4898
4898
|
strict: false,
|
|
4899
4899
|
followSymlinks: false,
|
|
4900
4900
|
maxFileSizeBytes: 1048576,
|
|
4901
|
+
maxNodes: 256,
|
|
4901
4902
|
watch: {
|
|
4902
4903
|
debounceMs: 300
|
|
4903
4904
|
},
|
|
@@ -7037,6 +7038,8 @@ async function loadScanResult(db) {
|
|
|
7037
7038
|
roots: parseJsonArray(metaRow.rootsJson),
|
|
7038
7039
|
providers: parseJsonArray(metaRow.providersJson),
|
|
7039
7040
|
scannedBy,
|
|
7041
|
+
recommendedNodeLimit: metaRow.recommendedNodeLimit,
|
|
7042
|
+
overrideMaxNodes: metaRow.overrideMaxNodes,
|
|
7040
7043
|
nodes,
|
|
7041
7044
|
links,
|
|
7042
7045
|
issues,
|
|
@@ -7060,6 +7063,11 @@ async function loadScanResult(db) {
|
|
|
7060
7063
|
scannedAt,
|
|
7061
7064
|
roots: ["."],
|
|
7062
7065
|
providers: [],
|
|
7066
|
+
// Synthetic envelope, default to the design cap (256) so SPA reads
|
|
7067
|
+
// the same shape across cold-boot and pre-cap-aware DBs. A real
|
|
7068
|
+
// scan overwrites scan_meta with the live values on next run.
|
|
7069
|
+
recommendedNodeLimit: 256,
|
|
7070
|
+
overrideMaxNodes: null,
|
|
7063
7071
|
nodes,
|
|
7064
7072
|
links,
|
|
7065
7073
|
issues,
|
|
@@ -7645,7 +7653,14 @@ function metaToRow(result) {
|
|
|
7645
7653
|
providersJson: JSON.stringify(result.providers),
|
|
7646
7654
|
statsFilesWalked: result.stats.filesWalked,
|
|
7647
7655
|
statsFilesSkipped: result.stats.filesSkipped,
|
|
7648
|
-
statsDurationMs: result.stats.durationMs
|
|
7656
|
+
statsDurationMs: result.stats.durationMs,
|
|
7657
|
+
...projectNodeLimitColumns(result)
|
|
7658
|
+
};
|
|
7659
|
+
}
|
|
7660
|
+
function projectNodeLimitColumns(result) {
|
|
7661
|
+
return {
|
|
7662
|
+
recommendedNodeLimit: result.recommendedNodeLimit ?? 256,
|
|
7663
|
+
overrideMaxNodes: result.overrideMaxNodes ?? null
|
|
7649
7664
|
};
|
|
7650
7665
|
}
|
|
7651
7666
|
function extractorRunToRow(record) {
|
|
@@ -15673,17 +15688,26 @@ async function walkAndExtract(opts) {
|
|
|
15673
15688
|
const walkOptions = opts.ignoreFilter ? { ignoreFilter: opts.ignoreFilter } : {};
|
|
15674
15689
|
let filesWalked = 0;
|
|
15675
15690
|
let index = 0;
|
|
15691
|
+
const effectiveMaxNodes = opts.overrideMaxNodes ?? opts.recommendedNodeLimit;
|
|
15692
|
+
let capReached = false;
|
|
15676
15693
|
const activeProviders = opts.providers.filter((provider) => {
|
|
15677
15694
|
if (!provider.gatedByActiveLens) return true;
|
|
15678
15695
|
if (opts.activeProvider === null) return true;
|
|
15679
15696
|
return provider.id === opts.activeProvider;
|
|
15680
15697
|
});
|
|
15681
|
-
|
|
15698
|
+
const advance = async (raw, provider) => {
|
|
15699
|
+
const advanced = await processRawNode(raw, provider, wctx, accum, claimedPaths, index + 1);
|
|
15700
|
+
if (advanced) index += 1;
|
|
15701
|
+
};
|
|
15702
|
+
outer: for (const provider of activeProviders) {
|
|
15682
15703
|
for await (const raw of resolveProviderWalk(provider)(opts.roots, walkOptions)) {
|
|
15683
15704
|
filesWalked += 1;
|
|
15684
15705
|
if (claimedPaths.has(raw.path)) continue;
|
|
15685
|
-
|
|
15686
|
-
|
|
15706
|
+
if (accum.nodes.length >= effectiveMaxNodes) {
|
|
15707
|
+
capReached = true;
|
|
15708
|
+
break outer;
|
|
15709
|
+
}
|
|
15710
|
+
await advance(raw, provider);
|
|
15687
15711
|
}
|
|
15688
15712
|
}
|
|
15689
15713
|
const orphanSidecars = discoverOrphanSidecars(opts.roots);
|
|
@@ -15694,6 +15718,9 @@ async function walkAndExtract(opts) {
|
|
|
15694
15718
|
cachedPaths: accum.cachedPaths,
|
|
15695
15719
|
frontmatterIssues: accum.frontmatterIssues,
|
|
15696
15720
|
filesWalked,
|
|
15721
|
+
recommendedNodeLimit: opts.recommendedNodeLimit,
|
|
15722
|
+
overrideMaxNodes: opts.overrideMaxNodes,
|
|
15723
|
+
capReached,
|
|
15697
15724
|
enrichments: [...accum.enrichmentBuffer.values()],
|
|
15698
15725
|
extractorRuns: accum.extractorRuns,
|
|
15699
15726
|
contributions: accum.contributionsBuffer,
|
|
@@ -15972,7 +15999,9 @@ async function runScanInternal(_kernel, options) {
|
|
|
15972
15999
|
priorExtractorRuns: setup.priorExtractorRuns,
|
|
15973
16000
|
providerFrontmatter: setup.providerFrontmatter,
|
|
15974
16001
|
pluginStores: options.pluginStores,
|
|
15975
|
-
activeProvider: activeProviderId
|
|
16002
|
+
activeProvider: activeProviderId,
|
|
16003
|
+
recommendedNodeLimit: options.recommendedNodeLimit ?? 256,
|
|
16004
|
+
overrideMaxNodes: options.overrideMaxNodes ?? null
|
|
15976
16005
|
});
|
|
15977
16006
|
const activeProvider = activeProviderId ? exts.providers.find((p) => p.id === activeProviderId) ?? null : null;
|
|
15978
16007
|
const resolved = resolveSignals({
|
|
@@ -16140,6 +16169,8 @@ function buildScanReturn(walked, issues, renameOps, stats, options, setup) {
|
|
|
16140
16169
|
roots: options.roots,
|
|
16141
16170
|
providers: setup.exts.providers.map((a) => a.id),
|
|
16142
16171
|
scannedBy: SCANNED_BY,
|
|
16172
|
+
recommendedNodeLimit: walked.recommendedNodeLimit,
|
|
16173
|
+
overrideMaxNodes: walked.overrideMaxNodes,
|
|
16143
16174
|
nodes: walked.nodes,
|
|
16144
16175
|
links: walked.internalLinks,
|
|
16145
16176
|
issues,
|
|
@@ -16830,7 +16861,8 @@ async function runScanForCommand(opts) {
|
|
|
16830
16861
|
extensions,
|
|
16831
16862
|
referenceablePaths,
|
|
16832
16863
|
ctx.cwd,
|
|
16833
|
-
activeProvider
|
|
16864
|
+
activeProvider,
|
|
16865
|
+
cfg.scan.maxNodes
|
|
16834
16866
|
);
|
|
16835
16867
|
const willPersist = !opts.noBuiltIns && !opts.dryRun;
|
|
16836
16868
|
return willPersist ? runPersistPath(opts, dbPath, jobsDir, strict, loadPrior, runScanWith, extensions) : runEphemeralPath(opts, dbPath, strict, loadPrior, runScanWith);
|
|
@@ -16931,7 +16963,7 @@ function makePriorLoader(noBuiltIns, strict) {
|
|
|
16931
16963
|
return loaded;
|
|
16932
16964
|
};
|
|
16933
16965
|
}
|
|
16934
|
-
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider) {
|
|
16966
|
+
function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, extensions, referenceablePaths, scanCwd, activeProvider, recommendedNodeLimit) {
|
|
16935
16967
|
return async (prior, priorExtractorRuns, orphanJobFiles) => {
|
|
16936
16968
|
if (opts.changed && prior === null) {
|
|
16937
16969
|
opts.stderr.write(SCAN_RUNNER_TEXTS.changedNoPriorWarning);
|
|
@@ -16946,6 +16978,7 @@ function makeScanRunner(kernel, opts, effectiveRoots, ignoreFilter, strict, exte
|
|
|
16946
16978
|
cwd: scanCwd,
|
|
16947
16979
|
prior,
|
|
16948
16980
|
activeProvider,
|
|
16981
|
+
recommendedNodeLimit,
|
|
16949
16982
|
...priorExtractorRuns ? { priorExtractorRuns } : {},
|
|
16950
16983
|
...orphanJobFiles ? { orphanJobFiles } : {}
|
|
16951
16984
|
});
|
|
@@ -16959,15 +16992,15 @@ function buildRunScanOptions(args2) {
|
|
|
16959
16992
|
tokenize: !opts.noTokens,
|
|
16960
16993
|
ignoreFilter: args2.ignoreFilter,
|
|
16961
16994
|
strict: args2.strict,
|
|
16962
|
-
emitter: opts
|
|
16963
|
-
colorEnabled: opts.colorEnabled === true
|
|
16964
|
-
}),
|
|
16995
|
+
emitter: buildRunScanEmitter(opts),
|
|
16965
16996
|
// Orphan job-file detection, empty list means "no orphans
|
|
16966
16997
|
// visible from this caller" (legacy behaviour). The orchestrator
|
|
16967
16998
|
// defaults to `[]` when the field is absent; we always pass the
|
|
16968
16999
|
// array (possibly empty) to keep the wiring uniform.
|
|
16969
17000
|
orphanJobFiles: orphanJobFiles ?? [],
|
|
16970
|
-
activeProvider: args2.activeProvider
|
|
17001
|
+
activeProvider: args2.activeProvider,
|
|
17002
|
+
recommendedNodeLimit: args2.recommendedNodeLimit,
|
|
17003
|
+
overrideMaxNodes: opts.maxNodes ?? null
|
|
16971
17004
|
};
|
|
16972
17005
|
if (args2.extensions) runOptions.extensions = args2.extensions;
|
|
16973
17006
|
if (prior) {
|
|
@@ -16979,6 +17012,12 @@ function buildRunScanOptions(args2) {
|
|
|
16979
17012
|
runOptions.cwd = args2.cwd;
|
|
16980
17013
|
return runOptions;
|
|
16981
17014
|
}
|
|
17015
|
+
function buildRunScanEmitter(opts) {
|
|
17016
|
+
if (opts.emitterFactory) return opts.emitterFactory();
|
|
17017
|
+
return createStderrProgressEmitter(opts.stderr, {
|
|
17018
|
+
colorEnabled: opts.colorEnabled === true
|
|
17019
|
+
});
|
|
17020
|
+
}
|
|
16982
17021
|
async function runPersistPath(opts, dbPath, jobsDir, strict, loadPrior, runScanWith, extensions) {
|
|
16983
17022
|
let outcome;
|
|
16984
17023
|
try {
|
|
@@ -21004,6 +21043,22 @@ var SCAN_TEXTS = {
|
|
|
21004
21043
|
persistedTo: " {{dbPath}}\n",
|
|
21005
21044
|
/** Body line for dry-run mode, same indent, marker tail. */
|
|
21006
21045
|
wouldPersist: " would persist to {{dbPath}} (dry-run)\n",
|
|
21046
|
+
/**
|
|
21047
|
+
* Cap-hit notice, printed when the walker stopped accepting nodes
|
|
21048
|
+
* because `--max-nodes` (or the `scan.maxNodes` setting) was reached.
|
|
21049
|
+
* `{{glyph}}` is the yellow warning glyph, `{{limit}}` the effective
|
|
21050
|
+
* cap, `{{source}}` either `--max-nodes` or `scan.maxNodes`. The hint
|
|
21051
|
+
* names both escape routes the user has: trimming `.skillmapignore`
|
|
21052
|
+
* (preferred) or raising the cap with `--max-nodes <N>`.
|
|
21053
|
+
*/
|
|
21054
|
+
scanCappedNotice: "{{glyph}} Scan capped at {{limit}} nodes ({{source}}).\n {{hint}}\n",
|
|
21055
|
+
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.",
|
|
21056
|
+
/**
|
|
21057
|
+
* Validation message for an invalid `--max-nodes` value. Surfaced as a
|
|
21058
|
+
* §3.1b two-line block.
|
|
21059
|
+
*/
|
|
21060
|
+
maxNodesInvalid: "{{glyph}} --max-nodes must be an integer >= 1 (got `{{value}}`).\n {{hint}}\n",
|
|
21061
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256.",
|
|
21007
21062
|
// --- scan compare-with sub-verb --------------------------------------
|
|
21008
21063
|
compareErrorPrefix: "sm scan compare-with: {{message}}\n",
|
|
21009
21064
|
compareDumpNotFound: "dump file not found: {{path}}",
|
|
@@ -21167,7 +21222,9 @@ function createWatcherRuntime(opts) {
|
|
|
21167
21222
|
tokenize,
|
|
21168
21223
|
ignoreFilter,
|
|
21169
21224
|
strict,
|
|
21170
|
-
emitter
|
|
21225
|
+
emitter,
|
|
21226
|
+
recommendedNodeLimit: cfg.scan.maxNodes,
|
|
21227
|
+
overrideMaxNodes: opts.maxNodesOverride ?? null
|
|
21171
21228
|
};
|
|
21172
21229
|
if (cfg.scan.referencePaths.length > 0) {
|
|
21173
21230
|
const walk2 = walkReferencePaths(cfg.scan.referencePaths, cwd);
|
|
@@ -21380,7 +21437,12 @@ var WATCH_TEXTS = {
|
|
|
21380
21437
|
* accepted shape so the operator can re-run without `--help`.
|
|
21381
21438
|
*/
|
|
21382
21439
|
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)."
|
|
21440
|
+
maxConsecutiveFailuresInvalidHint: "Pass an integer >= 0 (0 disables the circuit-breaker; the default is 5).",
|
|
21441
|
+
/**
|
|
21442
|
+
* §3.1b two-line block. Validation rejection for `--max-nodes`.
|
|
21443
|
+
*/
|
|
21444
|
+
maxNodesInvalid: "{{glyph}} sm watch: --max-nodes must be an integer >= 1 (got {{raw}}).\n {{hint}}\n",
|
|
21445
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256."
|
|
21384
21446
|
};
|
|
21385
21447
|
|
|
21386
21448
|
// cli/commands/watch.ts
|
|
@@ -21443,6 +21505,7 @@ async function runWatchLoop(opts) {
|
|
|
21443
21505
|
circuitBreaker: { maxConsecutiveFailures: breakerLimit },
|
|
21444
21506
|
killSwitches: readConformanceKillSwitches(),
|
|
21445
21507
|
...opts.maxBatches !== void 0 ? { maxBatches: opts.maxBatches } : {},
|
|
21508
|
+
...opts.maxNodes !== void 0 ? { maxNodesOverride: opts.maxNodes } : {},
|
|
21446
21509
|
events: {
|
|
21447
21510
|
onBatch: (outcome) => {
|
|
21448
21511
|
if (outcome.kind === "ok") {
|
|
@@ -21556,6 +21619,10 @@ var WatchCommand = class extends SmCommand {
|
|
|
21556
21619
|
required: false,
|
|
21557
21620
|
description: "Shut down with exit 2 after N consecutive batch failures (default 5; 0 disables the breaker)."
|
|
21558
21621
|
});
|
|
21622
|
+
maxNodes = Option28.String("--max-nodes", {
|
|
21623
|
+
required: false,
|
|
21624
|
+
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."
|
|
21625
|
+
});
|
|
21559
21626
|
// Long-running verb, the watcher prints its own "stopped" line on
|
|
21560
21627
|
// SIGINT / SIGTERM. Adding `done in <…>` after that would be noise.
|
|
21561
21628
|
emitElapsed = false;
|
|
@@ -21563,6 +21630,8 @@ var WatchCommand = class extends SmCommand {
|
|
|
21563
21630
|
const roots = this.roots.length > 0 ? this.roots : ["."];
|
|
21564
21631
|
const breaker = parseBreakerLimit(this.maxConsecutiveFailures, this.context.stderr, this.noColor);
|
|
21565
21632
|
if (breaker === null) return ExitCode.Error;
|
|
21633
|
+
const maxNodes = parseMaxNodesLimit(this.maxNodes, this.context.stderr, this.noColor);
|
|
21634
|
+
if (maxNodes === null) return ExitCode.Error;
|
|
21566
21635
|
const watchOpts = {
|
|
21567
21636
|
roots,
|
|
21568
21637
|
json: this.json,
|
|
@@ -21575,6 +21644,7 @@ var WatchCommand = class extends SmCommand {
|
|
|
21575
21644
|
printer: this.printer
|
|
21576
21645
|
};
|
|
21577
21646
|
if (breaker !== void 0) watchOpts.maxConsecutiveFailures = breaker;
|
|
21647
|
+
if (maxNodes !== void 0) watchOpts.maxNodes = maxNodes;
|
|
21578
21648
|
return runWatchLoop(watchOpts);
|
|
21579
21649
|
}
|
|
21580
21650
|
};
|
|
@@ -21595,6 +21665,23 @@ function parseBreakerLimit(raw, stderr, noColor) {
|
|
|
21595
21665
|
}
|
|
21596
21666
|
return parsed;
|
|
21597
21667
|
}
|
|
21668
|
+
function parseMaxNodesLimit(raw, stderr, noColor) {
|
|
21669
|
+
if (raw === void 0) return void 0;
|
|
21670
|
+
const n = Number(raw);
|
|
21671
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
21672
|
+
const stderrTty = stderr;
|
|
21673
|
+
const ansi = ansiFor({ isTTY: stderrTty.isTTY === true, noColorFlag: noColor });
|
|
21674
|
+
stderr.write(
|
|
21675
|
+
tx(WATCH_TEXTS.maxNodesInvalid, {
|
|
21676
|
+
glyph: ansi.red("\u2715"),
|
|
21677
|
+
raw,
|
|
21678
|
+
hint: ansi.dim(WATCH_TEXTS.maxNodesInvalidHint)
|
|
21679
|
+
})
|
|
21680
|
+
);
|
|
21681
|
+
return null;
|
|
21682
|
+
}
|
|
21683
|
+
return n;
|
|
21684
|
+
}
|
|
21598
21685
|
|
|
21599
21686
|
// cli/commands/scan.ts
|
|
21600
21687
|
var ScanCommand = class extends SmCommand {
|
|
@@ -21662,10 +21749,16 @@ var ScanCommand = class extends SmCommand {
|
|
|
21662
21749
|
yes = Option29.Boolean("--yes", false, {
|
|
21663
21750
|
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
21751
|
});
|
|
21752
|
+
maxNodes = Option29.String("--max-nodes", {
|
|
21753
|
+
required: false,
|
|
21754
|
+
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."
|
|
21755
|
+
});
|
|
21665
21756
|
// Each branch in the orchestrator maps to one validation gate
|
|
21666
21757
|
// (--watch alias / --changed mutex / -g mutex / dispatch).
|
|
21667
21758
|
// Splitting per branch scatters the gate from the value it gates.
|
|
21668
21759
|
async run() {
|
|
21760
|
+
const parsedMaxNodes = this.parseMaxNodesFlag();
|
|
21761
|
+
if (parsedMaxNodes.kind === "error") return parsedMaxNodes.exit;
|
|
21669
21762
|
if (this.watch) return this.runWatchAlias();
|
|
21670
21763
|
if (this.changed && this.noBuiltIns) {
|
|
21671
21764
|
const ansi = this.ansiFor("stderr");
|
|
@@ -21701,10 +21794,33 @@ var ScanCommand = class extends SmCommand {
|
|
|
21701
21794
|
killSwitches: readConformanceKillSwitches(),
|
|
21702
21795
|
colorEnabled,
|
|
21703
21796
|
yes: this.yes,
|
|
21704
|
-
style
|
|
21797
|
+
style,
|
|
21798
|
+
...parsedMaxNodes.value !== void 0 ? { maxNodes: parsedMaxNodes.value } : {}
|
|
21705
21799
|
});
|
|
21706
21800
|
return outcome.kind === "ok" ? this.renderOutcome(outcome.result, outcome.persistedTo, outcome.dbPath, outcome.strict) : this.renderFailure(outcome);
|
|
21707
21801
|
}
|
|
21802
|
+
/**
|
|
21803
|
+
* Parse `--max-nodes <N>`. Returns either the integer value (or
|
|
21804
|
+
* `undefined` when the flag was omitted) or an error sentinel after
|
|
21805
|
+
* printing the validation block. Invalid (non-integer, < 1) exits 2
|
|
21806
|
+
* per spec/cli-contract.md §Node cap.
|
|
21807
|
+
*/
|
|
21808
|
+
parseMaxNodesFlag() {
|
|
21809
|
+
if (this.maxNodes === void 0) return { kind: "ok", value: void 0 };
|
|
21810
|
+
const n = Number(this.maxNodes);
|
|
21811
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
21812
|
+
const ansi = this.ansiFor("stderr");
|
|
21813
|
+
this.printer.info(
|
|
21814
|
+
tx(SCAN_TEXTS.maxNodesInvalid, {
|
|
21815
|
+
glyph: ansi.red("\u2715"),
|
|
21816
|
+
value: this.maxNodes,
|
|
21817
|
+
hint: ansi.dim(SCAN_TEXTS.maxNodesInvalidHint)
|
|
21818
|
+
})
|
|
21819
|
+
);
|
|
21820
|
+
return { kind: "error", exit: ExitCode.Error };
|
|
21821
|
+
}
|
|
21822
|
+
return { kind: "ok", value: n };
|
|
21823
|
+
}
|
|
21708
21824
|
/**
|
|
21709
21825
|
* `--watch` is a thin alias for the `sm watch` verb. Combining
|
|
21710
21826
|
* `--watch` with one-shot-only flags is incoherent, the watcher
|
|
@@ -21724,6 +21840,7 @@ var ScanCommand = class extends SmCommand {
|
|
|
21724
21840
|
}
|
|
21725
21841
|
this.emitElapsed = false;
|
|
21726
21842
|
const roots = this.roots.length > 0 ? this.roots : ["."];
|
|
21843
|
+
const parsedMaxNodes = this.parseMaxNodesFlag();
|
|
21727
21844
|
return runWatchLoop({
|
|
21728
21845
|
roots,
|
|
21729
21846
|
json: this.json,
|
|
@@ -21733,7 +21850,8 @@ var ScanCommand = class extends SmCommand {
|
|
|
21733
21850
|
db: this.db,
|
|
21734
21851
|
noPlugins: this.noPlugins,
|
|
21735
21852
|
context: this.context,
|
|
21736
|
-
printer: this.printer
|
|
21853
|
+
printer: this.printer,
|
|
21854
|
+
...parsedMaxNodes.kind === "ok" && parsedMaxNodes.value !== void 0 ? { maxNodes: parsedMaxNodes.value } : {}
|
|
21737
21855
|
});
|
|
21738
21856
|
}
|
|
21739
21857
|
/**
|
|
@@ -21820,8 +21938,32 @@ var ScanCommand = class extends SmCommand {
|
|
|
21820
21938
|
})
|
|
21821
21939
|
);
|
|
21822
21940
|
}
|
|
21941
|
+
this.maybePrintCapNotice(result, ansi);
|
|
21823
21942
|
return exitCode2;
|
|
21824
21943
|
}
|
|
21944
|
+
/**
|
|
21945
|
+
* Surface the §Node cap notice when the walker actually stopped
|
|
21946
|
+
* accepting files because of the cap. Derivation: `filesWalked >
|
|
21947
|
+
* effectiveLimit` means the walker incremented past the cap at least
|
|
21948
|
+
* once (i.e. classified the (limit+1)-th raw before breaking). When
|
|
21949
|
+
* the project has EXACTLY the cap many files the loop ends naturally
|
|
21950
|
+
* without ever firing the break, so the notice stays silent.
|
|
21951
|
+
*/
|
|
21952
|
+
maybePrintCapNotice(result, ansi) {
|
|
21953
|
+
const recommended = result.recommendedNodeLimit;
|
|
21954
|
+
if (recommended === void 0) return;
|
|
21955
|
+
const override = result.overrideMaxNodes ?? null;
|
|
21956
|
+
const effectiveLimit = override ?? recommended;
|
|
21957
|
+
if (result.stats.filesWalked <= effectiveLimit) return;
|
|
21958
|
+
this.printer.info(
|
|
21959
|
+
tx(SCAN_TEXTS.scanCappedNotice, {
|
|
21960
|
+
glyph: ansi.yellow("\u26A0"),
|
|
21961
|
+
limit: String(effectiveLimit),
|
|
21962
|
+
source: override !== null ? "--max-nodes" : "scan.maxNodes",
|
|
21963
|
+
hint: ansi.dim(SCAN_TEXTS.scanCappedNoticeHint)
|
|
21964
|
+
})
|
|
21965
|
+
);
|
|
21966
|
+
}
|
|
21825
21967
|
/**
|
|
21826
21968
|
* `--json` output path. Under `--strict` (H4) self-validates the
|
|
21827
21969
|
* ScanResult against `scan-result.schema.json` before emitting it,
|
|
@@ -24285,6 +24427,9 @@ function createWatcherService(opts) {
|
|
|
24285
24427
|
if (opts.debounceMsOverride !== void 0) {
|
|
24286
24428
|
runtimeOpts.debounceMsOverride = opts.debounceMsOverride;
|
|
24287
24429
|
}
|
|
24430
|
+
if (opts.options.maxNodes !== void 0) {
|
|
24431
|
+
runtimeOpts.maxNodesOverride = opts.options.maxNodes;
|
|
24432
|
+
}
|
|
24288
24433
|
return runtimeOpts;
|
|
24289
24434
|
};
|
|
24290
24435
|
return {
|
|
@@ -24362,7 +24507,11 @@ async function runPersistedScan(c, deps) {
|
|
|
24362
24507
|
// BFF has no TTY; ambiguous activeProvider must be resolved by
|
|
24363
24508
|
// the operator via the Settings UI (PATCH /api/active-provider)
|
|
24364
24509
|
// before the scan, not via interactive prompt here.
|
|
24365
|
-
yes: true
|
|
24510
|
+
yes: true,
|
|
24511
|
+
// `--max-nodes` from the `sm serve` invocation (or the bare
|
|
24512
|
+
// `sm --max-nodes <N>` shortcut) flows through to every scan
|
|
24513
|
+
// the BFF runs so the override is honoured end-to-end.
|
|
24514
|
+
...deps.options.maxNodes !== void 0 ? { maxNodes: deps.options.maxNodes } : {}
|
|
24366
24515
|
});
|
|
24367
24516
|
if (outcome.kind !== "ok") {
|
|
24368
24517
|
throw new HTTPException13(500, {
|
|
@@ -24466,7 +24615,10 @@ async function runFreshScan(deps) {
|
|
|
24466
24615
|
printer: bffScanRunnerPrinter,
|
|
24467
24616
|
// BFF has no TTY; ambiguous activeProvider is the operator's
|
|
24468
24617
|
// problem to resolve via the Settings UI, not via prompt here.
|
|
24469
|
-
yes: true
|
|
24618
|
+
yes: true,
|
|
24619
|
+
// Carry `--max-nodes` from `sm serve` into the fresh-scan path
|
|
24620
|
+
// too so a UI-driven refresh honours the same cap as the watcher.
|
|
24621
|
+
...deps.options.maxNodes !== void 0 ? { maxNodes: deps.options.maxNodes } : {}
|
|
24470
24622
|
});
|
|
24471
24623
|
if (outcome.kind !== "ok") {
|
|
24472
24624
|
throw new HTTPException13(500, {
|
|
@@ -24488,6 +24640,12 @@ function emptyScanResult() {
|
|
|
24488
24640
|
scannedAt: Date.now(),
|
|
24489
24641
|
roots: ["."],
|
|
24490
24642
|
providers: [],
|
|
24643
|
+
// Surface the design default so the SPA reads the same field shape
|
|
24644
|
+
// on cold boot as on populated DBs. 256 mirrors `scan.maxNodes`
|
|
24645
|
+
// from `src/config/defaults.json`; the temporary testing default
|
|
24646
|
+
// (2) only applies after a real scan walks through the kernel.
|
|
24647
|
+
recommendedNodeLimit: 256,
|
|
24648
|
+
overrideMaxNodes: null,
|
|
24491
24649
|
nodes: [],
|
|
24492
24650
|
links: [],
|
|
24493
24651
|
issues: [],
|
|
@@ -25200,6 +25358,8 @@ function validateServerOptions(input) {
|
|
|
25200
25358
|
if (watcherError !== null) return { ok: false, error: watcherError };
|
|
25201
25359
|
const debounceError = validateWatcherDebounce(input.watcherDebounceMs);
|
|
25202
25360
|
if (debounceError !== null) return { ok: false, error: debounceError };
|
|
25361
|
+
const maxNodesError = validateMaxNodes(input.maxNodes);
|
|
25362
|
+
if (maxNodesError !== null) return { ok: false, error: maxNodesError };
|
|
25203
25363
|
const noUiError = validateNoUi(filled.noUi, filled.uiDist);
|
|
25204
25364
|
if (noUiError !== null) return { ok: false, error: noUiError };
|
|
25205
25365
|
const options = {
|
|
@@ -25217,6 +25377,9 @@ function validateServerOptions(input) {
|
|
|
25217
25377
|
if (input.watcherDebounceMs !== void 0) {
|
|
25218
25378
|
options.watcherDebounceMs = input.watcherDebounceMs;
|
|
25219
25379
|
}
|
|
25380
|
+
if (input.maxNodes !== void 0) {
|
|
25381
|
+
options.maxNodes = input.maxNodes;
|
|
25382
|
+
}
|
|
25220
25383
|
return { ok: true, options };
|
|
25221
25384
|
}
|
|
25222
25385
|
function applyDefaults(input) {
|
|
@@ -25277,6 +25440,17 @@ function validateWatcherDebounce(value) {
|
|
|
25277
25440
|
}
|
|
25278
25441
|
return null;
|
|
25279
25442
|
}
|
|
25443
|
+
function validateMaxNodes(value) {
|
|
25444
|
+
if (value === void 0) return null;
|
|
25445
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
25446
|
+
return {
|
|
25447
|
+
code: "max-nodes-invalid",
|
|
25448
|
+
message: `--max-nodes must be an integer >= 1 (got ${value})`,
|
|
25449
|
+
value: String(value)
|
|
25450
|
+
};
|
|
25451
|
+
}
|
|
25452
|
+
return null;
|
|
25453
|
+
}
|
|
25280
25454
|
function validateNoUi(noUi, uiDist) {
|
|
25281
25455
|
if (noUi && uiDist !== null) {
|
|
25282
25456
|
return {
|
|
@@ -25556,6 +25730,12 @@ var SERVE_TEXTS = {
|
|
|
25556
25730
|
*/
|
|
25557
25731
|
watcherDebounceInvalid: "{{glyph}} sm serve: --watcher-debounce-ms must be a non-negative integer (got {{value}}).\n {{hint}}\n",
|
|
25558
25732
|
watcherDebounceInvalidHint: "Pass an integer >= 0 (e.g. 250).",
|
|
25733
|
+
/**
|
|
25734
|
+
* §3.1b error block for an invalid `--max-nodes <N>`. Same shape as
|
|
25735
|
+
* the watcher-debounce template family.
|
|
25736
|
+
*/
|
|
25737
|
+
maxNodesInvalid: "{{glyph}} sm serve: --max-nodes must be an integer >= 1 (got {{value}}).\n {{hint}}\n",
|
|
25738
|
+
maxNodesInvalidHint: "Pass a positive integer, e.g. --max-nodes 256.",
|
|
25559
25739
|
// --- --no-ui flag-validation failures (ExitCode.Error) ------------------
|
|
25560
25740
|
/**
|
|
25561
25741
|
* §3.1b error block when `--no-ui` is paired with an explicit
|
|
@@ -25825,6 +26005,10 @@ var ServeCommand = class extends SmCommand {
|
|
|
25825
26005
|
// who want to tighten / relax the watcher's batching window without
|
|
25826
26006
|
// editing settings.json. Hidden flag, the Usage block omits it.
|
|
25827
26007
|
watcherDebounceMs = Option31.String("--watcher-debounce-ms", { required: false, hidden: true });
|
|
26008
|
+
maxNodes = Option31.String("--max-nodes", {
|
|
26009
|
+
required: false,
|
|
26010
|
+
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`."
|
|
26011
|
+
});
|
|
25828
26012
|
// Long-running daemon, `done in <…>` after a graceful shutdown is
|
|
25829
26013
|
// noise. Mirrors `sm watch`'s opt-out.
|
|
25830
26014
|
emitElapsed = false;
|
|
@@ -25903,6 +26087,17 @@ var ServeCommand = class extends SmCommand {
|
|
|
25903
26087
|
);
|
|
25904
26088
|
return ExitCode.Error;
|
|
25905
26089
|
}
|
|
26090
|
+
const maxNodesResult = parseMaxNodes(this.maxNodes);
|
|
26091
|
+
if (!maxNodesResult.ok) {
|
|
26092
|
+
this.printer.info(
|
|
26093
|
+
tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
26094
|
+
glyph: errGlyph,
|
|
26095
|
+
value: sanitizeForTerminal(maxNodesResult.value),
|
|
26096
|
+
hint: stderrAnsi.dim(SERVE_TEXTS.maxNodesInvalidHint)
|
|
26097
|
+
})
|
|
26098
|
+
);
|
|
26099
|
+
return ExitCode.Error;
|
|
26100
|
+
}
|
|
25906
26101
|
const input = {
|
|
25907
26102
|
dbPath,
|
|
25908
26103
|
uiDist: resolvedUiDist,
|
|
@@ -25916,6 +26111,7 @@ var ServeCommand = class extends SmCommand {
|
|
|
25916
26111
|
if (portResult.port !== void 0) input.port = portResult.port;
|
|
25917
26112
|
if (this.host !== void 0) input.host = this.host;
|
|
25918
26113
|
if (debounceResult.value !== void 0) input.watcherDebounceMs = debounceResult.value;
|
|
26114
|
+
if (maxNodesResult.value !== void 0) input.maxNodes = maxNodesResult.value;
|
|
25919
26115
|
const validation = validateServerOptions(input);
|
|
25920
26116
|
if (!validation.ok) {
|
|
25921
26117
|
this.printer.info(formatValidationError(validation.error, stderrAnsi));
|
|
@@ -25985,6 +26181,12 @@ function parseDebounce(raw) {
|
|
|
25985
26181
|
if (parsed === null) return { ok: false, value: raw };
|
|
25986
26182
|
return { ok: true, value: parsed };
|
|
25987
26183
|
}
|
|
26184
|
+
function parseMaxNodes(raw) {
|
|
26185
|
+
if (raw === void 0) return { ok: true, value: void 0 };
|
|
26186
|
+
const n = Number(raw);
|
|
26187
|
+
if (!Number.isInteger(n) || n < 1) return { ok: false, value: raw };
|
|
26188
|
+
return { ok: true, value: n };
|
|
26189
|
+
}
|
|
25988
26190
|
function resolveUiDist(ctx, raw) {
|
|
25989
26191
|
if (raw === void 0) {
|
|
25990
26192
|
return { ok: true, uiDist: resolveDefaultUiDist(ctx) };
|
|
@@ -26031,6 +26233,12 @@ function formatValidationError(err, ansi) {
|
|
|
26031
26233
|
value: sanitizeForTerminal(err.value),
|
|
26032
26234
|
hint: ansi.dim(SERVE_TEXTS.watcherDebounceInvalidHint)
|
|
26033
26235
|
});
|
|
26236
|
+
case "max-nodes-invalid":
|
|
26237
|
+
return tx(SERVE_TEXTS.maxNodesInvalid, {
|
|
26238
|
+
glyph: errGlyph,
|
|
26239
|
+
value: sanitizeForTerminal(err.value),
|
|
26240
|
+
hint: ansi.dim(SERVE_TEXTS.maxNodesInvalidHint)
|
|
26241
|
+
});
|
|
26034
26242
|
case "no-ui-conflicts-ui-dist":
|
|
26035
26243
|
return tx(SERVE_TEXTS.noUiConflictsUiDist, {
|
|
26036
26244
|
glyph: errGlyph,
|
|
@@ -27409,7 +27617,7 @@ var logLevel = resolveLogLevel({
|
|
|
27409
27617
|
errStream: process.stderr
|
|
27410
27618
|
});
|
|
27411
27619
|
configureLogger(new Logger({ level: logLevel, stream: process.stderr }));
|
|
27412
|
-
var bareArgs = args
|
|
27620
|
+
var bareArgs = resolveBareInvocation(args);
|
|
27413
27621
|
var routedArgs = routeHelpArgs(bareArgs ?? args, cli);
|
|
27414
27622
|
var lifecycleDispatcher = makeHookDispatcher(
|
|
27415
27623
|
builtIns().hooks ?? [],
|
|
@@ -27452,6 +27660,20 @@ await lifecycleDispatcher.dispatch(
|
|
|
27452
27660
|
makeEvent("shutdown", { exitCode })
|
|
27453
27661
|
);
|
|
27454
27662
|
process.exit(exitCode);
|
|
27663
|
+
function resolveBareInvocation(rawArgs) {
|
|
27664
|
+
if (rawArgs.length === 0) return resolveBareDefault();
|
|
27665
|
+
const first = rawArgs[0];
|
|
27666
|
+
const passthrough = /* @__PURE__ */ new Set(["--help", "-h", "--version", "-V", "-v"]);
|
|
27667
|
+
if (first !== void 0 && first.startsWith("-") && !passthrough.has(first)) {
|
|
27668
|
+
const isSingleDashLong = !first.startsWith("--") && first.length > 2;
|
|
27669
|
+
if (isSingleDashLong) return null;
|
|
27670
|
+
if (existsSync30(defaultProjectDbPath(defaultRuntimeContext()))) {
|
|
27671
|
+
return ["serve", ...rawArgs];
|
|
27672
|
+
}
|
|
27673
|
+
return resolveBareDefault();
|
|
27674
|
+
}
|
|
27675
|
+
return null;
|
|
27676
|
+
}
|
|
27455
27677
|
function resolveBareDefault() {
|
|
27456
27678
|
const ctx = defaultRuntimeContext();
|
|
27457
27679
|
if (existsSync30(defaultProjectDbPath(ctx))) {
|