@vibgrate/cli 2026.813.1 → 2026.814.2

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.
Files changed (123) hide show
  1. package/DOCS.md +258 -22
  2. package/NOTICE +7 -0
  3. package/README.md +273 -11
  4. package/dist/agent-5ANHRYEI.js +26 -0
  5. package/dist/{agent-N3CP3SPI.js.map → agent-5ANHRYEI.js.map} +1 -1
  6. package/dist/approvals-T2KXPJLV.js +9 -0
  7. package/dist/approvals-T2KXPJLV.js.map +1 -0
  8. package/dist/baseline-WVD6P5IO.js +9 -0
  9. package/dist/{baseline-ZMRZRGFI.js.map → baseline-WVD6P5IO.js.map} +1 -1
  10. package/dist/{checkpoint-4WFZMKEO.js → checkpoint-UYMYMMQO.js} +6 -3
  11. package/dist/checkpoint-UYMYMMQO.js.map +1 -0
  12. package/dist/chunk-2H2U3DC7.js +6 -0
  13. package/dist/{chunk-RT7P5AYU.js.map → chunk-2H2U3DC7.js.map} +1 -1
  14. package/dist/chunk-2U37PFB2.js +64 -0
  15. package/dist/chunk-2U37PFB2.js.map +1 -0
  16. package/dist/{chunk-GOPANQZT.js → chunk-54RGT2T5.js} +3 -3
  17. package/dist/{chunk-GOPANQZT.js.map → chunk-54RGT2T5.js.map} +1 -1
  18. package/dist/{chunk-OYHAF2J2.js → chunk-5GLQNMTI.js} +5 -5
  19. package/dist/{chunk-OYHAF2J2.js.map → chunk-5GLQNMTI.js.map} +1 -1
  20. package/dist/{chunk-EWZKOU66.js → chunk-75LJM5XD.js} +30 -66
  21. package/dist/chunk-75LJM5XD.js.map +1 -0
  22. package/dist/{chunk-KF2QT6RY.js → chunk-7NMXE6KG.js} +4 -4
  23. package/dist/{chunk-KF2QT6RY.js.map → chunk-7NMXE6KG.js.map} +1 -1
  24. package/dist/{chunk-UZP623Y4.js → chunk-7QDHQLUS.js} +4 -4
  25. package/dist/{chunk-UZP623Y4.js.map → chunk-7QDHQLUS.js.map} +1 -1
  26. package/dist/chunk-AJS4EL2C.js +266 -0
  27. package/dist/chunk-AJS4EL2C.js.map +1 -0
  28. package/dist/{chunk-Z3MUWXP3.js → chunk-BH54SLGZ.js} +4 -4
  29. package/dist/{chunk-Z3MUWXP3.js.map → chunk-BH54SLGZ.js.map} +1 -1
  30. package/dist/{chunk-CJNWHXQD.js → chunk-DSUGC7F5.js} +4 -4
  31. package/dist/{chunk-CJNWHXQD.js.map → chunk-DSUGC7F5.js.map} +1 -1
  32. package/dist/{chunk-FBVKQXBH.js → chunk-FOW5IF73.js} +3 -3
  33. package/dist/{chunk-FBVKQXBH.js.map → chunk-FOW5IF73.js.map} +1 -1
  34. package/dist/{chunk-6GQLEDVK.js → chunk-IHLLWBZU.js} +6 -5
  35. package/dist/chunk-IHLLWBZU.js.map +1 -0
  36. package/dist/{chunk-RHKJPTON.js → chunk-IHXNOY3R.js} +208 -56
  37. package/dist/chunk-IHXNOY3R.js.map +1 -0
  38. package/dist/{chunk-5JJBGBP2.js → chunk-JCN6MSXQ.js} +7 -7
  39. package/dist/{chunk-5JJBGBP2.js.map → chunk-JCN6MSXQ.js.map} +1 -1
  40. package/dist/{chunk-YJU7S7N6.js → chunk-KGPX4EUN.js} +4 -4
  41. package/dist/{chunk-YJU7S7N6.js.map → chunk-KGPX4EUN.js.map} +1 -1
  42. package/dist/{chunk-ADP6ITGF.js → chunk-N3XFY3PX.js} +68 -11
  43. package/dist/chunk-N3XFY3PX.js.map +1 -0
  44. package/dist/{chunk-JYM4QT6F.js → chunk-NKFXXP6W.js} +5 -5
  45. package/dist/{chunk-JYM4QT6F.js.map → chunk-NKFXXP6W.js.map} +1 -1
  46. package/dist/{chunk-5ROZODMW.js → chunk-TFAXW7VM.js} +2 -2
  47. package/dist/chunk-TFAXW7VM.js.map +1 -0
  48. package/dist/{chunk-6423BHLN.js → chunk-TNROG5CO.js} +19 -9
  49. package/dist/chunk-TNROG5CO.js.map +1 -0
  50. package/dist/chunk-TVDYEHIM.js +174 -0
  51. package/dist/chunk-TVDYEHIM.js.map +1 -0
  52. package/dist/{chunk-7ZHSSGUF.js → chunk-WQLZSVNF.js} +4 -3
  53. package/dist/chunk-WQLZSVNF.js.map +1 -0
  54. package/dist/{chunk-3WUTQYRY.js → chunk-WWGLVF7D.js} +9 -8
  55. package/dist/chunk-WWGLVF7D.js.map +1 -0
  56. package/dist/{chunk-KBP7GJV6.js → chunk-X76VPOYH.js} +19 -9
  57. package/dist/chunk-X76VPOYH.js.map +1 -0
  58. package/dist/{chunk-IJQOZ6ZD.js → chunk-YNV5M3JW.js} +8 -8
  59. package/dist/chunk-YNV5M3JW.js.map +1 -0
  60. package/dist/{chunk-Z3AYOZ3C.js → chunk-YQNTIBKS.js} +6 -6
  61. package/dist/{chunk-Z3AYOZ3C.js.map → chunk-YQNTIBKS.js.map} +1 -1
  62. package/dist/cli.js +1130 -489
  63. package/dist/cli.js.map +1 -1
  64. package/dist/embed-worker-main.js +4 -3
  65. package/dist/embed-worker-main.js.map +1 -1
  66. package/dist/{ensure-map-PHAJACFF.js → ensure-map-HQ7A5NDL.js} +15 -14
  67. package/dist/{ensure-map-PHAJACFF.js.map → ensure-map-HQ7A5NDL.js.map} +1 -1
  68. package/dist/fastembed-S6YEJYQV.js +292 -0
  69. package/dist/fastembed-S6YEJYQV.js.map +1 -0
  70. package/dist/graph-backend-W2TNTMY7.js +14 -0
  71. package/dist/{graph-backend-4B3MTVIW.js.map → graph-backend-W2TNTMY7.js.map} +1 -1
  72. package/dist/index.d.ts +4 -3
  73. package/dist/index.js +14 -13
  74. package/dist/index.js.map +1 -1
  75. package/dist/{interactive-WUXMXFNM.js → interactive-EW2VJ3BZ.js} +32 -30
  76. package/dist/interactive-EW2VJ3BZ.js.map +1 -0
  77. package/dist/load-64RK5O6C.js +10 -0
  78. package/dist/{load-EUZSV73H.js.map → load-64RK5O6C.js.map} +1 -1
  79. package/dist/{run-outcome-O5PR7ZCK.js → run-outcome-6QNQIHPV.js} +6 -5
  80. package/dist/run-outcome-6QNQIHPV.js.map +1 -0
  81. package/dist/runtime-session-RJHH3KMF.js +21 -0
  82. package/dist/{runtime-session-PPQDTFIK.js.map → runtime-session-RJHH3KMF.js.map} +1 -1
  83. package/dist/session-4BGYASOH.js +16 -0
  84. package/dist/{session-WS7SOVJE.js.map → session-4BGYASOH.js.map} +1 -1
  85. package/dist/session-store-AQUORKWB.js +4 -0
  86. package/dist/{session-store-KGONLWHN.js.map → session-store-AQUORKWB.js.map} +1 -1
  87. package/dist/{stream-json-7MK3QQYG.js → stream-json-GY5N7WZT.js} +76 -24
  88. package/dist/stream-json-GY5N7WZT.js.map +1 -0
  89. package/dist/version-DPAMQW6M.js +4 -0
  90. package/dist/version-DPAMQW6M.js.map +1 -0
  91. package/dist/{vg-mcp-bridge-DQLCHBI6.js → vg-mcp-bridge-IGHJKKSL.js} +11 -10
  92. package/dist/vg-mcp-bridge-IGHJKKSL.js.map +1 -0
  93. package/dist/{vgd-Y25XSQGZ.js → vgd-ORPA5C2K.js} +12 -11
  94. package/dist/vgd-ORPA5C2K.js.map +1 -0
  95. package/dist/worktree-session-D575IQWM.js +82 -0
  96. package/dist/worktree-session-D575IQWM.js.map +1 -0
  97. package/package.json +4 -2
  98. package/dist/agent-N3CP3SPI.js +0 -24
  99. package/dist/baseline-ZMRZRGFI.js +0 -9
  100. package/dist/checkpoint-4WFZMKEO.js.map +0 -1
  101. package/dist/chunk-3WUTQYRY.js.map +0 -1
  102. package/dist/chunk-5ROZODMW.js.map +0 -1
  103. package/dist/chunk-6423BHLN.js.map +0 -1
  104. package/dist/chunk-6GQLEDVK.js.map +0 -1
  105. package/dist/chunk-7ZHSSGUF.js.map +0 -1
  106. package/dist/chunk-ADP6ITGF.js.map +0 -1
  107. package/dist/chunk-EWZKOU66.js.map +0 -1
  108. package/dist/chunk-IJQOZ6ZD.js.map +0 -1
  109. package/dist/chunk-KBP7GJV6.js.map +0 -1
  110. package/dist/chunk-RHKJPTON.js.map +0 -1
  111. package/dist/chunk-RT7P5AYU.js +0 -6
  112. package/dist/chunk-Z7FM3ETS.js +0 -126
  113. package/dist/chunk-Z7FM3ETS.js.map +0 -1
  114. package/dist/graph-backend-4B3MTVIW.js +0 -13
  115. package/dist/interactive-WUXMXFNM.js.map +0 -1
  116. package/dist/load-EUZSV73H.js +0 -9
  117. package/dist/run-outcome-O5PR7ZCK.js.map +0 -1
  118. package/dist/runtime-session-PPQDTFIK.js +0 -20
  119. package/dist/session-WS7SOVJE.js +0 -15
  120. package/dist/session-store-KGONLWHN.js +0 -4
  121. package/dist/stream-json-7MK3QQYG.js.map +0 -1
  122. package/dist/vg-mcp-bridge-DQLCHBI6.js.map +0 -1
  123. package/dist/vgd-Y25XSQGZ.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,59 +1,61 @@
1
1
  #!/usr/bin/env node
2
- import { loadAdvancedScanHook, baselineCommand } from './chunk-5ROZODMW.js';
3
- import { fetchCatalog, resolveProviders } from './chunk-OYHAF2J2.js';
4
- import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-JYM4QT6F.js';
2
+ import { fetchCatalog, resolveProviders } from './chunk-5GLQNMTI.js';
3
+ import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-7NMXE6KG.js';
4
+ import { loadAdvancedScanHook, baselineCommand } from './chunk-TFAXW7VM.js';
5
+ import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-JCN6MSXQ.js';
6
+ export { runBuild } from './chunk-JCN6MSXQ.js';
7
+ import { disableColor, info, c, json, out } from './chunk-CT5BS56U.js';
8
+ import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-NKFXXP6W.js';
5
9
  import './chunk-IS7VTH2Q.js';
6
- import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-KF2QT6RY.js';
7
- import { runCodeSession } from './chunk-Z3AYOZ3C.js';
8
- import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-RHKJPTON.js';
10
+ import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-JFE7XCAE.js';
11
+ import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-3LOWJSAF.js';
12
+ import { runCodeSession } from './chunk-YQNTIBKS.js';
13
+ import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-IHXNOY3R.js';
9
14
  import './chunk-543E6WDJ.js';
10
- import { summarizeDiffs, ScriptedProvider } from './chunk-ADP6ITGF.js';
15
+ import './chunk-TVDYEHIM.js';
16
+ import './chunk-54RGT2T5.js';
17
+ import { vgdSocketPath, vgdIsRunning, vgdRequest, vgdPidPath } from './chunk-RBIRXQR6.js';
18
+ import { buildIdentifierTrieFromGraph } from './chunk-5HYCB55P.js';
19
+ import { parseReasoningEffort, summarizeDiffs, ScriptedProvider } from './chunk-N3XFY3PX.js';
11
20
  import './chunk-7AVYKZEM.js';
12
21
  import { buildModelInstallPlan } from './chunk-WHJMS7XC.js';
13
22
  import { ensurePackage, ensureUnavailableMessage } from './chunk-REIGWTTH.js';
14
- import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-5JJBGBP2.js';
15
- export { runBuild } from './chunk-5JJBGBP2.js';
16
- import { disableColor, info, c, json, out } from './chunk-CT5BS56U.js';
17
23
  import { init_resolve_ollama, gatherSystemMemory, resolveOllamaBinary, hasOllamaBinary, resolve_ollama_exports } from './chunk-OWSFZQOP.js';
18
24
  import { readOrchestratorState, writeOrchestratorState, parseMode, setDefaultMode, recommendMode, activePin, resolveMode, providerForBackend, QUALIFIED_PACKS, pinPack, unpinPack, buildOrchestratorStatus } from './chunk-NZELMYT4.js';
19
25
  import { fmt, estimateModelBytes } from './chunk-7N4Y3E47.js';
20
26
  import './chunk-IZDH67DX.js';
21
- import './chunk-GOPANQZT.js';
22
- import { vgdSocketPath, vgdIsRunning, vgdRequest, vgdPidPath } from './chunk-RBIRXQR6.js';
23
- import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-JFE7XCAE.js';
24
- import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-3LOWJSAF.js';
25
- import { buildIdentifierTrieFromGraph } from './chunk-5HYCB55P.js';
26
- import { serveStdio, isRelevantChange, exportGraph, GraphSource, createServer, formatForExt, RefreshScheduler } from './chunk-IJQOZ6ZD.js';
27
- import { refreshIfStale } from './chunk-6GQLEDVK.js';
28
- import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-CJNWHXQD.js';
29
- import { CliError, ExitCode, driftCount, ASSISTANTS, detectAssistants, isAssistantInstalled, usageError, detectServeLaunch, installAssistant, writeNavigationConfig, uninstallAssistant, buildGraph, writeSnapshot, probeFreshness, discover, assistantById, SMALL_REPO_FILES, isSkippedDirName, SKIP_FILES, SKIP_DIRS } from './chunk-6423BHLN.js';
30
- import { resolveDsn, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, parseDsn as parseDsn$1, uploadScanArtifact, dsnCommand, pushCommand, countTokens, shortestPath, pathDisconnect, testsToRun, detectRunner, coveringTests, FREE_PACK, readScanArtifact, publishPrivateLibrary, assessDocQuality, symbolsFromApi, fetchHostedDocsCached, selectForBudget, hostedBase, readStoredCredentials, projectCredentialsPath, homeCredentialsPath } from './chunk-3WUTQYRY.js';
31
- import { writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, loadConfig, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols, perDependencyDrift } from './chunk-N6ZMZ5AI.js';
27
+ import { serveStdio, isRelevantChange, exportGraph, GraphSource, createServer, formatForExt, RefreshScheduler } from './chunk-YNV5M3JW.js';
28
+ import { refreshIfStale } from './chunk-IHLLWBZU.js';
29
+ import { CliError, ExitCode, driftCount, ASSISTANTS, detectAssistants, isAssistantInstalled, usageError, detectServeLaunch, installAssistant, writeNavigationConfig, uninstallAssistant, engineUnavailable, buildGraph, writeSnapshot, probeFreshness, discover, assistantById, SMALL_REPO_FILES, isSkippedDirName, SKIP_FILES, SKIP_DIRS } from './chunk-TNROG5CO.js';
30
+ import { resolveDsn, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, parseDsn as parseDsn$1, uploadScanArtifact, dsnCommand, pushCommand, countTokens, shortestPath, pathDisconnect, testsToRun, detectRunner, coveringTests, FREE_PACK, readScanArtifact, publishPrivateLibrary, assessDocQuality, symbolsFromApi, fetchHostedDocsCached, selectForBudget, hostedBase, readStoredCredentials, projectCredentialsPath, homeCredentialsPath } from './chunk-WWGLVF7D.js';
32
31
  import { resolveIngestHost, dashHostForIngestHost, availableRegionIds, ingestHostForRegionId } from './chunk-HTLDXEHW.js';
32
+ import { writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, loadConfig, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols, perDependencyDrift } from './chunk-N6ZMZ5AI.js';
33
33
  import './chunk-VIWZ4QT7.js';
34
- import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-UZP623Y4.js';
34
+ import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-7QDHQLUS.js';
35
+ import { resolveOne } from './chunk-J7LKEB2R.js';
36
+ import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-DSUGC7F5.js';
37
+ import { queryGraphSemantic, queryGraph, indexFor, impactOf } from './chunk-KGPX4EUN.js';
35
38
  import { discoverModels } from './chunk-CQDUBAQY.js';
36
39
  import { freeBytesOnVolume, weightStoreDir, listCachedWeights, ensureWeightCached, catalogIntegrityReport } from './chunk-OV4KGXPD.js';
40
+ import { loadGraph, loadGraphPreferIndex, SCHEMA_VERSION } from './chunk-WQLZSVNF.js';
37
41
  import './chunk-5I4VSBWQ.js';
38
42
  import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-DT4KIVRI.js';
39
43
  import { ensureDir, pathExists, readJsonFile, writeTextFile, writeJsonFile } from './chunk-CRAMOEBE.js';
40
44
  import { init_cli_invocation, resolveCliInvocation, NPX_INVOCATION } from './chunk-3LSG7Z4I.js';
41
- import { resolveOne } from './chunk-J7LKEB2R.js';
42
- import { queryGraphSemantic, queryGraph, indexFor, impactOf } from './chunk-YJU7S7N6.js';
43
45
  import { resolvedGrammarFiles, grammarSetVersion } from './chunk-UTNNGKKX.js';
44
46
  import './chunk-RXP66R2E.js';
45
- import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, unavailableMessage, countPending, modelCacheInfo, embeddingsPath, clearModelCache, withTimeout } from './chunk-KBP7GJV6.js';
46
- import { loadGraph, loadGraphPreferIndex, SCHEMA_VERSION } from './chunk-7ZHSSGUF.js';
47
- import { cacheDir, resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, resetRelevanceProviderCache, loadRelevanceProvider, loadGraphFileWithSnapshot, serializeGraph, stableStringify, writeArtifacts, vibgrateDir, mapFileExists, relevanceModuleDir, parseGraph, ensureVibgrateGitignore } from './chunk-EWZKOU66.js';
48
- import { VERSION } from './chunk-RT7P5AYU.js';
47
+ import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, unavailableMessage, countPending, modelCacheInfo, embeddingsPath, clearModelCache, withTimeout } from './chunk-X76VPOYH.js';
48
+ import { cacheDir } from './chunk-2U37PFB2.js';
49
+ import { resetRelevanceProviderCache, loadRelevanceProvider, relevanceModuleDir, resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, loadGraphFileWithSnapshot, serializeGraph, stableStringify, writeArtifacts, vibgrateDir, mapFileExists, parseGraph, ensureVibgrateGitignore } from './chunk-75LJM5XD.js';
50
+ import { VERSION } from './chunk-2H2U3DC7.js';
49
51
  import './chunk-BWPBB45M.js';
50
52
  import { canonicalize, hashString, hashBytes } from './chunk-JFGYT6BI.js';
51
53
  import './chunk-BPF3YX2U.js';
52
54
  import { __toCommonJS } from './chunk-Z6ZWNWWR.js';
53
- import * as fs11 from 'fs';
54
- import fs11__default, { realpathSync } from 'fs';
55
- import * as path41 from 'path';
56
- import path41__default from 'path';
55
+ import * as fs12 from 'fs';
56
+ import fs12__default, { realpathSync } from 'fs';
57
+ import * as path43 from 'path';
58
+ import path43__default from 'path';
57
59
  import { fileURLToPath, pathToFileURL } from 'url';
58
60
  import { Command, CommanderError, Option } from 'commander';
59
61
  import { execSync, spawn, spawnSync, execFileSync } from 'child_process';
@@ -65,7 +67,7 @@ import * as zlib from 'zlib';
65
67
  import * as crypto3 from 'crypto';
66
68
  import { randomUUID, createHash } from 'crypto';
67
69
  import chalk7 from 'chalk';
68
- import * as fs25 from 'fs/promises';
70
+ import * as fs27 from 'fs/promises';
69
71
 
70
72
  init_cli_invocation();
71
73
  function registerStatus(program) {
@@ -75,10 +77,10 @@ function registerStatus(program) {
75
77
  applyGlobalOptions(cmd);
76
78
  }
77
79
  async function runStatus(global) {
78
- const root2 = path41.resolve(global.cwd ?? ".");
80
+ const root2 = path43.resolve(global.cwd ?? ".");
79
81
  const graphPath = resolveGraphPath(root2, global.graph);
80
82
  const graph = loadGraph(root2, graphPath);
81
- const hasCache = fs11.existsSync(path41.join(cacheDir(root2), "parse-cache.json"));
83
+ const hasCache = fs12.existsSync(path43.join(cacheDir(root2), "parse-cache.json"));
82
84
  let stale = null;
83
85
  let staleExact = false;
84
86
  if (graph) {
@@ -98,8 +100,8 @@ async function runStatus(global) {
98
100
  }
99
101
  if (global.json) {
100
102
  json({
101
- root: path41.relative(process.cwd(), root2) || ".",
102
- graphPath: path41.relative(root2, graphPath),
103
+ root: path43.relative(process.cwd(), root2) || ".",
104
+ graphPath: path43.relative(root2, graphPath),
103
105
  built: graph !== null,
104
106
  generatedAt: graph?.generatedAt ?? null,
105
107
  counts: graph?.meta.counts ?? null,
@@ -114,11 +116,11 @@ async function runStatus(global) {
114
116
  return;
115
117
  }
116
118
  if (!graph) {
117
- info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(path41.relative(root2, graphPath))}`);
119
+ info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(path43.relative(root2, graphPath))}`);
118
120
  info(` run ${c.bold("vg")} to build one`);
119
121
  return;
120
122
  }
121
- info(`${c.cyan("vg")} \xB7 ${path41.relative(root2, graphPath)}`);
123
+ info(`${c.cyan("vg")} \xB7 ${path43.relative(root2, graphPath)}`);
122
124
  info(` generated ${graph.generatedAt}`);
123
125
  info(
124
126
  ` nodes ${c.bold(String(graph.meta.counts.nodes))} edges ${c.bold(
@@ -135,7 +137,7 @@ async function runStatus(global) {
135
137
  if (vibgrateDir(root2)) ;
136
138
  }
137
139
  function rootOf(global) {
138
- return path41.resolve(global.cwd ?? ".");
140
+ return path43.resolve(global.cwd ?? ".");
139
141
  }
140
142
  function requireGraph(global) {
141
143
  const root2 = rootOf(global);
@@ -242,18 +244,19 @@ function registerAsk(program) {
242
244
  applyGlobalOptions(cmd);
243
245
  }
244
246
  function crashedMessage(signal) {
245
- return `semantic search is disabled: its native backend (onnxruntime-node, via fastembed) crashed with ${signal} \u2014 using fast lexical search instead. This is almost always an install-script block: npm skips onnxruntime-node's postinstall under allow-scripts/ignore-scripts, so the platform binaries were never downloaded. Reinstall allowing them \u2014 npm install -g --allow-scripts=@vibgrate/cli,onnxruntime-node,msgpackr-extract @vibgrate/cli \u2014 or run with --local to stay lexical quietly.`;
247
+ const envPrefix = process.platform === "linux" ? "ONNXRUNTIME_NODE_INSTALL=skip " : "";
248
+ return `semantic search is disabled: its native backend (onnxruntime-node, via the vendored fastembed path) crashed with ${signal} \u2014 using fast lexical search instead. This usually means the installed native binaries are broken (an interrupted install, or a platform without prebuilt CPU binaries). Reinstall to repair \u2014 ${envPrefix}npm install -g --allow-scripts=@vibgrate/cli,onnxruntime-node,msgpackr-extract @vibgrate/cli \u2014 or run with --local to stay lexical quietly.`;
246
249
  }
247
250
  function defaultCacheDir() {
248
- const base = process.env.XDG_CACHE_HOME || path41.join(os.homedir(), ".cache");
249
- return path41.join(base, "vibgrate", "models");
251
+ const base = process.env.XDG_CACHE_HOME || path43.join(os.homedir(), ".cache");
252
+ return path43.join(base, "vibgrate", "models");
250
253
  }
251
254
  function verdictPath(dir) {
252
- return path41.join(dir, `embed-health-${process.platform}-${process.arch}.json`);
255
+ return path43.join(dir, `embed-health-${process.platform}-${process.arch}.json`);
253
256
  }
254
257
  function readVerdict(dir) {
255
258
  try {
256
- const raw = JSON.parse(fs11.readFileSync(verdictPath(dir), "utf8"));
259
+ const raw = JSON.parse(fs12.readFileSync(verdictPath(dir), "utf8"));
257
260
  if (raw?.status !== "ok" && raw?.status !== "crashed") return null;
258
261
  if (raw.version !== VERSION) return null;
259
262
  return raw;
@@ -263,18 +266,18 @@ function readVerdict(dir) {
263
266
  }
264
267
  function writeVerdict(dir, verdict) {
265
268
  try {
266
- fs11.mkdirSync(dir, { recursive: true });
267
- fs11.writeFileSync(verdictPath(dir), JSON.stringify(verdict, null, 2) + "\n", "utf8");
269
+ fs12.mkdirSync(dir, { recursive: true });
270
+ fs12.writeFileSync(verdictPath(dir), JSON.stringify(verdict, null, 2) + "\n", "utf8");
268
271
  } catch {
269
272
  }
270
273
  }
271
274
  function probeModuleUrl(from = import.meta.url) {
272
- const dir = path41.dirname(fileURLToPath(from));
275
+ const dir = path43.dirname(fileURLToPath(from));
273
276
  for (const name of ["embeddings.js", "index.js"]) {
274
- const candidate = path41.join(dir, name);
275
- if (fs11.existsSync(candidate)) return pathToFileURL(candidate).href;
277
+ const candidate = path43.join(dir, name);
278
+ if (fs12.existsSync(candidate)) return pathToFileURL(candidate).href;
276
279
  }
277
- return pathToFileURL(path41.join(dir, "index.js")).href;
280
+ return pathToFileURL(path43.join(dir, "index.js")).href;
278
281
  }
279
282
  function defaultRunProbe(timeoutMs) {
280
283
  const moduleUrl = probeModuleUrl();
@@ -293,7 +296,7 @@ function defaultRunProbe(timeoutMs) {
293
296
  })
294
297
  .catch(() => process.stdout.write('{"ok":false}'));
295
298
  `;
296
- return new Promise((resolve21) => {
299
+ return new Promise((resolve23) => {
297
300
  const child = spawn(process.execPath, ["--input-type=module", "-e", script], {
298
301
  stdio: ["ignore", "pipe", "ignore"],
299
302
  // The probe must never inherit a debugger port or loader flags that would
@@ -306,7 +309,7 @@ function defaultRunProbe(timeoutMs) {
306
309
  if (settled) return;
307
310
  settled = true;
308
311
  clearTimeout(timer);
309
- resolve21({ signal, status, stdout });
312
+ resolve23({ signal, status, stdout });
310
313
  };
311
314
  const timer = setTimeout(() => {
312
315
  child.kill("SIGTERM");
@@ -349,7 +352,7 @@ async function embedderHealth(options = {}) {
349
352
  }
350
353
  function clearEmbedderHealth(cacheDir2) {
351
354
  try {
352
- fs11.unlinkSync(verdictPath(cacheDir2 ?? defaultCacheDir()));
355
+ fs12.unlinkSync(verdictPath(cacheDir2 ?? defaultCacheDir()));
353
356
  } catch {
354
357
  }
355
358
  }
@@ -1019,12 +1022,12 @@ var PUBLISH_INTERVAL_MS = 2e3;
1019
1022
  var KEEPALIVE_MS = 1e4;
1020
1023
  var STALE_MS = 6e4;
1021
1024
  function liveStatsDir(root2) {
1022
- return path41.join(cacheDir(root2), "serve-live");
1025
+ return path43.join(cacheDir(root2), "serve-live");
1023
1026
  }
1024
1027
  function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid, signal) => process.kill(pid, signal), selfPid = process.pid) {
1025
1028
  let entries;
1026
1029
  try {
1027
- entries = fs11.readdirSync(dir);
1030
+ entries = fs12.readdirSync(dir);
1028
1031
  } catch {
1029
1032
  return [];
1030
1033
  }
@@ -1033,7 +1036,7 @@ function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid
1033
1036
  if (!/^serve-\d+\.json$/.test(name)) continue;
1034
1037
  let parsed;
1035
1038
  try {
1036
- parsed = JSON.parse(fs11.readFileSync(path41.join(dir, name), "utf8"));
1039
+ parsed = JSON.parse(fs12.readFileSync(path43.join(dir, name), "utf8"));
1037
1040
  } catch {
1038
1041
  continue;
1039
1042
  }
@@ -1055,7 +1058,7 @@ var LiveStatsBus = class {
1055
1058
  this.dir = dir;
1056
1059
  this.stats = stats;
1057
1060
  this.pid = pid;
1058
- this.file = path41.join(dir, `serve-${this.pid}.json`);
1061
+ this.file = path43.join(dir, `serve-${this.pid}.json`);
1059
1062
  }
1060
1063
  dir;
1061
1064
  stats;
@@ -1087,10 +1090,10 @@ var LiveStatsBus = class {
1087
1090
  this.lastWriteAt = now;
1088
1091
  const body = { pid: this.pid, updatedAt: now, version: VERSION, snapshot: snap };
1089
1092
  try {
1090
- fs11.mkdirSync(this.dir, { recursive: true });
1093
+ fs12.mkdirSync(this.dir, { recursive: true });
1091
1094
  const tmp = `${this.file}.tmp`;
1092
- fs11.writeFileSync(tmp, JSON.stringify(body));
1093
- fs11.renameSync(tmp, this.file);
1095
+ fs12.writeFileSync(tmp, JSON.stringify(body));
1096
+ fs12.renameSync(tmp, this.file);
1094
1097
  } catch {
1095
1098
  }
1096
1099
  }
@@ -1101,24 +1104,24 @@ var LiveStatsBus = class {
1101
1104
  siblings(now = Date.now()) {
1102
1105
  let entries;
1103
1106
  try {
1104
- entries = fs11.readdirSync(this.dir);
1107
+ entries = fs12.readdirSync(this.dir);
1105
1108
  } catch {
1106
1109
  return [];
1107
1110
  }
1108
1111
  const out2 = [];
1109
1112
  for (const name of entries.sort()) {
1110
1113
  if (!/^serve-\d+\.json$/.test(name)) continue;
1111
- const file = path41.join(this.dir, name);
1114
+ const file = path43.join(this.dir, name);
1112
1115
  let parsed;
1113
1116
  try {
1114
- parsed = JSON.parse(fs11.readFileSync(file, "utf8"));
1117
+ parsed = JSON.parse(fs12.readFileSync(file, "utf8"));
1115
1118
  } catch {
1116
1119
  continue;
1117
1120
  }
1118
1121
  if (typeof parsed?.pid !== "number" || typeof parsed.updatedAt !== "number" || !parsed.snapshot?.totals) continue;
1119
1122
  if (now - parsed.updatedAt > STALE_MS) {
1120
1123
  try {
1121
- fs11.unlinkSync(file);
1124
+ fs12.unlinkSync(file);
1122
1125
  } catch {
1123
1126
  }
1124
1127
  continue;
@@ -1130,7 +1133,7 @@ var LiveStatsBus = class {
1130
1133
  }
1131
1134
  unlinkOwn = () => {
1132
1135
  try {
1133
- fs11.unlinkSync(this.file);
1136
+ fs12.unlinkSync(this.file);
1134
1137
  } catch {
1135
1138
  }
1136
1139
  };
@@ -1443,12 +1446,12 @@ var LedgerTail = class {
1443
1446
  if (size === this.offset) return;
1444
1447
  let chunk;
1445
1448
  try {
1446
- const fd = fs11.openSync(this.file, "r");
1449
+ const fd = fs12.openSync(this.file, "r");
1447
1450
  try {
1448
1451
  chunk = Buffer.alloc(size - this.offset);
1449
- fs11.readSync(fd, chunk, 0, chunk.length, this.offset);
1452
+ fs12.readSync(fd, chunk, 0, chunk.length, this.offset);
1450
1453
  } finally {
1451
- fs11.closeSync(fd);
1454
+ fs12.closeSync(fd);
1452
1455
  }
1453
1456
  } catch {
1454
1457
  return;
@@ -1461,7 +1464,7 @@ var LedgerTail = class {
1461
1464
  }
1462
1465
  sizeOf() {
1463
1466
  try {
1464
- return fs11.statSync(this.file).size;
1467
+ return fs12.statSync(this.file).size;
1465
1468
  } catch {
1466
1469
  return 0;
1467
1470
  }
@@ -1640,7 +1643,7 @@ async function serveHttp(graphPath, host, port, opts, freshness, onReady) {
1640
1643
  info(c.red(`vg serve: request error: ${err.message}`));
1641
1644
  }
1642
1645
  });
1643
- await new Promise((resolve21) => httpServer.listen(port, host, resolve21));
1646
+ await new Promise((resolve23) => httpServer.listen(port, host, resolve23));
1644
1647
  info(c.dim(`vg \xB7 MCP server on http://${host}:${port}/mcp (read-only, local, ${freshness})`));
1645
1648
  onReady?.();
1646
1649
  await new Promise(() => {
@@ -1854,19 +1857,19 @@ function endOfLine(text, line) {
1854
1857
  }
1855
1858
  var CACHE_VERSION = "vg-lsp-scan-cache/2";
1856
1859
  function cachePath(root2) {
1857
- return path41.join(cacheDir(root2), "lsp-scan.json");
1860
+ return path43.join(cacheDir(root2), "lsp-scan.json");
1858
1861
  }
1859
1862
  function manifestHash(root2) {
1860
1863
  const files = [];
1861
1864
  const walk2 = (dir) => {
1862
1865
  let entries;
1863
1866
  try {
1864
- entries = fs11.readdirSync(dir, { withFileTypes: true });
1867
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
1865
1868
  } catch {
1866
1869
  return;
1867
1870
  }
1868
1871
  for (const entry of entries) {
1869
- const abs = path41.join(dir, entry.name);
1872
+ const abs = path43.join(dir, entry.name);
1870
1873
  if (entry.isDirectory()) {
1871
1874
  if (isSkippedDirName(entry.name)) continue;
1872
1875
  walk2(abs);
@@ -1876,8 +1879,8 @@ function manifestHash(root2) {
1876
1879
  const base = entry.name.toLowerCase();
1877
1880
  if (!isManifest(abs) && !SKIP_FILES.has(base)) continue;
1878
1881
  try {
1879
- const rel = path41.relative(root2, abs).split(path41.sep).join("/");
1880
- files.push({ rel, hash: hashBytes(fs11.readFileSync(abs)) });
1882
+ const rel = path43.relative(root2, abs).split(path43.sep).join("/");
1883
+ files.push({ rel, hash: hashBytes(fs12.readFileSync(abs)) });
1881
1884
  } catch {
1882
1885
  }
1883
1886
  }
@@ -1887,16 +1890,16 @@ function manifestHash(root2) {
1887
1890
  return hashString(canonicalize(files));
1888
1891
  }
1889
1892
  function isDependencyFile(root2, filePath) {
1890
- const rel = path41.relative(path41.resolve(root2), path41.resolve(filePath));
1891
- if (rel === "" || rel.startsWith("..") || path41.isAbsolute(rel)) return false;
1892
- const parts = rel.split(path41.sep);
1893
+ const rel = path43.relative(path43.resolve(root2), path43.resolve(filePath));
1894
+ if (rel === "" || rel.startsWith("..") || path43.isAbsolute(rel)) return false;
1895
+ const parts = rel.split(path43.sep);
1893
1896
  if (parts.slice(0, -1).some((dir) => isSkippedDirName(dir))) return false;
1894
1897
  const base = parts[parts.length - 1].toLowerCase();
1895
1898
  return isManifest(filePath) || SKIP_FILES.has(base);
1896
1899
  }
1897
1900
  function loadScanCache(root2, key2) {
1898
1901
  try {
1899
- const raw = JSON.parse(fs11.readFileSync(cachePath(root2), "utf8"));
1902
+ const raw = JSON.parse(fs12.readFileSync(cachePath(root2), "utf8"));
1900
1903
  if (raw.version === CACHE_VERSION && raw.manifestHash === key2.manifestHash && raw.toolVersion === key2.toolVersion && raw.offline === key2.offline && raw.artifact) {
1901
1904
  return { manifestHash: raw.manifestHash, artifact: raw.artifact };
1902
1905
  }
@@ -1906,8 +1909,8 @@ function loadScanCache(root2, key2) {
1906
1909
  }
1907
1910
  function writeScanCache(root2, key2, artifact) {
1908
1911
  try {
1909
- fs11.mkdirSync(cacheDir(root2), { recursive: true });
1910
- fs11.writeFileSync(
1912
+ fs12.mkdirSync(cacheDir(root2), { recursive: true });
1913
+ fs12.writeFileSync(
1911
1914
  cachePath(root2),
1912
1915
  stableStringify(
1913
1916
  { version: CACHE_VERSION, manifestHash: key2.manifestHash, toolVersion: key2.toolVersion, offline: key2.offline, artifact },
@@ -1920,7 +1923,7 @@ function writeScanCache(root2, key2, artifact) {
1920
1923
  var MAX_ENTRIES = 1e3;
1921
1924
  var KEEP_ENTRIES = 500;
1922
1925
  function historyPath(root2) {
1923
- return path41.join(root2, ".vibgrate", "score-history.jsonl");
1926
+ return path43.join(root2, ".vibgrate", "score-history.jsonl");
1924
1927
  }
1925
1928
  function parseLine(line) {
1926
1929
  try {
@@ -1934,7 +1937,7 @@ function parseLine(line) {
1934
1937
  }
1935
1938
  function readHistory(root2) {
1936
1939
  try {
1937
- return fs11.readFileSync(historyPath(root2), "utf8").split("\n").filter((l) => l.trim()).map(parseLine).filter((e) => e !== null);
1940
+ return fs12.readFileSync(historyPath(root2), "utf8").split("\n").filter((l) => l.trim()).map(parseLine).filter((e) => e !== null);
1938
1941
  } catch {
1939
1942
  return [];
1940
1943
  }
@@ -1961,14 +1964,14 @@ function recordScore(root2, entry) {
1961
1964
  }
1962
1965
  }
1963
1966
  const file = historyPath(root2);
1964
- fs11.mkdirSync(path41.dirname(file), { recursive: true });
1967
+ fs12.mkdirSync(path43.dirname(file), { recursive: true });
1965
1968
  ensureVibgrateGitignore(root2);
1966
- fs11.appendFileSync(file, `${JSON.stringify(entry)}
1969
+ fs12.appendFileSync(file, `${JSON.stringify(entry)}
1967
1970
  `);
1968
1971
  const all = readHistory(root2);
1969
1972
  if (all.length > MAX_ENTRIES) {
1970
1973
  const kept = all.slice(-KEEP_ENTRIES);
1971
- fs11.writeFileSync(file, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
1974
+ fs12.writeFileSync(file, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
1972
1975
  }
1973
1976
  } catch {
1974
1977
  }
@@ -2311,8 +2314,8 @@ async function enrichVulns(ecosystem, name, version, opts = { offline: false })
2311
2314
  if (!ecosystem || !version) return { vulns: [], cveCount: 0, source: "error" };
2312
2315
  if (opts.offline) return { vulns: [], cveCount: 0, source: "offline" };
2313
2316
  const k = key(ecosystem, name, version);
2314
- const cached = cache.get(k);
2315
- if (cached) return { ...cached, source: "cache" };
2317
+ const cached2 = cache.get(k);
2318
+ if (cached2) return { ...cached2, source: "cache" };
2316
2319
  try {
2317
2320
  const controller = new AbortController();
2318
2321
  const timer = setTimeout(() => controller.abort(), 8e3);
@@ -2624,10 +2627,10 @@ var VibgrateLanguageServer = class {
2624
2627
  this.forceNextScan = false;
2625
2628
  try {
2626
2629
  const cacheKey = { manifestHash: manifestHash(this.opts.root), toolVersion: VERSION, offline: this.opts.offline };
2627
- const cached = force ? null : loadScanCache(this.opts.root, cacheKey);
2630
+ const cached2 = force ? null : loadScanCache(this.opts.root, cacheKey);
2628
2631
  let fromCache = false;
2629
- if (cached) {
2630
- this.artifact = pruneArtifactProjects(cached.artifact);
2632
+ if (cached2) {
2633
+ this.artifact = pruneArtifactProjects(cached2.artifact);
2631
2634
  fromCache = true;
2632
2635
  } else {
2633
2636
  const scanOpts = {
@@ -2940,10 +2943,10 @@ var VibgrateLanguageServer = class {
2940
2943
  const ecosystem = osvEcosystem(proj.type);
2941
2944
  if (!ecosystem) continue;
2942
2945
  const relManifest = manifestRelativePath(proj);
2943
- const absManifest = path41.resolve(this.opts.root, relManifest);
2946
+ const absManifest = path43.resolve(this.opts.root, relManifest);
2944
2947
  let text = null;
2945
2948
  try {
2946
- if (fs11.existsSync(absManifest)) text = fs11.readFileSync(absManifest, "utf8");
2949
+ if (fs12.existsSync(absManifest)) text = fs12.readFileSync(absManifest, "utf8");
2947
2950
  } catch {
2948
2951
  text = null;
2949
2952
  }
@@ -3092,7 +3095,7 @@ function pruneArtifactProjects(a) {
3092
3095
  return { ...a, projects, findings };
3093
3096
  }
3094
3097
  function projectByPath(a, projectPath) {
3095
- const norm = (p) => path41.normalize((p === "" ? "." : p).replace(/\\/g, "/"));
3098
+ const norm = (p) => path43.normalize((p === "" ? "." : p).replace(/\\/g, "/"));
3096
3099
  const want = norm(projectPath);
3097
3100
  for (const proj of a.projects ?? []) {
3098
3101
  if (norm(proj.path) === want) return proj;
@@ -3131,12 +3134,12 @@ function buildProjectRefs(rootDir, projects) {
3131
3134
  return refs.length > 0 ? refs : void 0;
3132
3135
  }
3133
3136
  function projectForFile(root2, a, filePath) {
3134
- const dir = path41.dirname(path41.resolve(filePath));
3137
+ const dir = path43.dirname(path43.resolve(filePath));
3135
3138
  let best;
3136
3139
  let bestLen = -1;
3137
3140
  for (const proj of a.projects ?? []) {
3138
- const projDir = path41.resolve(root2, proj.path);
3139
- if ((dir === projDir || dir.startsWith(projDir + path41.sep)) && projDir.length > bestLen) {
3141
+ const projDir = path43.resolve(root2, proj.path);
3142
+ if ((dir === projDir || dir.startsWith(projDir + path43.sep)) && projDir.length > bestLen) {
3140
3143
  best = proj;
3141
3144
  bestLen = projDir.length;
3142
3145
  }
@@ -3144,7 +3147,7 @@ function projectForFile(root2, a, filePath) {
3144
3147
  return best;
3145
3148
  }
3146
3149
  function sameProject(location, projectPath) {
3147
- return path41.normalize(location) === path41.normalize(projectPath);
3150
+ return path43.normalize(location) === path43.normalize(projectPath);
3148
3151
  }
3149
3152
  function hasReleaseDates(a) {
3150
3153
  for (const proj of a.projects ?? []) {
@@ -3214,10 +3217,10 @@ function buildBreakdown(rootDir, projects) {
3214
3217
  const relManifest = manifestRelativePath(p);
3215
3218
  if (isPrunedWorkspacePath(p.path) || isPrunedWorkspacePath(relManifest)) continue;
3216
3219
  const ecosystem = osvEcosystem(p.type);
3217
- const absManifest = path41.resolve(rootDir, relManifest);
3220
+ const absManifest = path43.resolve(rootDir, relManifest);
3218
3221
  let text = null;
3219
3222
  try {
3220
- if (fs11.existsSync(absManifest)) text = fs11.readFileSync(absManifest, "utf8");
3223
+ if (fs12.existsSync(absManifest)) text = fs12.readFileSync(absManifest, "utf8");
3221
3224
  } catch {
3222
3225
  text = null;
3223
3226
  }
@@ -3282,34 +3285,34 @@ function buildBreakdown(rootDir, projects) {
3282
3285
  }
3283
3286
  function manifestRelativePath(proj) {
3284
3287
  const base = proj.path === "." || proj.path === "" ? "" : proj.path;
3285
- const join31 = (name) => base ? path41.join(base, name) : name;
3288
+ const join33 = (name) => base ? path43.join(base, name) : name;
3286
3289
  switch (proj.type) {
3287
3290
  case "node":
3288
3291
  case "typescript":
3289
- return join31("package.json");
3292
+ return join33("package.json");
3290
3293
  case "python":
3291
- return join31("pyproject.toml");
3294
+ return join33("pyproject.toml");
3292
3295
  case "go":
3293
- return join31("go.mod");
3296
+ return join33("go.mod");
3294
3297
  case "rust":
3295
- return join31("Cargo.toml");
3298
+ return join33("Cargo.toml");
3296
3299
  case "ruby":
3297
- return join31("Gemfile");
3300
+ return join33("Gemfile");
3298
3301
  case "php":
3299
- return join31("composer.json");
3302
+ return join33("composer.json");
3300
3303
  case "java":
3301
3304
  case "kotlin":
3302
3305
  case "scala":
3303
3306
  case "groovy":
3304
- return join31("pom.xml");
3307
+ return join33("pom.xml");
3305
3308
  case "dotnet":
3306
- return join31(proj.name ? `${proj.name}.csproj` : "Directory.Build.props");
3309
+ return join33(proj.name ? `${proj.name}.csproj` : "Directory.Build.props");
3307
3310
  case "dart":
3308
- return join31("pubspec.yaml");
3311
+ return join33("pubspec.yaml");
3309
3312
  case "elixir":
3310
- return join31("mix.exs");
3313
+ return join33("mix.exs");
3311
3314
  default:
3312
- return join31("package.json");
3315
+ return join33("package.json");
3313
3316
  }
3314
3317
  }
3315
3318
  function lockfileRelativePath(rootDir, proj) {
@@ -3340,9 +3343,9 @@ function lockfileRelativePath(rootDir, proj) {
3340
3343
  const dirsToTry = base ? [base, ""] : [""];
3341
3344
  for (const dir of dirsToTry) {
3342
3345
  for (const name of candidateNames) {
3343
- const rel = dir ? path41.join(dir, name) : name;
3346
+ const rel = dir ? path43.join(dir, name) : name;
3344
3347
  try {
3345
- if (fs11.existsSync(path41.join(rootDir, rel))) return rel;
3348
+ if (fs12.existsSync(path43.join(rootDir, rel))) return rel;
3346
3349
  } catch {
3347
3350
  }
3348
3351
  }
@@ -3413,10 +3416,10 @@ function lookupImportFiles(map, pkg) {
3413
3416
  }
3414
3417
  function firstPackageMentionLine(root2, relFile, pkg) {
3415
3418
  try {
3416
- const abs = path41.resolve(root2, relFile);
3417
- const stat2 = fs11.statSync(abs);
3419
+ const abs = path43.resolve(root2, relFile);
3420
+ const stat2 = fs12.statSync(abs);
3418
3421
  if (!stat2.isFile() || stat2.size > 256 * 1024) return null;
3419
- const text = fs11.readFileSync(abs, "utf8");
3422
+ const text = fs12.readFileSync(abs, "utf8");
3420
3423
  const tokens = [pkg];
3421
3424
  if (pkg.startsWith("@")) {
3422
3425
  const parts = pkg.split("/");
@@ -3568,7 +3571,7 @@ function hoverMarkdown(dep, contribution) {
3568
3571
  return lines.join("\n");
3569
3572
  }
3570
3573
  function startLanguageServer(opts) {
3571
- if (!fs11.existsSync(opts.root)) {
3574
+ if (!fs12.existsSync(opts.root)) {
3572
3575
  process.stderr.write(`vg lsp: root does not exist: ${opts.root}
3573
3576
  `);
3574
3577
  process.exit(1);
@@ -3617,12 +3620,12 @@ function hookCommand(vgBin) {
3617
3620
  return `${vgBin} hook pre-tool-use`;
3618
3621
  }
3619
3622
  function installClaudeHooks(root2, vgBin = "vg") {
3620
- const file = path41.join(root2, ".claude", "settings.json");
3621
- const rel = path41.join(".claude", "settings.json");
3623
+ const file = path43.join(root2, ".claude", "settings.json");
3624
+ const rel = path43.join(".claude", "settings.json");
3622
3625
  let settings = {};
3623
- if (fs11.existsSync(file)) {
3626
+ if (fs12.existsSync(file)) {
3624
3627
  try {
3625
- const parsed = JSON.parse(fs11.readFileSync(file, "utf8"));
3628
+ const parsed = JSON.parse(fs12.readFileSync(file, "utf8"));
3626
3629
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3627
3630
  return { file: rel, status: "skipped", note: "settings.json is not a JSON object \u2014 left untouched" };
3628
3631
  }
@@ -3659,12 +3662,12 @@ function installClaudeHooks(root2, vgBin = "vg") {
3659
3662
  return { file: rel, status: "written" };
3660
3663
  }
3661
3664
  function uninstallClaudeHooks(root2) {
3662
- const file = path41.join(root2, ".claude", "settings.json");
3663
- const rel = path41.join(".claude", "settings.json");
3664
- if (!fs11.existsSync(file)) return { file: rel, status: "unchanged" };
3665
+ const file = path43.join(root2, ".claude", "settings.json");
3666
+ const rel = path43.join(".claude", "settings.json");
3667
+ if (!fs12.existsSync(file)) return { file: rel, status: "unchanged" };
3665
3668
  let settings;
3666
3669
  try {
3667
- settings = JSON.parse(fs11.readFileSync(file, "utf8"));
3670
+ settings = JSON.parse(fs12.readFileSync(file, "utf8"));
3668
3671
  } catch {
3669
3672
  return { file: rel, status: "skipped", note: "settings.json is not parseable JSON \u2014 left untouched" };
3670
3673
  }
@@ -3686,8 +3689,8 @@ function uninstallClaudeHooks(root2) {
3686
3689
  return { file: rel, status: "written" };
3687
3690
  }
3688
3691
  function writeSettings(file, settings) {
3689
- fs11.mkdirSync(path41.dirname(file), { recursive: true });
3690
- fs11.writeFileSync(file, `${JSON.stringify(settings, null, 2)}
3692
+ fs12.mkdirSync(path43.dirname(file), { recursive: true });
3693
+ fs12.writeFileSync(file, `${JSON.stringify(settings, null, 2)}
3691
3694
  `);
3692
3695
  }
3693
3696
 
@@ -3801,25 +3804,28 @@ function resolve5(id) {
3801
3804
  }
3802
3805
  return a;
3803
3806
  }
3804
- var RELEVANCE_MODULE_NAME = "@vibgrate/relevance";
3805
3807
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
3806
3808
  function registryBase(opts) {
3807
3809
  return (process.env.VIBGRATE_MODULE_REGISTRY || opts.registry || DEFAULT_REGISTRY).replace(/\/+$/, "");
3808
3810
  }
3811
+ function modulesBaseDir() {
3812
+ const base = process.env.XDG_CACHE_HOME || path43.join(os.homedir(), ".cache");
3813
+ return path43.join(base, "vibgrate", "modules");
3814
+ }
3809
3815
  function stateFile() {
3810
- return path41.join(path41.dirname(relevanceModuleDir()), "consent.json");
3816
+ return path43.join(modulesBaseDir(), "consent.json");
3811
3817
  }
3812
3818
  function readConsent() {
3813
3819
  try {
3814
- return JSON.parse(fs11.readFileSync(stateFile(), "utf8"));
3820
+ return JSON.parse(fs12.readFileSync(stateFile(), "utf8"));
3815
3821
  } catch {
3816
3822
  return {};
3817
3823
  }
3818
3824
  }
3819
3825
  function writeConsent(state) {
3820
3826
  try {
3821
- fs11.mkdirSync(path41.dirname(stateFile()), { recursive: true });
3822
- fs11.writeFileSync(stateFile(), JSON.stringify(state));
3827
+ fs12.mkdirSync(path43.dirname(stateFile()), { recursive: true });
3828
+ fs12.writeFileSync(stateFile(), JSON.stringify(state));
3823
3829
  } catch {
3824
3830
  }
3825
3831
  }
@@ -3827,17 +3833,16 @@ function kernelDisabled() {
3827
3833
  const v = process.env.VIBGRATE_NO_KERNEL;
3828
3834
  return v === "1" || v === "true";
3829
3835
  }
3830
- function moduleInstalled() {
3836
+ function moduleInstalledAt(dir) {
3831
3837
  try {
3832
- const meta = JSON.parse(fs11.readFileSync(path41.join(relevanceModuleDir(), ".module.json"), "utf8"));
3833
- if (fs11.existsSync(path41.join(relevanceModuleDir(), "index.js"))) {
3838
+ const meta = JSON.parse(fs12.readFileSync(path43.join(dir, ".module.json"), "utf8"));
3839
+ if (fs12.existsSync(path43.join(dir, "index.js"))) {
3834
3840
  return { installed: true, version: meta.version };
3835
3841
  }
3836
3842
  } catch {
3837
3843
  }
3838
3844
  return { installed: false };
3839
3845
  }
3840
- var DISCLOSURE = "vg can install the optional Vibgrate relevance module (proprietary license, runs fully locally, improves how questions find the code they mean). Disable any time with VIBGRATE_NO_KERNEL=1.";
3841
3846
  function verifyIntegrity(buf, integrity, shasum) {
3842
3847
  if (integrity) {
3843
3848
  const [algo, expected] = integrity.split("-", 2);
@@ -3879,21 +3884,21 @@ function untar(data) {
3879
3884
  if (type !== "0" && type !== "\0") continue;
3880
3885
  const name = pendingName ?? (prefix ? `${prefix}/${rawName}` : rawName);
3881
3886
  pendingName = null;
3882
- if (name.split("/").includes("..") || path41.isAbsolute(name)) {
3887
+ if (name.split("/").includes("..") || path43.isAbsolute(name)) {
3883
3888
  throw new Error(`unsafe path in tarball: ${name}`);
3884
3889
  }
3885
3890
  out2.push({ name, body: Buffer.from(body) });
3886
3891
  }
3887
3892
  return out2;
3888
3893
  }
3889
- async function installRelevanceModule(opts = {}) {
3894
+ async function installModule(mod, opts = {}) {
3890
3895
  if (kernelDisabled()) return { status: "disabled", detail: "VIBGRATE_NO_KERNEL is set" };
3891
- const existing = moduleInstalled();
3896
+ const existing = moduleInstalledAt(mod.dir());
3892
3897
  if (existing.installed && !opts.force) return { status: "already-installed", version: existing.version };
3893
3898
  const doFetch = opts.fetchImpl ?? fetch;
3894
3899
  const base = registryBase(opts);
3895
3900
  try {
3896
- const metaRes = await doFetch(`${base}/${RELEVANCE_MODULE_NAME.replace("/", "%2f")}`);
3901
+ const metaRes = await doFetch(`${base}/${mod.npmName.replace("/", "%2f")}`);
3897
3902
  if (!metaRes.ok) return { status: "unavailable", detail: `registry ${metaRes.status}` };
3898
3903
  const meta = await metaRes.json();
3899
3904
  const version = meta["dist-tags"]?.latest;
@@ -3904,35 +3909,54 @@ async function installRelevanceModule(opts = {}) {
3904
3909
  const gz = Buffer.from(await tarRes.arrayBuffer());
3905
3910
  verifyIntegrity(gz, dist.integrity, dist.shasum);
3906
3911
  const entries = untar(zlib.gunzipSync(gz));
3907
- const dir = relevanceModuleDir();
3908
- fs11.rmSync(dir, { recursive: true, force: true });
3909
- fs11.mkdirSync(dir, { recursive: true });
3912
+ const dir = mod.dir();
3913
+ fs12.rmSync(dir, { recursive: true, force: true });
3914
+ fs12.mkdirSync(dir, { recursive: true });
3910
3915
  let wrote = 0;
3911
3916
  for (const e of entries) {
3912
3917
  let rel = null;
3913
3918
  if (e.name.startsWith("package/dist/")) rel = e.name.slice("package/dist/".length);
3914
3919
  else if (e.name === "package/LICENSE" || e.name === "package/README.md") rel = e.name.slice("package/".length);
3915
3920
  if (!rel) continue;
3916
- const target = path41.join(dir, rel);
3917
- if (!target.startsWith(dir + path41.sep) && target !== dir) throw new Error(`unsafe extract path: ${rel}`);
3918
- fs11.mkdirSync(path41.dirname(target), { recursive: true });
3919
- fs11.writeFileSync(target, e.body);
3921
+ const target = path43.join(dir, rel);
3922
+ if (!target.startsWith(dir + path43.sep) && target !== dir) throw new Error(`unsafe extract path: ${rel}`);
3923
+ fs12.mkdirSync(path43.dirname(target), { recursive: true });
3924
+ fs12.writeFileSync(target, e.body);
3920
3925
  wrote += 1;
3921
3926
  }
3922
- if (!wrote || !fs11.existsSync(path41.join(dir, "index.js"))) {
3923
- fs11.rmSync(dir, { recursive: true, force: true });
3927
+ if (!wrote || !fs12.existsSync(path43.join(dir, "index.js"))) {
3928
+ fs12.rmSync(dir, { recursive: true, force: true });
3924
3929
  return { status: "unavailable", detail: "package layout not recognized (no dist/index.js)" };
3925
3930
  }
3926
- fs11.writeFileSync(path41.join(dir, ".module.json"), JSON.stringify({ name: RELEVANCE_MODULE_NAME, version }));
3927
- resetRelevanceProviderCache();
3931
+ fs12.writeFileSync(path43.join(dir, ".module.json"), JSON.stringify({ name: mod.npmName, version }));
3932
+ mod.onChanged?.();
3928
3933
  return { status: "installed", version };
3929
3934
  } catch (e) {
3930
3935
  return { status: "unavailable", detail: String(e.message ?? e).slice(0, 200) };
3931
3936
  }
3932
3937
  }
3938
+ function removeModule(mod) {
3939
+ fs12.rmSync(mod.dir(), { recursive: true, force: true });
3940
+ mod.onChanged?.();
3941
+ }
3942
+
3943
+ // src/install/relevance-module.ts
3944
+ var RELEVANCE_MODULE_NAME = "@vibgrate/relevance";
3945
+ var RELEVANCE_MODULE = {
3946
+ id: "relevance",
3947
+ npmName: RELEVANCE_MODULE_NAME,
3948
+ dir: relevanceModuleDir,
3949
+ onChanged: resetRelevanceProviderCache
3950
+ };
3951
+ function moduleInstalled() {
3952
+ return moduleInstalledAt(relevanceModuleDir());
3953
+ }
3954
+ var DISCLOSURE = "vg can install the optional Vibgrate relevance module (proprietary license, runs fully locally, improves how questions find the code they mean). Disable any time with VIBGRATE_NO_KERNEL=1.";
3955
+ async function installRelevanceModule(opts = {}) {
3956
+ return installModule(RELEVANCE_MODULE, opts);
3957
+ }
3933
3958
  function removeRelevanceModule() {
3934
- fs11.rmSync(relevanceModuleDir(), { recursive: true, force: true });
3935
- resetRelevanceProviderCache();
3959
+ removeModule(RELEVANCE_MODULE);
3936
3960
  }
3937
3961
  async function ensureRelevanceModule(io = {}) {
3938
3962
  try {
@@ -3945,78 +3969,178 @@ async function ensureRelevanceModule(io = {}) {
3945
3969
  return { status: "unavailable", detail: "auto-install failed" };
3946
3970
  }
3947
3971
  }
3972
+ function disabled() {
3973
+ const v = process.env.VIBGRATE_NO_KERNEL;
3974
+ return v === "1" || v === "true";
3975
+ }
3976
+ function hcsModuleDir() {
3977
+ return path43.join(modulesBaseDir(), "hcs");
3978
+ }
3979
+ function candidatePaths() {
3980
+ const custom = process.env.VIBGRATE_HCS_PATH;
3981
+ if (custom) {
3982
+ const p = path43.resolve(custom);
3983
+ try {
3984
+ if (fs12.statSync(p).isDirectory()) return [path43.join(p, "index.js")];
3985
+ } catch {
3986
+ }
3987
+ return [p];
3988
+ }
3989
+ return [path43.join(hcsModuleDir(), "index.js")];
3990
+ }
3991
+ var cached;
3992
+ function resetHcsEngineCache() {
3993
+ cached = void 0;
3994
+ }
3995
+ async function loadHcsEngine() {
3996
+ if (cached !== void 0) return cached;
3997
+ cached = null;
3998
+ if (disabled()) return cached;
3999
+ for (const p of candidatePaths()) {
4000
+ if (!fs12.existsSync(p)) continue;
4001
+ try {
4002
+ const mod = await import(pathToFileURL(p).href);
4003
+ const engine = await mod.createHcsEngine?.();
4004
+ if (engine && typeof engine.version === "function" && typeof engine.renderDigest === "function" && typeof engine.buildMap === "function" && typeof engine.evaluateGate === "function") {
4005
+ cached = engine;
4006
+ return cached;
4007
+ }
4008
+ } catch {
4009
+ }
4010
+ }
4011
+ return cached;
4012
+ }
4013
+
4014
+ // src/install/hcs-module.ts
4015
+ var HCS_MODULE_NAME = "@vibgrate/hcs-engine";
4016
+ var HCS_MODULE = {
4017
+ id: "hcs",
4018
+ npmName: HCS_MODULE_NAME,
4019
+ dir: hcsModuleDir,
4020
+ onChanged: resetHcsEngineCache
4021
+ };
4022
+ var HCS_DISCLOSURE = "vg can install the optional Vibgrate HCS engine module (proprietary license, runs fully locally in a WASM sandbox \u2014 no network, no process spawns). Disable any time with VIBGRATE_NO_KERNEL=1.";
4023
+ function hcsModuleInstalled() {
4024
+ return moduleInstalledAt(hcsModuleDir());
4025
+ }
4026
+ async function installHcsModule(opts = {}) {
4027
+ return installModule(HCS_MODULE, opts);
4028
+ }
4029
+ function removeHcsModule() {
4030
+ removeModule(HCS_MODULE);
4031
+ }
4032
+ async function ensureHcsModule(io = {}) {
4033
+ try {
4034
+ if (kernelDisabled()) return { status: "disabled" };
4035
+ const existing = hcsModuleInstalled();
4036
+ if (existing.installed) return { status: "already-installed", version: existing.version };
4037
+ if (readConsent().hcs === "denied") return { status: "declined" };
4038
+ return await installHcsModule({ fetchImpl: io.fetchImpl });
4039
+ } catch {
4040
+ return { status: "unavailable", detail: "auto-install failed" };
4041
+ }
4042
+ }
3948
4043
 
3949
4044
  // src/commands/module.ts
4045
+ var MODULES = {
4046
+ relevance: {
4047
+ npmName: RELEVANCE_MODULE_NAME,
4048
+ disclosure: DISCLOSURE,
4049
+ install: installRelevanceModule,
4050
+ remove: removeRelevanceModule,
4051
+ installed: moduleInstalled,
4052
+ resetLoader: resetRelevanceProviderCache,
4053
+ loadedVersion: async () => {
4054
+ const provider = await loadRelevanceProvider();
4055
+ return provider ? provider.version() : null;
4056
+ }
4057
+ },
4058
+ hcs: {
4059
+ npmName: HCS_MODULE_NAME,
4060
+ disclosure: HCS_DISCLOSURE,
4061
+ install: installHcsModule,
4062
+ remove: removeHcsModule,
4063
+ installed: hcsModuleInstalled,
4064
+ resetLoader: resetHcsEngineCache,
4065
+ loadedVersion: async () => {
4066
+ const engine = await loadHcsEngine();
4067
+ return engine ? engine.version() : null;
4068
+ }
4069
+ }
4070
+ };
4071
+ var SUPPORTED = Object.keys(MODULES).join(", ");
3950
4072
  function registerModule(program) {
3951
- const cmd = program.command("module").description("manage optional local modules (relevance)");
3952
- cmd.command("install").description("install an optional module (fetches from the registry, integrity-checked)").argument("<name>", "module name (supported: relevance)").option("--yes", "skip the confirmation prompt").option("--force", "reinstall even when already present").action(async function(name, opts) {
4073
+ const cmd = program.command("module").description(`manage optional local modules (${SUPPORTED})`);
4074
+ cmd.command("install").description("install an optional module (fetches from the registry, integrity-checked)").argument("<name>", `module name (supported: ${SUPPORTED})`).option("--yes", "skip the confirmation prompt").option("--force", "reinstall even when already present").action(async function(name, opts) {
3953
4075
  const global = readGlobal(this);
3954
- requireRelevance(name);
4076
+ const mod = requireModule(name);
3955
4077
  if (kernelDisabled()) {
3956
- throw new CliError("VIBGRATE_NO_KERNEL is set \u2014 unset it to install the relevance module", ExitCode.USAGE_ERROR);
4078
+ throw new CliError(`VIBGRATE_NO_KERNEL is set \u2014 unset it to install the ${name} module`, ExitCode.USAGE_ERROR);
3957
4079
  }
3958
4080
  if (!opts.yes && process.stdin.isTTY && process.stdout.isTTY) {
3959
- const ok = await confirm(`${DISCLOSURE}
4081
+ const ok = await confirm(`${mod.disclosure}
3960
4082
  Install now? [Y/n] `);
3961
4083
  if (!ok) {
3962
- writeConsent({ ...readConsent(), relevance: "denied" });
4084
+ writeConsent({ ...readConsent(), [name]: "denied" });
3963
4085
  info("not installed");
3964
4086
  return;
3965
4087
  }
3966
4088
  }
3967
- writeConsent({ ...readConsent(), relevance: "granted" });
3968
- const result = await installRelevanceModule({ force: opts.force });
4089
+ writeConsent({ ...readConsent(), [name]: "granted" });
4090
+ const result = await mod.install({ force: opts.force });
3969
4091
  if (global.json) {
3970
4092
  json(result);
3971
4093
  if (result.status === "unavailable") process.exitCode = ExitCode.ERROR;
3972
4094
  return;
3973
4095
  }
3974
- if (result.status === "installed") out(`installed ${RELEVANCE_MODULE_NAME}@${result.version}`);
4096
+ if (result.status === "installed") out(`installed ${mod.npmName}@${result.version}`);
3975
4097
  else if (result.status === "already-installed") out(`already installed (${result.version ?? "unknown"}) \u2014 use --force to reinstall`);
3976
4098
  else throw new CliError(`install failed: ${result.detail ?? result.status} \u2014 check network access to the registry, or retry later`, ExitCode.ERROR);
3977
4099
  });
3978
- cmd.command("remove").description("remove an installed module").argument("<name>", "module name (supported: relevance)").action(async function(name) {
3979
- requireRelevance(name);
3980
- removeRelevanceModule();
4100
+ cmd.command("remove").description("remove an installed module").argument("<name>", `module name (supported: ${SUPPORTED})`).action(async function(name) {
4101
+ requireModule(name).remove();
3981
4102
  out("removed");
3982
4103
  });
3983
4104
  cmd.command("status").description("show installed modules and whether they load").action(async function() {
3984
4105
  const global = readGlobal(this);
3985
- const installed = moduleInstalled();
3986
- resetRelevanceProviderCache();
3987
- const provider = installed.installed ? await loadRelevanceProvider() : null;
3988
- const status = {
3989
- relevance: {
4106
+ const consent = readConsent();
4107
+ const status = {};
4108
+ for (const [name, mod] of Object.entries(MODULES)) {
4109
+ const installed = mod.installed();
4110
+ mod.resetLoader();
4111
+ const loadedVersion = installed.installed ? await mod.loadedVersion() : null;
4112
+ status[name] = {
3990
4113
  installed: installed.installed,
3991
4114
  version: installed.version ?? null,
3992
- loadable: !!provider,
3993
- providerVersion: provider ? provider.version() : null,
4115
+ loadable: loadedVersion !== null,
4116
+ providerVersion: loadedVersion,
3994
4117
  disabled: kernelDisabled(),
3995
- consent: readConsent().relevance ?? "unset"
3996
- }
3997
- };
4118
+ consent: consent[name] ?? "unset"
4119
+ };
4120
+ }
3998
4121
  if (global.json) {
3999
4122
  json(status);
4000
4123
  return;
4001
4124
  }
4002
- const r = status.relevance;
4003
- out(`relevance: ${r.installed ? `installed ${r.version}` : "not installed"}${r.disabled ? " (disabled via VIBGRATE_NO_KERNEL)" : ""}`);
4004
- if (r.installed) out(` loads: ${r.loadable ? `yes (${r.providerVersion})` : "no"}`);
4005
- info(c.dim(` consent: ${r.consent}`));
4125
+ for (const [name, s] of Object.entries(status)) {
4126
+ out(`${name}: ${s.installed ? `installed ${s.version}` : "not installed"}${s.disabled ? " (disabled via VIBGRATE_NO_KERNEL)" : ""}`);
4127
+ if (s.installed) out(` loads: ${s.loadable ? `yes (${s.providerVersion})` : "no"}`);
4128
+ info(c.dim(` consent: ${s.consent}`));
4129
+ }
4006
4130
  });
4007
4131
  applyGlobalOptions(cmd);
4008
4132
  }
4009
- function requireRelevance(name) {
4010
- if (name !== "relevance") {
4011
- throw usageError(`unknown module '${name}' \u2014 supported modules: relevance`);
4012
- }
4133
+ function requireModule(name) {
4134
+ const mod = MODULES[name];
4135
+ if (!mod) throw usageError(`unknown module '${name}' \u2014 supported modules: ${SUPPORTED}`);
4136
+ return mod;
4013
4137
  }
4014
4138
  function confirm(question) {
4015
- return new Promise((resolve21) => {
4139
+ return new Promise((resolve23) => {
4016
4140
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
4017
4141
  rl.question(question, (answer) => {
4018
4142
  rl.close();
4019
- resolve21(answer.trim() === "" || /^y(es)?$/i.test(answer.trim()));
4143
+ resolve23(answer.trim() === "" || /^y(es)?$/i.test(answer.trim()));
4020
4144
  });
4021
4145
  });
4022
4146
  }
@@ -4040,7 +4164,7 @@ function hookContext(payloadText, root2, graphOverride) {
4040
4164
  let graph;
4041
4165
  try {
4042
4166
  const preferred = loadGraphPreferIndex(root2, graphPath);
4043
- graph = preferred ? preferred.graph : parseGraph(fs11.readFileSync(graphPath, "utf8"));
4167
+ graph = preferred ? preferred.graph : parseGraph(fs12.readFileSync(graphPath, "utf8"));
4044
4168
  } catch {
4045
4169
  return null;
4046
4170
  }
@@ -4062,7 +4186,7 @@ function registerHook(program) {
4062
4186
  const global = readGlobal(this);
4063
4187
  const root2 = rootOf(global);
4064
4188
  try {
4065
- const stdin = fs11.readFileSync(0, "utf8");
4189
+ const stdin = fs12.readFileSync(0, "utf8");
4066
4190
  const context = hookContext(stdin, root2, global.graph);
4067
4191
  if (context) {
4068
4192
  process.stdout.write(
@@ -4082,8 +4206,8 @@ function registerShare(program) {
4082
4206
  const cmd = program.command("share").description("make the map committable + auto-updating for your team (git)").option("--undo", "reverse what `vg share` installed").option("--reports", "also commit graph.html / GRAPH_REPORT.md (default: gitignored)").action(function(opts) {
4083
4207
  const global = readGlobal(this);
4084
4208
  const root2 = rootOf(global);
4085
- const gitDir = path41.join(root2, ".git");
4086
- if (!fs11.existsSync(gitDir)) {
4209
+ const gitDir = path43.join(root2, ".git");
4210
+ if (!fs12.existsSync(gitDir)) {
4087
4211
  throw new CliError("not a git repository \u2014 run `vg share` inside a git repo", ExitCode.USAGE_ERROR);
4088
4212
  }
4089
4213
  if (opts.undo) {
@@ -4104,23 +4228,23 @@ function registerShare(program) {
4104
4228
  applyGlobalOptions(cmd);
4105
4229
  }
4106
4230
  function writeVibgrateGitignore(root2, reports) {
4107
- const dir = path41.join(root2, ".vibgrate");
4108
- fs11.mkdirSync(dir, { recursive: true });
4231
+ const dir = path43.join(root2, ".vibgrate");
4232
+ fs12.mkdirSync(dir, { recursive: true });
4109
4233
  const lines = ["# Managed by `vg share` \u2014 keep graph.json committed, ignore the rest", "cache/", "facts.jsonl", "graph.snap"];
4110
4234
  if (!reports) lines.push("graph.html", "GRAPH_REPORT.md");
4111
- fs11.writeFileSync(path41.join(dir, ".gitignore"), `${lines.join("\n")}
4235
+ fs12.writeFileSync(path43.join(dir, ".gitignore"), `${lines.join("\n")}
4112
4236
  `);
4113
4237
  }
4114
4238
  function writeGitAttributes(root2) {
4115
- const file = path41.join(root2, ".gitattributes");
4239
+ const file = path43.join(root2, ".gitattributes");
4116
4240
  const line = ".vibgrate/graph.json merge=vg";
4117
- let content = fs11.existsSync(file) ? fs11.readFileSync(file, "utf8") : "";
4241
+ let content = fs12.existsSync(file) ? fs12.readFileSync(file, "utf8") : "";
4118
4242
  if (!content.split("\n").some((l) => l.trim() === line)) {
4119
4243
  content = content.length ? `${content.replace(/\s*$/, "")}
4120
4244
  ${line}
4121
4245
  ` : `${line}
4122
4246
  `;
4123
- fs11.writeFileSync(file, content);
4247
+ fs12.writeFileSync(file, content);
4124
4248
  }
4125
4249
  }
4126
4250
  function configureMergeDriver(root2) {
@@ -4129,8 +4253,8 @@ function configureMergeDriver(root2) {
4129
4253
  }
4130
4254
  function installPreCommitHook(root2) {
4131
4255
  const hooksDir = hookDir(root2);
4132
- fs11.mkdirSync(hooksDir, { recursive: true });
4133
- const file = path41.join(hooksDir, "pre-commit");
4256
+ fs12.mkdirSync(hooksDir, { recursive: true });
4257
+ const file = path43.join(hooksDir, "pre-commit");
4134
4258
  const block = [
4135
4259
  HOOK_BEGIN,
4136
4260
  "if command -v vg >/dev/null 2>&1; then",
@@ -4139,7 +4263,7 @@ function installPreCommitHook(root2) {
4139
4263
  "fi",
4140
4264
  HOOK_END
4141
4265
  ].join("\n");
4142
- let content = fs11.existsSync(file) ? fs11.readFileSync(file, "utf8") : "#!/bin/sh\n";
4266
+ let content = fs12.existsSync(file) ? fs12.readFileSync(file, "utf8") : "#!/bin/sh\n";
4143
4267
  const re = new RegExp(`${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}`);
4144
4268
  if (re.test(content)) content = content.replace(re, block);
4145
4269
  else content = `${content.replace(/\s*$/, "")}
@@ -4148,21 +4272,21 @@ ${block}
4148
4272
  `;
4149
4273
  if (!content.startsWith("#!")) content = `#!/bin/sh
4150
4274
  ${content}`;
4151
- fs11.writeFileSync(file, content);
4152
- fs11.chmodSync(file, 493);
4275
+ fs12.writeFileSync(file, content);
4276
+ fs12.chmodSync(file, 493);
4153
4277
  }
4154
4278
  function undo(root2) {
4155
- const hookFile = path41.join(hookDir(root2), "pre-commit");
4156
- if (fs11.existsSync(hookFile)) {
4279
+ const hookFile = path43.join(hookDir(root2), "pre-commit");
4280
+ if (fs12.existsSync(hookFile)) {
4157
4281
  const re = new RegExp(`\\n*${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}\\n*`);
4158
- const next2 = fs11.readFileSync(hookFile, "utf8").replace(re, "\n");
4159
- if (next2.trim() === "#!/bin/sh") fs11.rmSync(hookFile);
4160
- else fs11.writeFileSync(hookFile, next2);
4282
+ const next2 = fs12.readFileSync(hookFile, "utf8").replace(re, "\n");
4283
+ if (next2.trim() === "#!/bin/sh") fs12.rmSync(hookFile);
4284
+ else fs12.writeFileSync(hookFile, next2);
4161
4285
  }
4162
- const attr = path41.join(root2, ".gitattributes");
4163
- if (fs11.existsSync(attr)) {
4164
- const next2 = fs11.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
4165
- fs11.writeFileSync(attr, next2);
4286
+ const attr = path43.join(root2, ".gitattributes");
4287
+ if (fs12.existsSync(attr)) {
4288
+ const next2 = fs12.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
4289
+ fs12.writeFileSync(attr, next2);
4166
4290
  }
4167
4291
  try {
4168
4292
  git(root2, ["config", "--remove-section", "merge.vg"]);
@@ -4172,10 +4296,10 @@ function undo(root2) {
4172
4296
  function hookDir(root2) {
4173
4297
  try {
4174
4298
  const configured = git(root2, ["config", "--get", "core.hooksPath"]).trim();
4175
- if (configured) return path41.resolve(root2, configured);
4299
+ if (configured) return path43.resolve(root2, configured);
4176
4300
  } catch {
4177
4301
  }
4178
- return path41.join(root2, ".git", "hooks");
4302
+ return path43.join(root2, ".git", "hooks");
4179
4303
  }
4180
4304
  function git(root2, args) {
4181
4305
  return execFileSync("git", args, { cwd: root2, encoding: "utf8" });
@@ -4189,9 +4313,9 @@ function registerWatch(program) {
4189
4313
  const global = readGlobal(this);
4190
4314
  const root2 = rootOf(global);
4191
4315
  const debounceMs = Math.max(50, Number(opts.debounce) || DEFAULT_DEBOUNCE_MS);
4192
- const watchRoots = (paths.length ? paths : ["."]).map((p) => path41.resolve(root2, p));
4316
+ const watchRoots = (paths.length ? paths : ["."]).map((p) => path43.resolve(root2, p));
4193
4317
  for (const w of watchRoots) {
4194
- if (!fs11.existsSync(w)) {
4318
+ if (!fs12.existsSync(w)) {
4195
4319
  throw new CliError(`watch path not found: ${w}`, ExitCode.USAGE_ERROR);
4196
4320
  }
4197
4321
  }
@@ -4244,7 +4368,7 @@ function registerWatch(program) {
4244
4368
  const watchers = [];
4245
4369
  for (const w of watchRoots) {
4246
4370
  try {
4247
- const watcher = fs11.watch(w, { recursive: true }, (_event, filename) => {
4371
+ const watcher = fs12.watch(w, { recursive: true }, (_event, filename) => {
4248
4372
  if (!filename) {
4249
4373
  schedule("change");
4250
4374
  return;
@@ -4257,12 +4381,12 @@ function registerWatch(program) {
4257
4381
  throw new CliError(`cannot watch ${w}: ${err.message}`, ExitCode.ERROR);
4258
4382
  }
4259
4383
  }
4260
- info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path41.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
4261
- await new Promise((resolve21) => {
4384
+ info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path43.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
4385
+ await new Promise((resolve23) => {
4262
4386
  const stop = () => {
4263
4387
  for (const w of watchers) w.close();
4264
4388
  if (timer) clearTimeout(timer);
4265
- resolve21();
4389
+ resolve23();
4266
4390
  };
4267
4391
  process.once("SIGINT", stop);
4268
4392
  process.once("SIGTERM", stop);
@@ -4590,10 +4714,10 @@ function normalizeStandards(raw) {
4590
4714
  }
4591
4715
  function loadStandards(root2) {
4592
4716
  for (const rel of STANDARDS_FILES) {
4593
- const p = path41__default.join(root2, rel);
4717
+ const p = path43__default.join(root2, rel);
4594
4718
  let text;
4595
4719
  try {
4596
- text = fs11__default.readFileSync(p, "utf8");
4720
+ text = fs12__default.readFileSync(p, "utf8");
4597
4721
  } catch {
4598
4722
  continue;
4599
4723
  }
@@ -5311,8 +5435,8 @@ async function runHostBench(options = {}) {
5311
5435
  }
5312
5436
  async function runArmSimulate(input) {
5313
5437
  const { arm, lib, modelPath, turns, trie, env, live } = input;
5314
- const path43 = `${modelPath}#${arm.id}`;
5315
- const session = await acquireHostSession(lib, path43);
5438
+ const path45 = `${modelPath}#${arm.id}`;
5439
+ const session = await acquireHostSession(lib, path45);
5316
5440
  const system = "You are a coding agent with a Task Capsule.";
5317
5441
  const capsule = "function readConfig(): Config { return load(); }";
5318
5442
  let last = null;
@@ -6089,14 +6213,14 @@ function buildLocalInferenceStatus(opts) {
6089
6213
  const dynamicCustomSampler = /^(1|true|yes)$/i.test(String(env.VG_LLM_CUSTOM_SAMPLER ?? ""));
6090
6214
  const preferOllama = /^(1|true|yes)$/i.test(String(env.VG_PREFER_OLLAMA ?? ""));
6091
6215
  const weightCatalog = catalogIntegrityReport();
6092
- const cached = listCachedWeights(env);
6216
+ const cached2 = listCachedWeights(env);
6093
6217
  const sessions = listHostSessions();
6094
6218
  const recommendedMode = recommendMode(opts.system, opts.repo);
6095
6219
  const hints = [];
6096
6220
  if (!weightCatalog.complete) {
6097
6221
  hints.push(`weight catalog unpinned: ${weightCatalog.unpinned.join(", ")}`);
6098
6222
  }
6099
- if (cached.length === 0) {
6223
+ if (cached2.length === 0) {
6100
6224
  hints.push("no first-party GGUF in weight store \u2014 `vg models install` for embedded path");
6101
6225
  }
6102
6226
  if (preferOllama) {
@@ -6121,8 +6245,8 @@ function buildLocalInferenceStatus(opts) {
6121
6245
  weightCatalog,
6122
6246
  weightStore: {
6123
6247
  dir: weightStoreDir(env),
6124
- cachedGgufs: cached.length,
6125
- names: cached.map((w) => w.name).slice(0, 12)
6248
+ cachedGgufs: cached2.length,
6249
+ names: cached2.map((w) => w.name).slice(0, 12)
6126
6250
  },
6127
6251
  hostPool: {
6128
6252
  size: hostSessionPoolSize(),
@@ -6255,7 +6379,7 @@ function registerModels(program) {
6255
6379
  );
6256
6380
  });
6257
6381
  applyGlobalOptions(modeCmd);
6258
- const resolve21 = cmd.command("resolve").description("resolve a Code Mode to pack + underlying model + fit (no download)").argument("[mode]", "spark | flow | forge (default: auto-fit or configured default)").action(function(modeArg) {
6382
+ const resolve23 = cmd.command("resolve").description("resolve a Code Mode to pack + underlying model + fit (no download)").argument("[mode]", "spark | flow | forge (default: auto-fit or configured default)").action(function(modeArg) {
6259
6383
  const global = readGlobal(this);
6260
6384
  const root2 = rootOf(global);
6261
6385
  const sys = gatherSystemMemory();
@@ -6287,7 +6411,7 @@ function registerModels(program) {
6287
6411
  info(c.yellow(" will not fit \u2014 choose a lower mode or free memory before loading"));
6288
6412
  }
6289
6413
  });
6290
- applyGlobalOptions(resolve21);
6414
+ applyGlobalOptions(resolve23);
6291
6415
  const installCmd = cmd.command("install").description("resolve the best Code Mode for this machine and install the pack").argument("[mode]", "spark | flow | forge (default: auto-fit)").option("--dry-run", "print the install plan only \u2014 do not download").option("--yes", "skip prompts (install already runs by default)").action(async function(modeArg, opts) {
6292
6416
  const global = readGlobal(this);
6293
6417
  const root2 = rootOf(global);
@@ -6524,7 +6648,7 @@ function registerModels(program) {
6524
6648
  );
6525
6649
  }
6526
6650
  } else {
6527
- if (!target.path || !fs11.existsSync(target.path)) {
6651
+ if (!target.path || !fs12.existsSync(target.path)) {
6528
6652
  throw new CliError(
6529
6653
  `model file not found at ${target.path || "(unknown path)"} \u2014 it may already be removed.`,
6530
6654
  ExitCode.NOT_FOUND
@@ -6538,7 +6662,7 @@ function registerModels(program) {
6538
6662
  }
6539
6663
  if (!global.json) info(c.dim(` $ rm ${target.path}`));
6540
6664
  try {
6541
- fs11.unlinkSync(target.path);
6665
+ fs12.unlinkSync(target.path);
6542
6666
  } catch (e) {
6543
6667
  const msg = e instanceof Error ? e.message : String(e);
6544
6668
  throw new CliError(`could not delete ${target.path}: ${msg}`, ExitCode.ERROR);
@@ -6676,9 +6800,9 @@ function registerModels(program) {
6676
6800
  }
6677
6801
  });
6678
6802
  if (opts.out) {
6679
- const outPath = path41.resolve(opts.out);
6680
- fs11.mkdirSync(path41.dirname(outPath), { recursive: true });
6681
- fs11.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
6803
+ const outPath = path43.resolve(opts.out);
6804
+ fs12.mkdirSync(path43.dirname(outPath), { recursive: true });
6805
+ fs12.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
6682
6806
  `);
6683
6807
  if (!global.json) info(c.dim(` wrote ${outPath}`));
6684
6808
  }
@@ -6792,11 +6916,11 @@ function fitColor(label) {
6792
6916
  return label;
6793
6917
  }
6794
6918
  function confirmYesNo(question) {
6795
- return new Promise((resolve21) => {
6919
+ return new Promise((resolve23) => {
6796
6920
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
6797
6921
  rl.question(`${question} [y/N] `, (answer) => {
6798
6922
  rl.close();
6799
- resolve21(/^y(es)?$/i.test(answer.trim()));
6923
+ resolve23(/^y(es)?$/i.test(answer.trim()));
6800
6924
  });
6801
6925
  });
6802
6926
  }
@@ -6827,14 +6951,14 @@ function resolveUninstallTarget(name, runtimeOpt) {
6827
6951
  }
6828
6952
  return exact[0];
6829
6953
  }
6830
- const base = path41.basename(wantLc);
6954
+ const base = path43.basename(wantLc);
6831
6955
  const soft = fleet.filter((m) => {
6832
6956
  const n = m.name.toLowerCase();
6833
- return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) || path41.basename(n) === base;
6957
+ return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) || path43.basename(n) === base;
6834
6958
  });
6835
6959
  if (soft.length === 1) return soft[0];
6836
6960
  if (soft.length > 1) {
6837
- const baseHits = soft.filter((m) => path41.basename(m.name).toLowerCase() === base);
6961
+ const baseHits = soft.filter((m) => path43.basename(m.name).toLowerCase() === base);
6838
6962
  const pool = baseHits.length ? baseHits : soft;
6839
6963
  const order = ["ollama", "gguf", "lm-studio"];
6840
6964
  for (const rt of order) {
@@ -6872,11 +6996,11 @@ function printBackends(backends) {
6872
6996
  }
6873
6997
  }
6874
6998
  function codeConfigPath(root2) {
6875
- return path41.join(root2, ".vibgrate", "code.json");
6999
+ return path43.join(root2, ".vibgrate", "code.json");
6876
7000
  }
6877
7001
  function loadCodeConfig(root2) {
6878
7002
  try {
6879
- const raw = JSON.parse(fs11.readFileSync(codeConfigPath(root2), "utf8"));
7003
+ const raw = JSON.parse(fs12.readFileSync(codeConfigPath(root2), "utf8"));
6880
7004
  return sanitize(raw);
6881
7005
  } catch {
6882
7006
  return {};
@@ -6943,7 +7067,7 @@ function contextBudgetFor(config, modelContextWindow) {
6943
7067
  var MCP_CONFIG_FILES = [".cursor/mcp.json", ".vscode/mcp.json", ".mcp.json"];
6944
7068
  function readMcpServersFile(file) {
6945
7069
  try {
6946
- const raw = JSON.parse(fs11.readFileSync(file, "utf8"));
7070
+ const raw = JSON.parse(fs12.readFileSync(file, "utf8"));
6947
7071
  const map = raw.mcpServers ?? raw.servers;
6948
7072
  return map && typeof map === "object" ? parseMcpServers(map) : {};
6949
7073
  } catch {
@@ -6954,7 +7078,7 @@ function discoverMcpServers(root2, ownServers) {
6954
7078
  const servers = {};
6955
7079
  const sources = [];
6956
7080
  for (const rel of MCP_CONFIG_FILES) {
6957
- const found = readMcpServersFile(path41.join(root2, rel));
7081
+ const found = readMcpServersFile(path43.join(root2, rel));
6958
7082
  const names = Object.keys(found);
6959
7083
  if (names.length) {
6960
7084
  sources.push(rel);
@@ -6970,9 +7094,160 @@ function discoverMcpServers(root2, ownServers) {
6970
7094
 
6971
7095
  // src/commands/code.ts
6972
7096
  function registerCode(program) {
6973
- const cmd = program.command("code").description("propose a graph-grounded code edit (guided mode with no instruction; dry-run by default)").argument("[instruction...]", "what to change, in plain language (omit for guided interactive mode)").option("--provider <id>", "backend: vibgrate-relay (Vibgrate Relay), ollama, lmstudio, foundry-local, openrouter, litellm, openai, together, llama-cpp").option("--model <id>", "model id (or set VG_CODE_MODEL). No model is hard-coded \u2014 pick the current best.").option("--mode <mode>", "Code Mode: spark | flow | forge (preferred over raw model names; auto-fits when omitted and no --model)").option("--model-path <gguf>", "gguf path for --provider llama-cpp (weights are never auto-downloaded)").option("-f, --file <path>", "restrict the edit surface to this file (repeatable)", collect, []).option("-b, --budget <n>", "approx context token budget", "3000").option("--apply", "write the change (still requires --yes or an interactive confirm)").option("--yes", "consent to write / to a first-use package install, non-interactively").option("--auto", "autonomous agent: auto-approve every edit and command (use with care)").option("--max-steps <n>", "cap the number of agent steps", "24").option("--single", "one-shot planner (single edit) instead of the multi-step agent").option("--stream", "stream the model output live").option("--stream-json", "machine protocol: NDJSON agent events on stdout, approval decisions on stdin (for host UIs like the VS Code panel)").option("--session", "with --stream-json: stay open for further turns (warm graph and tools) instead of exiting after one").option("--verify [command]", "after the agent finishes, run tests and make it fix failures (uses the config testCommand if no command is given)").option("--continue", "resume the most recent session (recap + restore /undo)").option("--capsule", "use a source-bearing Task Capsule for first context (Fusion A/B; exact source ranges from the graph)").option("--no-capsule", "disable Task Capsule context even if enabled in .vibgrate/code.json").option("--security-tier <tier>", "shell isolation: L0 (host), L1 (Seatbelt/bubblewrap when available), L2/L3 reserved").option("--mock <file>", "use a scripted reply from <file> instead of a model (offline; for tests/CI)").option("-o, --out <file>", "write the JSON result to <file> (implies --json shape; for CI/benchmarks)").action(async function(instructionParts, opts) {
7097
+ const cmd = program.command("code").description("graph-grounded coding agent (guided mode with no instruction; every edit and command is approved)").argument("[instruction...]", "what to change, in plain language (omit for guided interactive mode)").option("--provider <id>", "backend: vibgrate-relay (Vibgrate Relay), ollama, lmstudio, foundry-local, openrouter, litellm, openai, together, llama-cpp").option("--model <id>", "model id (or set VG_CODE_MODEL). No model is hard-coded \u2014 pick the current best.").option("--mode <mode>", "Code Mode: spark | flow | forge (preferred over raw model names; auto-fits when omitted and no --model)").option("--model-path <gguf>", "gguf path for --provider llama-cpp (weights are never auto-downloaded)").option("-f, --file <path>", "restrict the edit surface to this file (repeatable)", collect, []).option("-b, --budget <n>", "approx context token budget", "3000").option("--apply", "one-shot path (--single/--mock) only: write the change (still requires --yes or an interactive confirm)").option("--yes", "consent to write / to a first-use package install, non-interactively").option("--auto", "autonomous agent: auto-approve every edit and command (use with care)").option("--max-steps <n>", "cap the number of agent steps", "24").option("--single", "one-shot planner (single edit) instead of the multi-step agent").option("--stream", "stream the model output live").option("--stream-json", "machine protocol: NDJSON agent events on stdout, approval decisions on stdin (for host UIs like the VS Code panel)").option("--session", "with --stream-json: stay open for further turns (warm graph and tools) instead of exiting after one").option("--verify [command]", "after the agent finishes, run tests and make it fix failures (uses the config testCommand if no command is given)").option("--continue [id]", "resume a session: the most recent one, or the given session id (recap + restore /undo)").option("--restore-checkpoint <commit>", "one-shot: restore the given --file paths from a checkpoint commit, then exit (for host UIs after the original session ended)").option("--reasoning-effort <level>", "how hard a reasoning-capable model should think: low | medium | high (ignored by models without the knob)").option("--worktree [id]", "run the session in an isolated git worktree under .vibgrate/worktrees (bare: create a new one; with id: reuse it)").option("--worktree-diff <id>", "one-shot: print the worktree's delta against its base as a patch, then exit").option("--worktree-apply <id>", "one-shot: apply the worktree's delta onto the main tree (git apply --3way), then exit").option("--worktree-remove <id>", "one-shot: remove the worktree checkout, then exit").option("--capsule", "use a source-bearing Task Capsule for first context (Fusion A/B; exact source ranges from the graph)").option("--no-capsule", "disable Task Capsule context even if enabled in .vibgrate/code.json").option("--security-tier <tier>", "shell isolation: L0 (host), L1 (Seatbelt/bubblewrap when available), L2/L3 reserved").option("--mock <file>", "use a scripted reply from <file> instead of a model (offline; for tests/CI)").option("-o, --out <file>", "write the JSON result to <file> (implies --json shape; for CI/benchmarks)").action(async function(instructionParts, opts) {
6974
7098
  const global = readGlobal(this);
6975
- const instruction = (instructionParts ?? []).join(" ").trim();
7099
+ let instruction = (instructionParts ?? []).join(" ").trim();
7100
+ if (typeof opts.continue === "string") {
7101
+ const { looksLikeSessionId } = await import('./session-store-AQUORKWB.js');
7102
+ if (!looksLikeSessionId(opts.continue)) {
7103
+ instruction = [opts.continue, instruction].filter(Boolean).join(" ");
7104
+ opts.continue = true;
7105
+ }
7106
+ }
7107
+ if (opts.restoreCheckpoint) {
7108
+ const { restoreCheckpoint, isValidCheckpointCommit } = await import('./checkpoint-UYMYMMQO.js');
7109
+ if (!isValidCheckpointCommit(opts.restoreCheckpoint)) {
7110
+ throw usageError("--restore-checkpoint expects a checkpoint commit id (hex SHA)");
7111
+ }
7112
+ const files = (opts.file ?? []).filter(Boolean);
7113
+ if (!files.length) {
7114
+ throw usageError("--restore-checkpoint needs the files to restore, e.g. -f src/a.ts -f src/b.ts");
7115
+ }
7116
+ const root3 = rootOf(global);
7117
+ const child = await import('child_process');
7118
+ const gitRunner = (gitArgs, gitEnv) => {
7119
+ const res = child.spawnSync("git", gitArgs, {
7120
+ cwd: root3,
7121
+ encoding: "utf8",
7122
+ env: { ...process.env, ...gitEnv ?? {} },
7123
+ timeout: 3e4,
7124
+ maxBuffer: 32 * 1024 * 1024
7125
+ });
7126
+ return { stdout: res.stdout ?? "", exitCode: res.status ?? 1 };
7127
+ };
7128
+ const outcome = restoreCheckpoint(gitRunner, { commit: opts.restoreCheckpoint, files });
7129
+ if (opts.streamJson) {
7130
+ process.stdout.write(
7131
+ JSON.stringify({ event: "checkpoint-restored", commit: opts.restoreCheckpoint, ...outcome }) + "\n"
7132
+ );
7133
+ } else if (global.json) {
7134
+ json({ commit: opts.restoreCheckpoint, ...outcome });
7135
+ } else {
7136
+ out(
7137
+ `restored ${outcome.restored.length}, removed ${outcome.removed.length}, failed ${outcome.failed.length}`
7138
+ );
7139
+ }
7140
+ if (outcome.failed.length) process.exitCode = 1;
7141
+ return;
7142
+ }
7143
+ if (opts.worktreeDiff || opts.worktreeApply || opts.worktreeRemove) {
7144
+ const wt = await import('./worktree-session-D575IQWM.js');
7145
+ const child = await import('child_process');
7146
+ const os7 = await import('os');
7147
+ const pathMod = await import('path');
7148
+ const root3 = rootOf(global);
7149
+ const gitRunner = (gitArgs, gitEnv) => {
7150
+ const res = child.spawnSync("git", gitArgs, {
7151
+ cwd: root3,
7152
+ encoding: "utf8",
7153
+ env: { ...process.env, ...gitEnv ?? {} },
7154
+ timeout: 6e4,
7155
+ maxBuffer: 64 * 1024 * 1024
7156
+ });
7157
+ return { stdout: (res.stdout ?? "") + (res.stderr ?? ""), exitCode: res.status ?? 1 };
7158
+ };
7159
+ const emitLine = (line) => {
7160
+ if (opts.streamJson) process.stdout.write(JSON.stringify(line) + "\n");
7161
+ else if (global.json) json(line);
7162
+ };
7163
+ const findWt = (id) => wt.listSessionWorktrees(gitRunner, root3).find((w) => w.id === id);
7164
+ if (opts.worktreeDiff) {
7165
+ const target = findWt(opts.worktreeDiff);
7166
+ if (!target) throw new CliError(`no worktree ${opts.worktreeDiff} under .vibgrate/worktrees`, ExitCode.NOT_FOUND);
7167
+ const diff2 = wt.worktreeDiffToBase(gitRunner, target.path, target.base);
7168
+ if ("error" in diff2) throw new CliError(diff2.error, ExitCode.ERROR);
7169
+ const MAX_PATCH = 2 * 1024 * 1024;
7170
+ const truncated = diff2.patch.length > MAX_PATCH;
7171
+ emitLine({
7172
+ event: "worktree-diff",
7173
+ id: target.id,
7174
+ base: target.base,
7175
+ files: diff2.files,
7176
+ patch: truncated ? diff2.patch.slice(0, MAX_PATCH) : diff2.patch,
7177
+ truncated
7178
+ });
7179
+ if (!opts.streamJson && !global.json) {
7180
+ out(diff2.patch || `worktree ${target.id}: no changes vs base`);
7181
+ }
7182
+ return;
7183
+ }
7184
+ if (opts.worktreeApply) {
7185
+ const target = findWt(opts.worktreeApply);
7186
+ if (!target) throw new CliError(`no worktree ${opts.worktreeApply} under .vibgrate/worktrees`, ExitCode.NOT_FOUND);
7187
+ const diff2 = wt.worktreeDiffToBase(gitRunner, target.path, target.base);
7188
+ if ("error" in diff2) throw new CliError(diff2.error, ExitCode.ERROR);
7189
+ if (!diff2.files.length) {
7190
+ emitLine({ event: "worktree-applied", id: target.id, applied: true, files: [] });
7191
+ if (!opts.streamJson && !global.json) out(`worktree ${target.id}: nothing to apply`);
7192
+ return;
7193
+ }
7194
+ const patchFile = pathMod.join(
7195
+ fs12.mkdtempSync(pathMod.join(os7.tmpdir(), "vg-wt-")),
7196
+ "delta.patch"
7197
+ );
7198
+ fs12.writeFileSync(patchFile, diff2.patch);
7199
+ const outcome = wt.applyWorktreePatch(gitRunner, root3, patchFile, diff2.files);
7200
+ emitLine({ event: "worktree-applied", id: target.id, ...outcome });
7201
+ if (!opts.streamJson && !global.json) {
7202
+ out(
7203
+ outcome.applied ? `applied ${outcome.files.length} file(s) from worktree ${target.id}` : `apply failed: ${outcome.error}`
7204
+ );
7205
+ }
7206
+ if (!outcome.applied) process.exitCode = 1;
7207
+ return;
7208
+ }
7209
+ if (opts.worktreeRemove) {
7210
+ const outcome = wt.removeSessionWorktree(gitRunner, root3, opts.worktreeRemove);
7211
+ emitLine({ event: "worktree-removed", id: opts.worktreeRemove, ...outcome });
7212
+ if (!opts.streamJson && !global.json) {
7213
+ out(outcome.removed ? `removed worktree ${opts.worktreeRemove}` : `remove failed: ${outcome.error}`);
7214
+ }
7215
+ if (!outcome.removed) process.exitCode = 1;
7216
+ return;
7217
+ }
7218
+ }
7219
+ const mainRoot = rootOf(global);
7220
+ let activeWorktree;
7221
+ if (opts.worktree) {
7222
+ const wt = await import('./worktree-session-D575IQWM.js');
7223
+ const child = await import('child_process');
7224
+ const gitRunner = (gitArgs, gitEnv) => {
7225
+ const res = child.spawnSync("git", gitArgs, {
7226
+ cwd: mainRoot,
7227
+ encoding: "utf8",
7228
+ env: { ...process.env, ...gitEnv ?? {} },
7229
+ timeout: 6e4,
7230
+ maxBuffer: 64 * 1024 * 1024
7231
+ });
7232
+ return { stdout: (res.stdout ?? "") + (res.stderr ?? ""), exitCode: res.status ?? 1 };
7233
+ };
7234
+ if (typeof opts.worktree === "string") {
7235
+ const existing = wt.listSessionWorktrees(gitRunner, mainRoot).find((w) => w.id === opts.worktree);
7236
+ if (!existing) {
7237
+ throw new CliError(`no worktree ${opts.worktree} under .vibgrate/worktrees \u2014 start one with --worktree`, ExitCode.NOT_FOUND);
7238
+ }
7239
+ activeWorktree = existing;
7240
+ } else {
7241
+ const created = wt.createSessionWorktree(
7242
+ gitRunner,
7243
+ mainRoot,
7244
+ `wt${Date.now().toString(36)}`
7245
+ );
7246
+ if ("error" in created) throw new CliError(created.error, ExitCode.ERROR);
7247
+ activeWorktree = created;
7248
+ }
7249
+ global.cwd = activeWorktree.path;
7250
+ }
6976
7251
  if (!global.local) {
6977
7252
  await ensureRelevanceModule();
6978
7253
  }
@@ -6986,7 +7261,7 @@ function registerCode(program) {
6986
7261
  try {
6987
7262
  const { parseMode: parseMode2, resolveMode: resolveMode2, readOrchestratorState: readOrchestratorState2, activePin: activePin2 } = await import('./model-orchestrator-LHYPJBFH.js');
6988
7263
  const { gatherSystemMemory: gatherSystemMemory2 } = await import('./local-runtime-2ED33KK6.js');
6989
- const { loadGraph: loadGraph2 } = await import('./load-EUZSV73H.js');
7264
+ const { loadGraph: loadGraph2 } = await import('./load-64RK5O6C.js');
6990
7265
  const state = readOrchestratorState2();
6991
7266
  const mode = parseMode2(modeFlag) ?? state.defaultMode ?? void 0;
6992
7267
  const pin = mode ? activePin2(mode, state) : null;
@@ -7071,7 +7346,7 @@ function registerCode(program) {
7071
7346
  if (!(process.stdin.isTTY && process.stdout.isTTY)) {
7072
7347
  throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"` (guided mode needs an interactive terminal)');
7073
7348
  }
7074
- const { runInteractive } = await import('./interactive-WUXMXFNM.js');
7349
+ const { runInteractive } = await import('./interactive-EW2VJ3BZ.js');
7075
7350
  await runInteractive(
7076
7351
  rootOf(global),
7077
7352
  global,
@@ -7101,7 +7376,7 @@ function registerCode(program) {
7101
7376
  }
7102
7377
  if (!instruction && !stdinFirstTurn) throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"`');
7103
7378
  {
7104
- const { ensureCodeMap } = await import('./ensure-map-PHAJACFF.js');
7379
+ const { ensureCodeMap } = await import('./ensure-map-HQ7A5NDL.js');
7105
7380
  const mapRoot = rootOf(global);
7106
7381
  try {
7107
7382
  await ensureCodeMap(mapRoot, global, {
@@ -7138,7 +7413,7 @@ function registerCode(program) {
7138
7413
  let mockReply;
7139
7414
  if (opts.mock) {
7140
7415
  try {
7141
- mockReply = fs11.readFileSync(opts.mock, "utf8");
7416
+ mockReply = fs12.readFileSync(opts.mock, "utf8");
7142
7417
  } catch {
7143
7418
  throw new CliError(`couldn't read the --mock file: ${opts.mock}`, ExitCode.USAGE_ERROR);
7144
7419
  }
@@ -7186,20 +7461,20 @@ function registerCode(program) {
7186
7461
  process.stdout.write(JSON.stringify(line) + "\n");
7187
7462
  };
7188
7463
  try {
7189
- const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-O5PR7ZCK.js');
7464
+ const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-6QNQIHPV.js');
7190
7465
  const primarySlug = route.providers[0]?.model.includes("/") ? route.providers[0].model.split("/")[0] : route.providers[0]?.id;
7191
- const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-7MK3QQYG.js');
7192
- const { nodeCodeFs } = await import('./session-WS7SOVJE.js');
7466
+ const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-GY5N7WZT.js');
7467
+ const { nodeCodeFs } = await import('./session-4BGYASOH.js');
7193
7468
  const readline6 = await import('readline');
7194
7469
  const child = await import('child_process');
7195
7470
  const { loadOrDiscoverFederation } = await import('./federation-MDQPO3PW.js');
7196
7471
  const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
7197
7472
  const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
7198
- const { startCodeRuntimeSession } = await import('./runtime-session-PPQDTFIK.js');
7199
- const { resolveGraphBackend } = await import('./graph-backend-4B3MTVIW.js');
7473
+ const { startCodeRuntimeSession } = await import('./runtime-session-RJHH3KMF.js');
7474
+ const { resolveGraphBackend } = await import('./graph-backend-W2TNTMY7.js');
7200
7475
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
7201
7476
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
7202
- const { vgdRequest: vgdRequest2 } = await import('./vgd-Y25XSQGZ.js');
7477
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-ORPA5C2K.js');
7203
7478
  const federation = loadOrDiscoverFederation(root2);
7204
7479
  const modelProfile = mergeModelExecutionProfile(
7205
7480
  resolveModelExecutionProfile({
@@ -7257,7 +7532,7 @@ ${res.stderr}` : ""),
7257
7532
  exitCode: res.status ?? 1
7258
7533
  };
7259
7534
  };
7260
- const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-DQLCHBI6.js');
7535
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-IGHJKKSL.js');
7261
7536
  const vgBuiltin = createVgBuiltinMcpTools({
7262
7537
  getGraph: () => graph,
7263
7538
  root: root2,
@@ -7277,11 +7552,11 @@ ${res.stderr}` : ""),
7277
7552
  };
7278
7553
  }
7279
7554
  const externalTools = mergeExternalToolsets(vgBuiltin, projectMcp);
7280
- const { createCheckpoint } = await import('./checkpoint-4WFZMKEO.js');
7281
- const os6 = await import('os');
7555
+ const { createCheckpoint } = await import('./checkpoint-UYMYMMQO.js');
7556
+ const os7 = await import('os');
7282
7557
  const pathMod = await import('path');
7283
7558
  const checkpointIndex = pathMod.join(
7284
- fs11.mkdtempSync(pathMod.join(os6.tmpdir(), "vg-code-cp-")),
7559
+ fs12.mkdtempSync(pathMod.join(os7.tmpdir(), "vg-code-cp-")),
7285
7560
  "index"
7286
7561
  );
7287
7562
  const gitRunner = (gitArgs, gitEnv) => {
@@ -7302,6 +7577,7 @@ ${res.stderr}` : ""),
7302
7577
  files,
7303
7578
  indexFile: checkpointIndex
7304
7579
  });
7580
+ const { loadApprovalRules, addApprovalRule, ruleForAction, ruleLabel } = await import('./approvals-T2KXPJLV.js');
7305
7581
  const { loadProjectRules, nodeRulesReader } = await import('./rules-ASYEUNB5.js');
7306
7582
  const projectRules = loadProjectRules(nodeRulesReader(root2));
7307
7583
  if (projectRules.sources.length && !global.quiet) {
@@ -7325,6 +7601,9 @@ ${res.stderr}` : ""),
7325
7601
  graphBackend,
7326
7602
  modelProfile,
7327
7603
  auto: !!auto,
7604
+ // v5: spawn-time reasoning budget. Session mode lets a per-turn
7605
+ // value override it; one-shot runs use this.
7606
+ reasoningEffort: parseReasoningEffort(opts.reasoningEffort),
7328
7607
  maxSteps,
7329
7608
  budget: modelProfile.capsuleBudgetTokens,
7330
7609
  contextBudget,
@@ -7347,27 +7626,43 @@ ${res.stderr}` : ""),
7347
7626
  },
7348
7627
  now: () => Date.now(),
7349
7628
  projectRules: projectRules.rendered || void 0,
7350
- checkpoint: takeCheckpoint
7629
+ checkpoint: takeCheckpoint,
7630
+ // Standing allow-always rules, re-read per approval so an
7631
+ // "Always allow" or a revocation applies to the very next action.
7632
+ // Always the MAIN root: consent is per-developer, and a worktree
7633
+ // checkout has no code-approvals.json (it is gitignored).
7634
+ approvalRules: () => loadApprovalRules(mainRoot)
7351
7635
  };
7352
7636
  try {
7353
7637
  if (opts.session) {
7354
- const { runCodeStreamJsonSession } = await import('./stream-json-7MK3QQYG.js');
7355
- const { runAgent: runAgent2 } = await import('./agent-N3CP3SPI.js');
7638
+ const { runCodeStreamJsonSession, STREAM_JSON_PROTOCOL_VERSION } = await import('./stream-json-GY5N7WZT.js');
7639
+ const { runAgent: runAgent2 } = await import('./agent-5ANHRYEI.js');
7356
7640
  const {
7357
7641
  condenseSession,
7358
7642
  loadLatestSession,
7643
+ loadSession,
7359
7644
  newSession,
7360
7645
  recordTask,
7361
7646
  saveSession,
7647
+ sessionsDir,
7362
7648
  summarizeSession
7363
- } = await import('./session-store-KGONLWHN.js');
7364
- const resumedRecord = opts.continue ? loadLatestSession(root2) : void 0;
7649
+ } = await import('./session-store-AQUORKWB.js');
7650
+ const { VERSION: VERSION2 } = await import('./version-DPAMQW6M.js');
7651
+ const resumedRecord = typeof opts.continue === "string" ? loadSession(mainRoot, opts.continue) : opts.continue ? loadLatestSession(mainRoot) : void 0;
7652
+ if (typeof opts.continue === "string" && !resumedRecord) {
7653
+ emitStream({
7654
+ event: "event",
7655
+ type: "notice",
7656
+ text: `Could not load session ${opts.continue} \u2014 starting a fresh conversation.`
7657
+ });
7658
+ }
7365
7659
  let record = resumedRecord ?? newSession(
7366
7660
  `s${Date.now().toString(36)}`,
7367
7661
  primarySlug ?? route.providers[0]?.id ?? "unknown",
7368
7662
  route.providers[0]?.model ?? "unknown",
7369
7663
  Date.now()
7370
7664
  );
7665
+ if (activeWorktree) record = { ...record, worktree: activeWorktree };
7371
7666
  const pendingTurns = [];
7372
7667
  let wakeTurn;
7373
7668
  let ended = false;
@@ -7384,32 +7679,54 @@ ${res.stderr}` : ""),
7384
7679
  if (ended) return Promise.resolve(null);
7385
7680
  const queued = pendingTurns.shift();
7386
7681
  if (queued !== void 0) return Promise.resolve(queued);
7387
- return new Promise((resolve21) => {
7388
- wakeTurn = resolve21;
7682
+ return new Promise((resolve23) => {
7683
+ wakeTurn = resolve23;
7389
7684
  });
7390
7685
  };
7391
7686
  let turnIndex = 0;
7687
+ let lastTurnAttachments;
7392
7688
  await runCodeStreamJsonSession({
7393
7689
  emit: emitAndRecord,
7394
7690
  auto: !!auto,
7395
7691
  sessionId: record.id,
7396
7692
  resumed: !!resumedRecord,
7693
+ // Environment facts for the host: where sessions live (the
7694
+ // single source of truth for history UIs, fixing multi-root
7695
+ // ambiguity) and the versions in play for its first-use report.
7696
+ sessionInfo: {
7697
+ sessionDir: sessionsDir(mainRoot),
7698
+ engineVersion: VERSION2,
7699
+ protocolVersion: STREAM_JSON_PROTOCOL_VERSION,
7700
+ provider: primarySlug,
7701
+ model: route.providers[0]?.model,
7702
+ ...activeWorktree ? { worktree: { path: activeWorktree.path, base: activeWorktree.base } } : {}
7703
+ },
7397
7704
  instruction,
7398
7705
  nextTurn,
7399
7706
  bindDecisions: (session) => {
7400
7707
  streamApprove = (action) => session.approve(action);
7708
+ session.onAlwaysRule = (action) => {
7709
+ const rule = ruleForAction(action);
7710
+ if (!rule) return;
7711
+ const saved = addApprovalRule(mainRoot, rule);
7712
+ emitStream({
7713
+ event: "event",
7714
+ type: "notice",
7715
+ text: saved ? `Always-allow rule saved: ${ruleLabel(rule)} (manage in .vibgrate/code-approvals.json)` : "Could not save the always-allow rule (is .vibgrate writable?) \u2014 approved this once."
7716
+ });
7717
+ };
7401
7718
  const rl = readline6.createInterface({ input: process.stdin });
7402
7719
  rl.on("line", (raw) => {
7403
7720
  const msg = parseHostMessage(raw);
7404
7721
  if (!msg) return;
7405
7722
  if (msg.kind === "approve") {
7406
- session.submitDecision(msg.id, msg.approve);
7723
+ session.submitDecision(msg.id, msg.approve, msg.always);
7407
7724
  runOutcome.noteDecision(msg.id, msg.approve);
7408
7725
  } else if (msg.kind === "answer") session.submitAnswer(msg.id, msg.answer);
7409
7726
  else if (msg.kind === "submit")
7410
7727
  pushTurn({ instruction: msg.instruction, agentMode: msg.agentMode, images: msg.images });
7411
7728
  else if (msg.kind === "restore") {
7412
- void import('./checkpoint-4WFZMKEO.js').then(({ restoreCheckpoint }) => {
7729
+ void import('./checkpoint-UYMYMMQO.js').then(({ restoreCheckpoint }) => {
7413
7730
  const outcome = restoreCheckpoint(gitRunner, {
7414
7731
  commit: msg.commit,
7415
7732
  files: msg.files
@@ -7418,12 +7735,22 @@ ${res.stderr}` : ""),
7418
7735
  });
7419
7736
  } else if (msg.kind === "compact") {
7420
7737
  record = condenseSession(record, Date.now());
7421
- saveSession(root2, record);
7738
+ saveSession(mainRoot, record);
7422
7739
  emitStream({
7423
7740
  event: "event",
7424
7741
  type: "notice",
7425
7742
  text: "Conversation compacted \u2014 earlier turns condensed into a checkpoint."
7426
7743
  });
7744
+ } else if (msg.kind === "inject") {
7745
+ session.inject(msg.text);
7746
+ } else if (msg.kind === "rename") {
7747
+ const t = msg.title.slice(0, 120);
7748
+ if (t) record = { ...record, title: t };
7749
+ else {
7750
+ record = { ...record };
7751
+ delete record.title;
7752
+ }
7753
+ saveSession(mainRoot, record);
7427
7754
  } else if (msg.kind === "cancel") {
7428
7755
  session.cancelTurn();
7429
7756
  runOutcome.cancelPending();
@@ -7439,7 +7766,8 @@ ${res.stderr}` : ""),
7439
7766
  pushTurn(null);
7440
7767
  });
7441
7768
  },
7442
- runTurn: ({ instruction: turnInstruction, signal, session, agentMode, auto: turnAuto, images }) => {
7769
+ runTurn: ({ instruction: turnInstruction, signal, session, agentMode, auto: turnAuto, images, reasoningEffort: turnEffort, attachments: turnAttachments }) => {
7770
+ lastTurnAttachments = turnAttachments;
7443
7771
  const priorSummary = summarizeSession(record) || void 0;
7444
7772
  turnIndex++;
7445
7773
  runOutcome.beginRun(turnRunId(record.id, turnIndex), turnInstruction);
@@ -7448,6 +7776,8 @@ ${res.stderr}` : ""),
7448
7776
  return runAgent2({
7449
7777
  ...baseAgentOptions,
7450
7778
  instruction: turnInstruction,
7779
+ // v4 steer: the loop drains injected content at each step.
7780
+ takeInjected: () => session.drainInjected(),
7451
7781
  priorSummary,
7452
7782
  // Carry-over for capsule seed ranking: the previous
7453
7783
  // turn's instruction (the current turn is recorded only
@@ -7457,6 +7787,9 @@ ${res.stderr}` : ""),
7457
7787
  auto: turnAuto,
7458
7788
  plan,
7459
7789
  images,
7790
+ // v5: per-turn reasoning budget beats the spawn-time flag,
7791
+ // so a host's effort picker takes effect without a respawn.
7792
+ reasoningEffort: turnEffort ?? baseAgentOptions.reasoningEffort,
7460
7793
  approve: session.approve,
7461
7794
  askUser: session.askUser,
7462
7795
  onEvent: session.onEvent
@@ -7469,11 +7802,13 @@ ${res.stderr}` : ""),
7469
7802
  instruction: turn.instruction,
7470
7803
  summary: turn.result?.finalText ?? "turn failed",
7471
7804
  changes: turn.result?.changes ?? [],
7472
- stopped: turn.result?.stopped ?? "error"
7805
+ stopped: turn.result?.stopped ?? "error",
7806
+ // Metadata only — recordTask never stores the bytes.
7807
+ attachments: lastTurnAttachments
7473
7808
  },
7474
7809
  Date.now()
7475
7810
  );
7476
- saveSession(root2, record);
7811
+ saveSession(mainRoot, record);
7477
7812
  return summarizeSession(record);
7478
7813
  }
7479
7814
  });
@@ -7485,12 +7820,16 @@ ${res.stderr}` : ""),
7485
7820
  emit: emitAndRecord,
7486
7821
  bindDecisions: (session) => {
7487
7822
  streamApprove = (action) => session.approve(action);
7823
+ session.onAlwaysRule = (action) => {
7824
+ const rule = ruleForAction(action);
7825
+ if (rule) addApprovalRule(mainRoot, rule);
7826
+ };
7488
7827
  const rl = readline6.createInterface({ input: process.stdin });
7489
7828
  rl.on("line", (raw) => {
7490
7829
  const msg = parseHostMessage(raw);
7491
7830
  if (!msg) return;
7492
7831
  if (msg.kind === "approve") {
7493
- session.submitDecision(msg.id, msg.approve);
7832
+ session.submitDecision(msg.id, msg.approve, msg.always);
7494
7833
  runOutcome.noteDecision(msg.id, msg.approve);
7495
7834
  } else if (msg.kind === "answer") session.submitAnswer(msg.id, msg.answer);
7496
7835
  else if (msg.kind === "cancel") {
@@ -7520,21 +7859,23 @@ ${res.stderr}` : ""),
7520
7859
  if (!autonomous && !tty) {
7521
7860
  throw usageError("the agent approves each edit/command \u2014 run in a terminal to approve interactively, or pass --auto to run autonomously (or --single for a one-shot diff).");
7522
7861
  }
7523
- const { agentTask } = await import('./interactive-WUXMXFNM.js');
7524
- const { nodeCodeFs } = await import('./session-WS7SOVJE.js');
7862
+ const { agentTask } = await import('./interactive-EW2VJ3BZ.js');
7863
+ const { nodeCodeFs } = await import('./session-4BGYASOH.js');
7525
7864
  const { TtyPrompter } = await import('./ui-K7D3BCHD.js');
7526
7865
  let priorSummary;
7527
7866
  let priorInstruction;
7528
7867
  if (opts.continue) {
7529
- const { loadLatestSession, summarizeSession } = await import('./session-store-KGONLWHN.js');
7530
- const prev = loadLatestSession(root2);
7868
+ const { loadLatestSession, loadSession, summarizeSession } = await import('./session-store-AQUORKWB.js');
7869
+ const prev = typeof opts.continue === "string" ? loadSession(mainRoot, opts.continue) : loadLatestSession(mainRoot);
7531
7870
  if (prev) {
7532
7871
  priorSummary = summarizeSession(prev);
7533
7872
  priorInstruction = prev.tasks.at(-1)?.instruction;
7873
+ } else if (typeof opts.continue === "string") {
7874
+ info(`could not load session ${opts.continue} \u2014 continuing without its recap`);
7534
7875
  }
7535
7876
  }
7536
7877
  const prompter = tty ? new TtyPrompter() : void 0;
7537
- const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-DQLCHBI6.js');
7878
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-IGHJKKSL.js');
7538
7879
  const vgBuiltin = createVgBuiltinMcpTools({
7539
7880
  getGraph: () => graph,
7540
7881
  root: root2,
@@ -7558,11 +7899,11 @@ ${res.stderr}` : ""),
7558
7899
  const { loadFederation } = await import('./federation-MDQPO3PW.js');
7559
7900
  const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
7560
7901
  const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
7561
- const { startCodeRuntimeSession } = await import('./runtime-session-PPQDTFIK.js');
7562
- const { resolveGraphBackend } = await import('./graph-backend-4B3MTVIW.js');
7902
+ const { startCodeRuntimeSession } = await import('./runtime-session-RJHH3KMF.js');
7903
+ const { resolveGraphBackend } = await import('./graph-backend-W2TNTMY7.js');
7563
7904
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
7564
7905
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
7565
- const { vgdRequest: vgdRequest2 } = await import('./vgd-Y25XSQGZ.js');
7906
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-ORPA5C2K.js');
7566
7907
  const federation = loadFederation(root2);
7567
7908
  const modelProfile = mergeModelExecutionProfile(
7568
7909
  resolveModelExecutionProfile({
@@ -7656,7 +7997,7 @@ ${res.stderr}` : ""),
7656
7997
  attribution: { client: "vg-code", provider: providerSlug, model: primary?.model }
7657
7998
  });
7658
7999
  if (opts.out) {
7659
- fs11.writeFileSync(opts.out, JSON.stringify(result, null, 2) + "\n");
8000
+ fs12.writeFileSync(opts.out, JSON.stringify(result, null, 2) + "\n");
7660
8001
  }
7661
8002
  if (global.json) {
7662
8003
  json(result);
@@ -7708,11 +8049,11 @@ function resolveSecurityTierFlag(flag, fromConfig, auto) {
7708
8049
  return auto ? "L1" : "L0";
7709
8050
  }
7710
8051
  function confirm2(question) {
7711
- return new Promise((resolve21) => {
8052
+ return new Promise((resolve23) => {
7712
8053
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
7713
8054
  rl.question(`${question} [y/N] `, (answer) => {
7714
8055
  rl.close();
7715
- resolve21(/^y(es)?$/i.test(answer.trim()));
8056
+ resolve23(/^y(es)?$/i.test(answer.trim()));
7716
8057
  });
7717
8058
  });
7718
8059
  }
@@ -7869,7 +8210,7 @@ async function addCmd(root2, rest, opts, asJson) {
7869
8210
  }
7870
8211
  function readPackageVersion(root2) {
7871
8212
  try {
7872
- const pkg = JSON.parse(fs11__default.readFileSync(path41__default.join(root2, "package.json"), "utf8"));
8213
+ const pkg = JSON.parse(fs12__default.readFileSync(path43__default.join(root2, "package.json"), "utf8"));
7873
8214
  return typeof pkg.version === "string" ? pkg.version : void 0;
7874
8215
  } catch {
7875
8216
  return void 0;
@@ -7877,7 +8218,7 @@ function readPackageVersion(root2) {
7877
8218
  }
7878
8219
  function readOptionalFile(p) {
7879
8220
  try {
7880
- const t = fs11__default.readFileSync(p, "utf8");
8221
+ const t = fs12__default.readFileSync(p, "utf8");
7881
8222
  return t.trim() ? t : void 0;
7882
8223
  } catch {
7883
8224
  return void 0;
@@ -7892,8 +8233,8 @@ async function publishCmd(root2, rest, opts, global, asJson) {
7892
8233
  if (!parsed) throw new CliError("publishing a private library requires a DSN \u2014 run `vibgrate login` or set VIBGRATE_DSN", ExitCode.USAGE_ERROR);
7893
8234
  const version = (opts.version || readPackageVersion(root2) || "").trim();
7894
8235
  if (!version) throw usageError("a --version is required (or run from a package whose package.json has a version)");
7895
- const readme = readOptionalFile(opts.readme ? path41__default.resolve(opts.readme) : path41__default.join(root2, "README.md"));
7896
- const dts = opts.dts ? readOptionalFile(path41__default.resolve(opts.dts)) : void 0;
8236
+ const readme = readOptionalFile(opts.readme ? path43__default.resolve(opts.readme) : path43__default.join(root2, "README.md"));
8237
+ const dts = opts.dts ? readOptionalFile(path43__default.resolve(opts.dts)) : void 0;
7897
8238
  if (!readme && !dts) throw usageError("nothing to publish \u2014 no README.md found and no --dts given");
7898
8239
  const result = await publishPrivateLibrary(
7899
8240
  { name, version, readme, dts, language: opts.language },
@@ -8025,8 +8366,8 @@ function registerExport(program) {
8025
8366
  out(content.trimEnd());
8026
8367
  return;
8027
8368
  }
8028
- fs11.mkdirSync(path41.dirname(path41.resolve(file)), { recursive: true });
8029
- fs11.writeFileSync(file, content);
8369
+ fs12.mkdirSync(path43.dirname(path43.resolve(file)), { recursive: true });
8370
+ fs12.writeFileSync(file, content);
8030
8371
  info(`${c.green("\u2714")} wrote ${file} ${c.dim(`(${format})`)}`);
8031
8372
  });
8032
8373
  applyGlobalOptions(cmd);
@@ -8036,43 +8377,43 @@ function detectFormat(file) {
8036
8377
  if (lower.endsWith(".cdx.json")) return "cyclonedx";
8037
8378
  if (lower.endsWith(".spdx.json")) return "spdx";
8038
8379
  if (file === "-") return "json";
8039
- return formatForExt(path41.extname(file));
8380
+ return formatForExt(path43.extname(file));
8040
8381
  }
8041
8382
  function registerBundle(program) {
8042
8383
  const cmd = program.command("bundle").description("build an air-gapped bundle (grammars + graph + library catalog)").option("--offline", "offline bundle (default; present for clarity)").option("-o, --out <dir>", "output directory", "vg-bundle").action(function(opts) {
8043
8384
  const global = readGlobal(this);
8044
8385
  const root2 = rootOf(global);
8045
- const outDir = path41.resolve(root2, opts.out ?? "vg-bundle");
8386
+ const outDir = path43.resolve(root2, opts.out ?? "vg-bundle");
8046
8387
  let grammarFiles;
8047
8388
  try {
8048
8389
  grammarFiles = resolvedGrammarFiles();
8049
8390
  } catch {
8050
8391
  throw new CliError("no grammars found to bundle (run a build first)", ExitCode.ERROR);
8051
8392
  }
8052
- fs11.mkdirSync(path41.join(outDir, "grammars"), { recursive: true });
8393
+ fs12.mkdirSync(path43.join(outDir, "grammars"), { recursive: true });
8053
8394
  let grammarCount = 0;
8054
8395
  for (const { fileName, absPath } of grammarFiles) {
8055
- fs11.copyFileSync(absPath, path41.join(outDir, "grammars", fileName));
8396
+ fs12.copyFileSync(absPath, path43.join(outDir, "grammars", fileName));
8056
8397
  grammarCount++;
8057
8398
  }
8058
8399
  const included = [`grammars/ (${grammarCount} .wasm)`];
8059
8400
  const graphSrc = resolveGraphPath(root2, global.graph);
8060
- if (fs11.existsSync(graphSrc)) {
8061
- fs11.copyFileSync(graphSrc, path41.join(outDir, "graph.json"));
8401
+ if (fs12.existsSync(graphSrc)) {
8402
+ fs12.copyFileSync(graphSrc, path43.join(outDir, "graph.json"));
8062
8403
  included.push("graph.json");
8063
8404
  } else {
8064
8405
  const graph = loadGraphFileWithSnapshot(graphSrc);
8065
8406
  if (graph) {
8066
- fs11.writeFileSync(path41.join(outDir, "graph.json"), serializeGraph(graph));
8407
+ fs12.writeFileSync(path43.join(outDir, "graph.json"), serializeGraph(graph));
8067
8408
  included.push("graph.json");
8068
8409
  }
8069
8410
  }
8070
8411
  const cat = catalogPath(root2);
8071
- if (fs11.existsSync(cat)) {
8072
- fs11.copyFileSync(cat, path41.join(outDir, "vibgrate.lib.json"));
8412
+ if (fs12.existsSync(cat)) {
8413
+ fs12.copyFileSync(cat, path43.join(outDir, "vibgrate.lib.json"));
8073
8414
  included.push("vibgrate.lib.json");
8074
- if (fs11.existsSync(libDir(root2))) {
8075
- fs11.cpSync(libDir(root2), path41.join(outDir, "lib"), { recursive: true });
8415
+ if (fs12.existsSync(libDir(root2))) {
8416
+ fs12.cpSync(libDir(root2), path43.join(outDir, "lib"), { recursive: true });
8076
8417
  included.push("lib/");
8077
8418
  }
8078
8419
  }
@@ -8084,15 +8425,15 @@ function registerBundle(program) {
8084
8425
  included,
8085
8426
  usage: "Run `vg build --grammars <this dir>/grammars` to build fully offline."
8086
8427
  };
8087
- fs11.writeFileSync(path41.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
8428
+ fs12.writeFileSync(path43.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
8088
8429
  `);
8089
8430
  if (global.json) {
8090
- json({ out: path41.relative(root2, outDir), ...manifest });
8431
+ json({ out: path43.relative(root2, outDir), ...manifest });
8091
8432
  return;
8092
8433
  }
8093
- info(`${c.cyan("vg bundle")} \xB7 wrote ${path41.relative(root2, outDir)}/`);
8434
+ info(`${c.cyan("vg bundle")} \xB7 wrote ${path43.relative(root2, outDir)}/`);
8094
8435
  for (const i of included) info(` ${c.green("\u2714")} ${i}`);
8095
- info(c.dim(` offline: vg build --grammars "${path41.relative(root2, outDir)}/grammars"`));
8436
+ info(c.dim(` offline: vg build --grammars "${path43.relative(root2, outDir)}/grammars"`));
8096
8437
  });
8097
8438
  applyGlobalOptions(cmd);
8098
8439
  }
@@ -8110,7 +8451,7 @@ async function runDoctor(global) {
8110
8451
  const root2 = rootOf(global);
8111
8452
  const local = global.local === true;
8112
8453
  const graphPath = resolveGraphPath(root2, global.graph);
8113
- const configFile = CONFIG_BASENAMES.find((f) => fs11.existsSync(path41.join(root2, f))) ?? null;
8454
+ const configFile = CONFIG_BASENAMES.find((f) => fs12.existsSync(path43.join(root2, f))) ?? null;
8114
8455
  const graph = loadGraph(root2, graphPath);
8115
8456
  let staleFiles = null;
8116
8457
  if (graph) {
@@ -8136,14 +8477,14 @@ async function runDoctor(global) {
8136
8477
  root: root2,
8137
8478
  configFile,
8138
8479
  map: {
8139
- path: path41.relative(root2, graphPath),
8480
+ path: path43.relative(root2, graphPath),
8140
8481
  built: graph !== null,
8141
8482
  generatedAt: graph?.generatedAt ?? null,
8142
8483
  staleFiles
8143
8484
  },
8144
8485
  libCatalog: {
8145
- path: path41.relative(root2, catalogPath(root2)),
8146
- present: fs11.existsSync(catalogPath(root2)),
8486
+ path: path43.relative(root2, catalogPath(root2)),
8487
+ present: fs12.existsSync(catalogPath(root2)),
8147
8488
  libraries: libCount
8148
8489
  },
8149
8490
  credentials: creds,
@@ -8200,7 +8541,7 @@ async function runDoctor(global) {
8200
8541
  );
8201
8542
  info(
8202
8543
  ` host pool ${li.hostPool.size} warm session(s)` + (li.hostPool.sessions[0] ? c.dim(
8203
- ` \xB7 last ${path41.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
8544
+ ` \xB7 last ${path43.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
8204
8545
  ) : c.dim(" \xB7 none (load via vg code / vgd host-load)"))
8205
8546
  );
8206
8547
  if (li.dynamicOnToken || li.dynamicCustomSampler) {
@@ -8400,7 +8741,7 @@ function registerDaemon(program) {
8400
8741
  const register = cmd.command("register").description("register the current repository with a running vgd").argument("[root]", "repository root (default: cwd)").action(async function(rootArg) {
8401
8742
  const global = readGlobal(this);
8402
8743
  const socketPath = socketOf(this);
8403
- const root2 = path41.resolve(rootArg ?? rootOf(global));
8744
+ const root2 = path43.resolve(rootArg ?? rootOf(global));
8404
8745
  if (!await vgdIsRunning({ socketPath })) {
8405
8746
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
8406
8747
  }
@@ -8436,7 +8777,7 @@ function registerDaemon(program) {
8436
8777
  const federation = cmd.command("federation").description("register a multi-root federation from .vibgrate/federation.json (or primary cwd)").argument("[root]", "primary repository root (default: cwd)").action(async function(rootArg) {
8437
8778
  const global = readGlobal(this);
8438
8779
  const socketPath = socketOf(this);
8439
- const primary = path41.resolve(rootArg ?? rootOf(global));
8780
+ const primary = path43.resolve(rootArg ?? rootOf(global));
8440
8781
  if (!await vgdIsRunning({ socketPath })) {
8441
8782
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
8442
8783
  }
@@ -8464,7 +8805,7 @@ function registerDaemon(program) {
8464
8805
  const publish = cmd.command("publish").description("load the workspace code map into vgd ActiveGraph (from global/legacy store)").argument("[root]", "repository root (default: cwd)").option("--git-ref <ref>", "branch or SHA (default: detect HEAD)").action(async function(rootArg) {
8465
8806
  const global = readGlobal(this);
8466
8807
  const socketPath = socketOf(this);
8467
- const root2 = path41.resolve(rootArg ?? rootOf(global));
8808
+ const root2 = path43.resolve(rootArg ?? rootOf(global));
8468
8809
  if (!await vgdIsRunning({ socketPath })) {
8469
8810
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon ensure\` (${socketPath})`, ExitCode.NOT_FOUND);
8470
8811
  }
@@ -8478,7 +8819,7 @@ function registerDaemon(program) {
8478
8819
  throw new CliError(loaded.error, ExitCode.NOT_FOUND);
8479
8820
  }
8480
8821
  if (!loaded.ok) {
8481
- const { loadGraph: loadGraph2 } = await import('./load-EUZSV73H.js');
8822
+ const { loadGraph: loadGraph2 } = await import('./load-64RK5O6C.js');
8482
8823
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
8483
8824
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
8484
8825
  const graph = loadGraph2(root2, global.graph);
@@ -8594,7 +8935,7 @@ function socketOf(cmd) {
8594
8935
  let c2 = cmd;
8595
8936
  while (c2) {
8596
8937
  const opts = c2.opts();
8597
- if (opts.socket) return path41.resolve(opts.socket);
8938
+ if (opts.socket) return path43.resolve(opts.socket);
8598
8939
  c2 = c2.parent;
8599
8940
  }
8600
8941
  return vgdSocketPath();
@@ -8674,7 +9015,7 @@ async function restartVgdIfRunning(socketPath = vgdSocketPath()) {
8674
9015
  }
8675
9016
  function readVgdPid() {
8676
9017
  try {
8677
- const raw = fs11.readFileSync(vgdPidPath(), "utf8").trim();
9018
+ const raw = fs12.readFileSync(vgdPidPath(), "utf8").trim();
8678
9019
  const pid = Number.parseInt(raw, 10);
8679
9020
  return Number.isInteger(pid) && pid > 0 ? pid : null;
8680
9021
  } catch {
@@ -8759,7 +9100,7 @@ function registerPolicy(program) {
8759
9100
  const global = readGlobal(this);
8760
9101
  let raw;
8761
9102
  try {
8762
- raw = fs11.readFileSync(file, "utf8");
9103
+ raw = fs12.readFileSync(file, "utf8");
8763
9104
  } catch {
8764
9105
  throw new CliError(`cannot read ${file}`, ExitCode.NOT_FOUND);
8765
9106
  }
@@ -8878,12 +9219,299 @@ function registerLlmHost(program) {
8878
9219
  });
8879
9220
  applyGlobalOptions(cmd);
8880
9221
  }
9222
+ var DIGEST_FORMATS = ["md", "json", "html"];
9223
+ var DIGEST_LEVELS = ["concise", "full"];
9224
+ var MAP_FORMATS = ["json", "md", "mermaid"];
9225
+ var MAP_PROFILES = ["integration", "migration", "governance"];
9226
+ var GATE_FORMATS = ["text", "json", "sarif"];
9227
+ var LANGUAGE_EXTENSIONS = {
9228
+ rust: [".rs"],
9229
+ ruby: [".rb", ".rake", ".gemspec"],
9230
+ php: [".php"],
9231
+ dart: [".dart"],
9232
+ swift: [".swift"],
9233
+ scala: [".scala", ".sc"],
9234
+ cplusplus: [".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".ixx"],
9235
+ cobol: [".cbl", ".cob", ".cpy", ".cob85", ".cobol"],
9236
+ vb6: [".vbp", ".bas", ".cls", ".frm", ".ctl", ".dsr"]
9237
+ };
9238
+ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
9239
+ "node_modules",
9240
+ ".git",
9241
+ ".vibgrate",
9242
+ ".hg",
9243
+ ".svn",
9244
+ "dist",
9245
+ "build",
9246
+ "out",
9247
+ "bin",
9248
+ "obj",
9249
+ "target",
9250
+ "vendor",
9251
+ "coverage",
9252
+ "__pycache__",
9253
+ "DerivedData",
9254
+ "Pods"
9255
+ ]);
9256
+ var TEST_PATTERNS = [/[/\\]tests?[/\\]/i, /[/\\]__tests__[/\\]/i, /[/\\]spec[/\\]/i, /\.spec\./i, /\.test\./i];
9257
+ var MAX_EXTRACT_FILE_BYTES = 2 * 1024 * 1024;
9258
+ async function requireEngine() {
9259
+ if (kernelDisabled()) {
9260
+ throw engineUnavailable(
9261
+ "vg hcs needs the HCS engine module, but VIBGRATE_NO_KERNEL is set \u2014 unset it and retry"
9262
+ );
9263
+ }
9264
+ let engine = await loadHcsEngine();
9265
+ if (engine) return engine;
9266
+ const result = await ensureHcsModule();
9267
+ if (result.status === "installed") {
9268
+ info(c.dim(`installed ${HCS_MODULE_NAME}@${result.version} (proprietary license, runs fully locally)`));
9269
+ resetHcsEngineCache();
9270
+ engine = await loadHcsEngine();
9271
+ if (engine) return engine;
9272
+ }
9273
+ if (result.status === "declined") {
9274
+ throw engineUnavailable(
9275
+ "the HCS engine module was previously declined \u2014 run `vg module install hcs` to install it"
9276
+ );
9277
+ }
9278
+ throw engineUnavailable(
9279
+ `the HCS engine module is not installed and could not be fetched${result.detail ? ` (${result.detail})` : ""} \u2014 run \`vg module install hcs\` on a machine with registry access, or point VIBGRATE_HCS_PATH at an installed engine. This exit (6, ENGINE_UNAVAILABLE) is distinct from a gate failure (2) by design.`
9280
+ );
9281
+ }
9282
+ async function readStdin() {
9283
+ const chunks = [];
9284
+ for await (const chunk of process.stdin) {
9285
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
9286
+ }
9287
+ return Buffer.concat(chunks).toString("utf-8");
9288
+ }
9289
+ function readFileOrThrow(file, label) {
9290
+ const p = path43.resolve(file);
9291
+ if (!fs12.existsSync(p)) throw usageError(`${label} file not found: ${p}`);
9292
+ return fs12.readFileSync(p, "utf-8");
9293
+ }
9294
+ async function readInput(file, label) {
9295
+ return file ? readFileOrThrow(file, label) : readStdin();
9296
+ }
9297
+ function writeOutput(outFile, content) {
9298
+ if (!outFile) {
9299
+ process.stdout.write(content.endsWith("\n") ? content : content + "\n");
9300
+ return;
9301
+ }
9302
+ const outPath = path43.resolve(outFile);
9303
+ const dir = path43.dirname(outPath);
9304
+ if (!fs12.existsSync(dir)) throw usageError(`output directory does not exist: ${dir}`);
9305
+ fs12.writeFileSync(outPath, content.endsWith("\n") ? content : content + "\n", "utf-8");
9306
+ info(c.dim(`wrote ${outPath}`));
9307
+ }
9308
+ function requireChoice(value, valid2, flag) {
9309
+ if (!valid2.includes(value)) throw usageError(`${flag} must be one of: ${valid2.join(", ")}`);
9310
+ }
9311
+ function engineCall(what, fn) {
9312
+ try {
9313
+ return fn();
9314
+ } catch (err) {
9315
+ throw new CliError(`${what} failed: ${err instanceof Error ? err.message : String(err)}`);
9316
+ }
9317
+ }
9318
+ function registerHcs(program) {
9319
+ const cmd = program.command("hcs").description("Holistic Code Specification \u2014 extract and analyze deterministic code facts");
9320
+ cmd.command("extract").description("extract HCS facts from source into an NDJSON stream").argument("[dir]", "directory to extract from", ".").option("--language <lang>", "only extract this language (default: all the engine supports)").option("--include-tests", "include test files (excluded by default)").option("-o, --out <file>", "write NDJSON to file (default: stdout)").option(
9321
+ "--previous <file>",
9322
+ "previous extract output to update incrementally (default: the --out file, so repeated `-o` runs are incremental; a missing file means a full extraction)"
9323
+ ).option("--full", "ignore the previous stream and re-extract every file from scratch").action(async function(dir, opts) {
9324
+ const engine = await requireEngine();
9325
+ if (!engine.extractFacts || !engine.supportedLanguages) {
9326
+ throw engineUnavailable(
9327
+ "the installed HCS engine does not include extraction \u2014 update it with `vg module install hcs --force`"
9328
+ );
9329
+ }
9330
+ const canIncremental = Boolean(engine.planExtract && engine.mergeExtract);
9331
+ if (opts.previous && !canIncremental) {
9332
+ throw engineUnavailable(
9333
+ "the installed HCS engine does not include incremental extraction \u2014 update it with `vg module install hcs --force`"
9334
+ );
9335
+ }
9336
+ const statePath = opts.previous ?? opts.out;
9337
+ const useIncremental = canIncremental && statePath !== void 0;
9338
+ const root2 = path43.resolve(dir);
9339
+ if (!fs12.existsSync(root2) || !fs12.statSync(root2).isDirectory()) {
9340
+ throw usageError(`not a directory: ${root2}`);
9341
+ }
9342
+ const supported = new Set(
9343
+ engine.supportedLanguages().split(",").map((l) => l.trim()).filter(Boolean)
9344
+ );
9345
+ if (opts.language && !supported.has(opts.language)) {
9346
+ throw usageError(`--language must be one of: ${[...supported].sort().join(", ")}`);
9347
+ }
9348
+ const wanted = opts.language ? /* @__PURE__ */ new Set([opts.language]) : supported;
9349
+ const extToLang = /* @__PURE__ */ new Map();
9350
+ for (const [lang, exts] of Object.entries(LANGUAGE_EXTENSIONS)) {
9351
+ if (wanted.has(lang)) for (const ext of exts) extToLang.set(ext, lang);
9352
+ }
9353
+ const byLanguage = /* @__PURE__ */ new Map();
9354
+ const walk2 = (abs, rel) => {
9355
+ let entries;
9356
+ try {
9357
+ entries = fs12.readdirSync(abs, { withFileTypes: true });
9358
+ } catch {
9359
+ return;
9360
+ }
9361
+ for (const entry of entries.sort((a, b) => a.name < b.name ? -1 : 1)) {
9362
+ if (entry.name.startsWith(".")) continue;
9363
+ const absChild = path43.join(abs, entry.name);
9364
+ const relChild = rel ? `${rel}/${entry.name}` : entry.name;
9365
+ if (entry.isDirectory()) {
9366
+ if (!SKIP_DIRS2.has(entry.name)) walk2(absChild, relChild);
9367
+ continue;
9368
+ }
9369
+ if (!entry.isFile()) continue;
9370
+ if (!opts.includeTests && TEST_PATTERNS.some((p) => p.test(relChild))) continue;
9371
+ const lang = extToLang.get(path43.extname(entry.name).toLowerCase());
9372
+ if (!lang) continue;
9373
+ try {
9374
+ if (fs12.statSync(absChild).size > MAX_EXTRACT_FILE_BYTES) continue;
9375
+ const content = fs12.readFileSync(absChild, "utf-8");
9376
+ let bucket = byLanguage.get(lang);
9377
+ if (!bucket) byLanguage.set(lang, bucket = []);
9378
+ bucket.push({ path: relChild, content });
9379
+ } catch {
9380
+ }
9381
+ }
9382
+ };
9383
+ walk2(root2, "");
9384
+ if (byLanguage.size === 0 && !useIncremental) {
9385
+ info(`no extractable sources found under ${root2} (languages: ${[...wanted].sort().join(", ")})`);
9386
+ writeOutput(opts.out, "");
9387
+ return;
9388
+ }
9389
+ const extractLanguage = (language, only) => {
9390
+ let files = byLanguage.get(language);
9391
+ if (only) files = files.filter((f) => only.has(f.path));
9392
+ if (files.length === 0) return "";
9393
+ info(c.dim(`extracting ${language} (${files.length} files)`));
9394
+ return engineCall(
9395
+ `${language} extraction`,
9396
+ () => engine.extractFacts(JSON.stringify({ language, files, emittedAt: "" }))
9397
+ ).trim();
9398
+ };
9399
+ const languages = [...byLanguage.keys()].sort();
9400
+ if (!useIncremental) {
9401
+ const parts2 = languages.map((l) => extractLanguage(l)).filter(Boolean);
9402
+ writeOutput(opts.out, parts2.join("\n"));
9403
+ return;
9404
+ }
9405
+ const previousPath = path43.resolve(statePath);
9406
+ const previousNdjson = !opts.full && fs12.existsSync(previousPath) ? fs12.readFileSync(previousPath, "utf-8") : "";
9407
+ if (opts.full) info(c.dim("running a full re-extraction (--full)"));
9408
+ else if (!previousNdjson) info(c.dim(`previous stream not found at ${previousPath} \u2014 running a full extraction`));
9409
+ const currentFilesJson = JSON.stringify(
9410
+ languages.flatMap((l) => byLanguage.get(l).map((f) => ({ path: f.path, content: f.content })))
9411
+ );
9412
+ const plan = JSON.parse(
9413
+ engineCall("incremental planning", () => engine.planExtract(previousNdjson, currentFilesJson))
9414
+ );
9415
+ const toExtract = /* @__PURE__ */ new Set([...plan.added, ...plan.changed]);
9416
+ info(
9417
+ c.dim(
9418
+ `incremental plan (${plan.mode}): ${plan.added.length} added, ${plan.changed.length} changed, ${plan.removed.length} removed, ${plan.unchanged} unchanged`
9419
+ )
9420
+ );
9421
+ const parts = languages.map((l) => extractLanguage(l, toExtract)).filter(Boolean);
9422
+ const merged = JSON.parse(
9423
+ engineCall(
9424
+ "incremental merge",
9425
+ () => engine.mergeExtract(previousNdjson, parts.join("\n"), currentFilesJson)
9426
+ )
9427
+ );
9428
+ info(
9429
+ c.dim(
9430
+ `merged: ${merged.stats.reusedFacts} facts reused, ${merged.stats.freshFacts} fresh, ${merged.stats.droppedFacts} dropped`
9431
+ )
9432
+ );
9433
+ writeOutput(opts.out, merged.ndjson);
9434
+ });
9435
+ cmd.command("digest").description("render an HCS NDJSON fact stream (from `vg hcs extract`) as Markdown, JSON, or HTML").option("--in <file>", "NDJSON file to read (default: stdin)").option("-o, --out <file>", "write output to file (default: stdout)").option("--format <format>", `output format: ${DIGEST_FORMATS.join(" | ")}`, "md").option("--level <level>", `detail level: ${DIGEST_LEVELS.join(" | ")}`, "concise").option("--title <title>", "override the document title").action(async function(opts) {
9436
+ requireChoice(opts.format, DIGEST_FORMATS, "--format");
9437
+ requireChoice(opts.level, DIGEST_LEVELS, "--level");
9438
+ const engine = await requireEngine();
9439
+ const ndjson = await readInput(opts.in, "input");
9440
+ const options = { format: opts.format, level: opts.level };
9441
+ if (opts.title) options.title = opts.title;
9442
+ writeOutput(opts.out, engineCall("digest rendering", () => engine.renderDigest(ndjson, JSON.stringify(options))));
9443
+ });
9444
+ cmd.command("map").description("build the System Map from an HCS NDJSON fact stream").option("--facts <file>", "NDJSON facts file to read (default: stdin)").option("-o, --out <file>", "write output to file (default: stdout)").option("--format <format>", `output format: ${MAP_FORMATS.join(" | ")}`, "json").option("--profile <profile>", `consumer projection: ${MAP_PROFILES.join(" | ")}`).action(async function(opts) {
9445
+ requireChoice(opts.format, MAP_FORMATS, "--format");
9446
+ if (opts.profile) requireChoice(opts.profile, MAP_PROFILES, "--profile");
9447
+ const generatedAt = readGlobal(this).generatedAt;
9448
+ const engine = await requireEngine();
9449
+ const ndjson = await readInput(opts.facts, "facts");
9450
+ const options = { format: opts.format };
9451
+ if (opts.profile) options.profile = opts.profile;
9452
+ if (generatedAt) options.generatedAt = generatedAt;
9453
+ writeOutput(opts.out, engineCall("map build", () => engine.buildMap(ndjson, JSON.stringify(options))));
9454
+ });
9455
+ cmd.command("gate").description("governance gate \u2014 diff two HCS fact streams and fail (exit 2) on material structural regressions").requiredOption("--baseline <file>", 'baseline NDJSON facts (the "before" stream)').option("--facts <file>", 'current NDJSON facts (the "after" stream; default: stdin)').option("--policy <file>", "gate policy JSON \u2014 thresholds and disabled rules").option("-o, --out <file>", "write the result to file (default: stdout)").option("--format <format>", `output format: ${GATE_FORMATS.join(" | ")}`, "text").action(async function(opts) {
9456
+ requireChoice(opts.format, GATE_FORMATS, "--format");
9457
+ const engine = await requireEngine();
9458
+ const before = readFileOrThrow(opts.baseline, "baseline");
9459
+ const after = await readInput(opts.facts, "facts");
9460
+ let policy;
9461
+ if (opts.policy) {
9462
+ try {
9463
+ policy = JSON.parse(readFileOrThrow(opts.policy, "policy"));
9464
+ } catch (err) {
9465
+ if (err instanceof CliError) throw err;
9466
+ throw usageError(`invalid policy JSON: ${err instanceof Error ? err.message : String(err)}`);
9467
+ }
9468
+ }
9469
+ const jsonOut = engineCall(
9470
+ "gate evaluation",
9471
+ () => engine.evaluateGate(before, after, JSON.stringify({ format: "json", policy }))
9472
+ );
9473
+ const pass = JSON.parse(jsonOut).pass;
9474
+ const output = opts.format === "json" ? jsonOut : engineCall("gate evaluation", () => engine.evaluateGate(before, after, JSON.stringify({ format: opts.format, policy })));
9475
+ writeOutput(opts.out, output);
9476
+ if (!pass) {
9477
+ info(c.red("gate FAILED \u2014 material structural regression against the baseline"));
9478
+ process.exitCode = ExitCode.GATE_FAILED;
9479
+ } else {
9480
+ info(c.green("gate passed"));
9481
+ }
9482
+ });
9483
+ cmd.command("validate").description("validate an HCS NDJSON model against the spec (exits with the Appendix-I conformance code)").argument("<file>", "NDJSON model file (e.g. `vg hcs extract` output)").action(async function(file) {
9484
+ const opts = { json: readGlobal(this).json };
9485
+ const engine = await requireEngine();
9486
+ if (!engine.validateLines) {
9487
+ throw engineUnavailable(
9488
+ "the installed HCS engine does not include the validator \u2014 update it with `vg module install hcs --force`"
9489
+ );
9490
+ }
9491
+ const content = readFileOrThrow(file, "model");
9492
+ const lines = content.split("\n").filter((l) => l.trim());
9493
+ const report = JSON.parse(engineCall("validation", () => engine.validateLines(JSON.stringify(lines))));
9494
+ if (opts.json) {
9495
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
9496
+ } else if (report.ok) {
9497
+ info(c.green("\u2714 conformant \u2014 model satisfies the HCS spec"));
9498
+ } else {
9499
+ info(c.red(`\u2718 ${report.errors.length} validation error(s) (exit ${report.exitCode}):`));
9500
+ for (const e of report.errors.slice(0, 50)) {
9501
+ info(c.dim(` [${e.code}] ${e.factId || "(model)"}: ${e.message}`));
9502
+ }
9503
+ if (report.errors.length > 50) info(c.dim(` \u2026 and ${report.errors.length - 50} more`));
9504
+ }
9505
+ process.exitCode = report.exitCode;
9506
+ });
9507
+ applyGlobalOptions(cmd);
9508
+ }
8881
9509
  var initCommand = new Command("init").description("Initialize vibgrate in a project").argument("[path]", "Path to initialize", ".").option("--baseline", "Create initial baseline after init").option("--yes", "Skip confirmation prompts").action(async (targetPath, opts) => {
8882
- const rootDir = path41.resolve(targetPath);
8883
- const vibgrateDir2 = path41.join(rootDir, ".vibgrate");
9510
+ const rootDir = path43.resolve(targetPath);
9511
+ const vibgrateDir2 = path43.join(rootDir, ".vibgrate");
8884
9512
  await ensureDir(vibgrateDir2);
8885
9513
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold(".vibgrate/")} directory`);
8886
- const configPath = path41.join(rootDir, "vibgrate.config.ts");
9514
+ const configPath = path43.join(rootDir, "vibgrate.config.ts");
8887
9515
  if (await pathExists(configPath)) {
8888
9516
  console.log(chalk7.dim(" vibgrate.config.ts already exists, skipping"));
8889
9517
  } else {
@@ -8891,7 +9519,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
8891
9519
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold("vibgrate.config.ts")}`);
8892
9520
  }
8893
9521
  if (opts.baseline) {
8894
- const { runBaseline } = await import('./baseline-ZMRZRGFI.js');
9522
+ const { runBaseline } = await import('./baseline-WVD6P5IO.js');
8895
9523
  await runBaseline(rootDir);
8896
9524
  }
8897
9525
  console.log("");
@@ -8994,7 +9622,7 @@ function collectPackageImports(graph, ecosystem, pkg) {
8994
9622
  };
8995
9623
  }
8996
9624
  async function firstReferenceLine(rootDir, relFile, identifier, readFile3) {
8997
- const content = await readFile3(path41.join(rootDir, relFile));
9625
+ const content = await readFile3(path43.join(rootDir, relFile));
8998
9626
  if (!content) return null;
8999
9627
  const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9000
9628
  const re = new RegExp(`\\b${escaped}\\b`);
@@ -9032,9 +9660,9 @@ function sitesFromImportFiles(files, limit = 10) {
9032
9660
  }
9033
9661
  async function defaultReadFile(absPath) {
9034
9662
  try {
9035
- const stat2 = await fs25.stat(absPath);
9663
+ const stat2 = await fs27.stat(absPath);
9036
9664
  if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
9037
- return await fs25.readFile(absPath, "utf8");
9665
+ return await fs27.readFile(absPath, "utf8");
9038
9666
  } catch {
9039
9667
  return null;
9040
9668
  }
@@ -9230,7 +9858,7 @@ var AI_ASSISTANT_DETECTORS = [
9230
9858
  async function detectAiAssistant(rootDir) {
9231
9859
  for (const detector of AI_ASSISTANT_DETECTORS) {
9232
9860
  for (const file of detector.files) {
9233
- if (await pathExists$1(path41.join(rootDir, file))) {
9861
+ if (await pathExists$1(path43.join(rootDir, file))) {
9234
9862
  return detector.name;
9235
9863
  }
9236
9864
  }
@@ -9424,18 +10052,31 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
9424
10052
  collectExcludes,
9425
10053
  []
9426
10054
  ).option("--concurrency <n>", "Max concurrent npm calls", "8").option("--push", "Auto-push results to Vibgrate API after scan").option("--dsn <dsn>", "DSN token for push (or use VIBGRATE_DSN env)").option("--region <region>", "Override data residency region for push (us, eu)").option("--strict", "Fail on push errors").option("--ui-purpose", "Enable optional UI purpose evidence extraction (slower)").option("--no-local-artifacts", "Do not write .vibgrate JSON artifacts to disk").option("--max-privacy", "Enable strongest privacy mode (minimal scanners, no local artifacts)").option("--offline", "Run without network calls; do not upload results").option("--full", "Comprehensive scan: turns on known-vulnerability detection (= --vulns) and, when a standards policy exists, a banned-dependency report \u2014 on top of drift scoring and the code map").option("--vulns", "Also scan installed dependencies for known vulnerabilities (OSV online, or advisories from --package-manifest when offline)").option("--package-manifest <file>", "Use local package-version manifest JSON/ZIP (for offline mode)").option("--project-scan-timeout <seconds>", "Per-project scan timeout in seconds (default: 180)").option("--drift-budget <score>", "Fail if DriftScore is above budget (0-100)").option("--drift-worsening <percent>", "Fail if drift worsens by more than % since baseline").option("--repository-name <name>", "Override the repository name recorded for this scan (defaults to the directory or package.json name)").option("--force", "Always create a fresh scan ingest, even if the repository is unchanged since the last scan (skips the unchanged/reuse optimization). Used by scheduled and dashboard-triggered scans.").option("--no-graph", "Skip building the local code map (the AI/docs index) that scan produces after scoring drift").option("--quiet", "Suppress promotional output (the free-plan tracking panel and the AI Context install prompt); scan results are unaffected").action(async (targetPath, opts) => {
9427
- const rootDir = path41.resolve(targetPath);
10055
+ const rootDir = path43.resolve(targetPath);
9428
10056
  if (!await pathExists$1(rootDir)) {
9429
10057
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
9430
10058
  process.exit(1);
9431
10059
  }
9432
10060
  const hasDsn = !!resolveDsn(opts.dsn);
9433
- const willPush = !opts.offline && (opts.push || hasDsn);
10061
+ let willPush = !opts.offline && (opts.push || hasDsn);
9434
10062
  const noLocalArtifacts = opts.localArtifacts === false;
9435
- const isFirstRun = !await pathExists$1(path41.join(rootDir, ".vibgrate", "scan_result.json"));
10063
+ const isFirstRun = !await pathExists$1(path43.join(rootDir, ".vibgrate", "scan_result.json"));
9436
10064
  let pinnedRegion;
9437
10065
  let planTier;
9438
10066
  let upgradeUrl;
10067
+ let pushBlockedReason;
10068
+ const blockPush = (reason, detailLines) => {
10069
+ if (opts.strict) {
10070
+ console.error(chalk7.red(reason));
10071
+ for (const line of detailLines) console.error(chalk7.dim(line));
10072
+ process.exit(1);
10073
+ }
10074
+ console.error(chalk7.yellow(`\u26A0 ${reason}`));
10075
+ for (const line of detailLines) console.error(chalk7.dim(` ${line}`));
10076
+ console.error(chalk7.dim(" Scanning locally \u2014 results will not be uploaded to Vibgrate Cloud."));
10077
+ pushBlockedReason = reason;
10078
+ willPush = false;
10079
+ };
9439
10080
  if (willPush && hasDsn) {
9440
10081
  const dsn = resolveDsn(opts.dsn);
9441
10082
  const parsed = parseDsn(dsn);
@@ -9458,59 +10099,45 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
9458
10099
  planTier = preflight.plan?.tier;
9459
10100
  upgradeUrl = preflight.upgradeUrl ?? `https://${dashHostForIngestHost(preflight.ingestHost ?? ingestHost)}/${parsed.workspaceId}`;
9460
10101
  if (preflight.vm && !preflight.vm.allowed) {
9461
- console.error(chalk7.red(preflight.error ?? "VM meter usage exhausted"));
9462
- console.error(
9463
- chalk7.dim(
9464
- `VM minutes: ${preflight.vm.used}/${preflight.vm.limit} (${preflight.plan.label} plan) \u2014 enable overages or upgrade your plan.`
9465
- )
9466
- );
9467
- process.exit(1);
9468
- }
9469
- if (preflight.repositories && !preflight.repositories.allowed) {
9470
- console.error(
9471
- chalk7.red(
9472
- preflight.error ?? `Repository limit reached for the ${preflight.plan.label} plan \u2014 cannot scan a new repository.`
9473
- )
9474
- );
10102
+ blockPush(preflight.error ?? "VM meter usage exhausted", [
10103
+ `VM minutes: ${preflight.vm.used}/${preflight.vm.limit} (${preflight.plan.label} plan) \u2014 enable overages or upgrade your plan.`
10104
+ ]);
10105
+ } else if (preflight.repositories && !preflight.repositories.allowed) {
9475
10106
  const max = preflight.repositories.max < 0 ? "unlimited" : String(preflight.repositories.max);
9476
- console.error(
9477
- chalk7.dim(
9478
- `Repositories: ${preflight.repositories.total}/${max} (${preflight.plan.label} plan) \u2014 archive a repository or upgrade your plan.`
9479
- )
9480
- );
10107
+ const detail = [
10108
+ `Repositories: ${preflight.repositories.total}/${max} (${preflight.plan.label} plan) \u2014 archive a repository or upgrade your plan.`
10109
+ ];
9481
10110
  if (preflight.upgradeUrl) {
9482
- console.error(chalk7.dim(` Upgrade: ${preflight.upgradeUrl}`));
10111
+ detail.push(`Upgrade: ${preflight.upgradeUrl}`);
9483
10112
  }
9484
- process.exit(1);
9485
- }
9486
- if (preflight.status === "error" || !preflight.scans.allowed) {
9487
- console.error(chalk7.red(preflight.error ?? "Scan ingestion not allowed for this workspace."));
9488
- console.error(
9489
- chalk7.dim(
9490
- `Credits: ${preflight.scans.used}/${preflight.scans.limit} (${preflight.plan.label} plan)`
9491
- )
10113
+ blockPush(
10114
+ preflight.error ?? `Repository limit reached for the ${preflight.plan.label} plan \u2014 cannot upload a new repository.`,
10115
+ detail
9492
10116
  );
9493
- if (opts.strict) process.exit(1);
9494
- process.exit(1);
9495
- }
9496
- console.log(
9497
- chalk7.dim(
9498
- `Plan: ${preflight.plan.label} \u2014 scan credits ${preflight.scans.used}/${preflight.scans.limit} this month`
9499
- )
9500
- );
9501
- if (preflight.repository?.unchanged && !opts.force) {
10117
+ } else if (preflight.status === "error" || !preflight.scans.allowed) {
10118
+ blockPush(preflight.error ?? "Scan ingestion not allowed for this workspace.", [
10119
+ `Credits: ${preflight.scans.used}/${preflight.scans.limit} (${preflight.plan.label} plan)`
10120
+ ]);
10121
+ } else {
9502
10122
  console.log(
9503
- chalk7.green("\u2714") + ` Repository unchanged at ${preflight.repository.lastVcsSha?.slice(0, 7) ?? "same revision"} \u2014 skipping scan.`
10123
+ chalk7.dim(
10124
+ `Plan: ${preflight.plan.label} \u2014 scan credits ${preflight.scans.used}/${preflight.scans.limit} this month`
10125
+ )
9504
10126
  );
9505
- if (preflight.repository.lastIngestId) {
9506
- emitIngestIdLine(preflight.repository.lastIngestId, { unchanged: true });
9507
- const dashUrl = `https://${dashHostForIngestHost(ingestHost)}/${parsed.workspaceId}/scan/${preflight.repository.lastIngestId}`;
9508
- console.log(chalk7.dim(` Latest report: ${dashUrl}`));
9509
- } else if (opts.strict) {
9510
- console.error(chalk7.red("Repository unchanged but no previous ingest id available."));
9511
- process.exit(1);
10127
+ if (preflight.repository?.unchanged && !opts.force) {
10128
+ console.log(
10129
+ chalk7.green("\u2714") + ` Repository unchanged at ${preflight.repository.lastVcsSha?.slice(0, 7) ?? "same revision"} \u2014 skipping scan.`
10130
+ );
10131
+ if (preflight.repository.lastIngestId) {
10132
+ emitIngestIdLine(preflight.repository.lastIngestId, { unchanged: true });
10133
+ const dashUrl = `https://${dashHostForIngestHost(ingestHost)}/${parsed.workspaceId}/scan/${preflight.repository.lastIngestId}`;
10134
+ console.log(chalk7.dim(` Latest report: ${dashUrl}`));
10135
+ } else if (opts.strict) {
10136
+ console.error(chalk7.red("Repository unchanged but no previous ingest id available."));
10137
+ process.exit(1);
10138
+ }
10139
+ return;
9512
10140
  }
9513
- return;
9514
10141
  }
9515
10142
  } catch (e) {
9516
10143
  const msg = e instanceof Error ? e.message : String(e);
@@ -9626,6 +10253,12 @@ Failing fitness function: drift worsened by ${worseningPercent.toFixed(2)}% (thr
9626
10253
  }
9627
10254
  if (willPush) {
9628
10255
  await autoPush(artifact, rootDir, scanOpts);
10256
+ } else if (pushBlockedReason) {
10257
+ console.error("");
10258
+ console.error(chalk7.yellow(`\u26A0 Results were not uploaded: ${pushBlockedReason}`));
10259
+ if (upgradeUrl) {
10260
+ console.error(chalk7.dim(` Upgrade: ${upgradeUrl}`));
10261
+ }
9629
10262
  }
9630
10263
  const showAiPrompt = scanOpts.format === "text" && !opts.quiet && !hasDsn && !opts.offline && !noLocalArtifacts && !opts.maxPrivacy && isFirstRun;
9631
10264
  if (showAiPrompt) {
@@ -9675,7 +10308,7 @@ var WATCHED_FILES = /* @__PURE__ */ new Set([
9675
10308
  "packages.lock.json"
9676
10309
  ]);
9677
10310
  var WATCHED_EXT = /\.(cs|fs)proj$/i;
9678
- var SKIP_DIRS2 = /* @__PURE__ */ new Set([
10311
+ var SKIP_DIRS3 = /* @__PURE__ */ new Set([
9679
10312
  "node_modules",
9680
10313
  ".git",
9681
10314
  "dist",
@@ -9696,7 +10329,7 @@ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
9696
10329
  function scanStaleness(rootDir, artifactPath) {
9697
10330
  let ref;
9698
10331
  try {
9699
- ref = fs11.statSync(artifactPath).mtimeMs;
10332
+ ref = fs12.statSync(artifactPath).mtimeMs;
9700
10333
  } catch {
9701
10334
  return { stale: false };
9702
10335
  }
@@ -9708,7 +10341,7 @@ function scanStaleness(rootDir, artifactPath) {
9708
10341
  if (depth > 8 || scanned > MAX_ENTRIES2) return;
9709
10342
  let entries;
9710
10343
  try {
9711
- entries = fs11.readdirSync(dir, { withFileTypes: true });
10344
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
9712
10345
  } catch {
9713
10346
  return;
9714
10347
  }
@@ -9716,20 +10349,20 @@ function scanStaleness(rootDir, artifactPath) {
9716
10349
  scanned++;
9717
10350
  if (scanned > MAX_ENTRIES2) break;
9718
10351
  if (e.isDirectory()) {
9719
- if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path41.join(dir, e.name), depth + 1);
10352
+ if (!SKIP_DIRS3.has(e.name) && !e.name.startsWith(".")) walk2(path43.join(dir, e.name), depth + 1);
9720
10353
  continue;
9721
10354
  }
9722
10355
  if (!WATCHED_FILES.has(e.name) && !WATCHED_EXT.test(e.name)) continue;
9723
- const abs = path41.join(dir, e.name);
10356
+ const abs = path43.join(dir, e.name);
9724
10357
  let mtimeMs;
9725
10358
  try {
9726
- mtimeMs = fs11.statSync(abs).mtimeMs;
10359
+ mtimeMs = fs12.statSync(abs).mtimeMs;
9727
10360
  } catch {
9728
10361
  continue;
9729
10362
  }
9730
10363
  if (mtimeMs > newest) {
9731
10364
  newest = mtimeMs;
9732
- newestChanged = path41.relative(rootDir, abs) || e.name;
10365
+ newestChanged = path43.relative(rootDir, abs) || e.name;
9733
10366
  }
9734
10367
  }
9735
10368
  };
@@ -9793,7 +10426,7 @@ function extractContracts(content, pkg, ecosystem) {
9793
10426
  }
9794
10427
 
9795
10428
  // src/reporting/planning/usage.ts
9796
- var SKIP_DIRS3 = /* @__PURE__ */ new Set([
10429
+ var SKIP_DIRS4 = /* @__PURE__ */ new Set([
9797
10430
  "node_modules",
9798
10431
  ".git",
9799
10432
  "dist",
@@ -9860,7 +10493,7 @@ function analyzeTree(root2, packages) {
9860
10493
  if (depth > MAX_DEPTH || filesSeen >= MAX_FILES) return;
9861
10494
  let entries;
9862
10495
  try {
9863
- entries = fs11.readdirSync(dir, { withFileTypes: true });
10496
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
9864
10497
  } catch {
9865
10498
  return;
9866
10499
  }
@@ -9868,18 +10501,18 @@ function analyzeTree(root2, packages) {
9868
10501
  for (const entry of entries) {
9869
10502
  if (filesSeen >= MAX_FILES) return;
9870
10503
  if (entry.isDirectory()) {
9871
- if (SKIP_DIRS3.has(entry.name) || entry.name.startsWith(".")) continue;
9872
- walk2(path41.join(dir, entry.name), depth + 1);
10504
+ if (SKIP_DIRS4.has(entry.name) || entry.name.startsWith(".")) continue;
10505
+ walk2(path43.join(dir, entry.name), depth + 1);
9873
10506
  continue;
9874
10507
  }
9875
- const fileEco = EXT_ECOSYSTEM[path41.extname(entry.name)];
10508
+ const fileEco = EXT_ECOSYSTEM[path43.extname(entry.name)];
9876
10509
  if (!fileEco || fileEco === "unknown") continue;
9877
10510
  filesSeen++;
9878
- const full = path41.join(dir, entry.name);
10511
+ const full = path43.join(dir, entry.name);
9879
10512
  let content;
9880
10513
  try {
9881
- if (fs11.statSync(full).size > MAX_FILE_BYTES2) continue;
9882
- content = fs11.readFileSync(full, "utf8");
10514
+ if (fs12.statSync(full).size > MAX_FILE_BYTES2) continue;
10515
+ content = fs12.readFileSync(full, "utf8");
9883
10516
  } catch {
9884
10517
  continue;
9885
10518
  }
@@ -10190,7 +10823,7 @@ function applyPlan(rootDir, upgrades, opts = {}) {
10190
10823
  }
10191
10824
  const outcomes = effective.map((t) => {
10192
10825
  const c2 = pmCommandFor(u.ecosystem, u.package, u.to, opts.packageManager, { workspaceRoot: t.isWorkspaceRoot });
10193
- return { t, res: run(c2, path41.join(rootDir, t.dir)) };
10826
+ return { t, res: run(c2, path43.join(rootDir, t.dir)) };
10194
10827
  });
10195
10828
  const failures = outcomes.filter((o) => !o.res.ok);
10196
10829
  if (failures.length === 0) {
@@ -10219,8 +10852,8 @@ function applyPlan(rootDir, upgrades, opts = {}) {
10219
10852
  return results;
10220
10853
  }
10221
10854
  var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
10222
- var CACHE_DIR = path41.join(os.homedir(), ".vibgrate");
10223
- var CACHE_FILE = path41.join(CACHE_DIR, "update-check.json");
10855
+ var CACHE_DIR = path43.join(os.homedir(), ".vibgrate");
10856
+ var CACHE_FILE = path43.join(CACHE_DIR, "update-check.json");
10224
10857
  async function fetchLatestVersion() {
10225
10858
  try {
10226
10859
  const controller = new AbortController();
@@ -10247,8 +10880,8 @@ async function fetchLatestVersion() {
10247
10880
  }
10248
10881
  async function writeCache(data) {
10249
10882
  try {
10250
- await fs25.mkdir(CACHE_DIR, { recursive: true });
10251
- await fs25.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
10883
+ await fs27.mkdir(CACHE_DIR, { recursive: true });
10884
+ await fs27.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
10252
10885
  } catch {
10253
10886
  }
10254
10887
  }
@@ -10283,10 +10916,10 @@ function buildDeferredUpdateScript(opts) {
10283
10916
  }
10284
10917
  function scheduleDeferredUpdate(command, pid = process.pid, dir = os.tmpdir()) {
10285
10918
  const stamp = `${pid}-${process.hrtime.bigint().toString(36)}`;
10286
- const scriptPath = path41.join(dir, `vg-update-${stamp}.cmd`);
10287
- const logPath = path41.join(dir, `vg-update-${stamp}.log`);
10919
+ const scriptPath = path43.join(dir, `vg-update-${stamp}.cmd`);
10920
+ const logPath = path43.join(dir, `vg-update-${stamp}.log`);
10288
10921
  try {
10289
- fs11.writeFileSync(scriptPath, buildDeferredUpdateScript({ pid, command, logPath }), "utf8");
10922
+ fs12.writeFileSync(scriptPath, buildDeferredUpdateScript({ pid, command, logPath }), "utf8");
10290
10923
  const child = spawn(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", scriptPath], {
10291
10924
  detached: true,
10292
10925
  stdio: "ignore",
@@ -10305,11 +10938,12 @@ var SCRIPT_PACKAGES = [PACKAGE_NAME, "onnxruntime-node", "msgpackr-extract"];
10305
10938
  function allowScriptsFlag(pm) {
10306
10939
  return pm === "npm" ? ` --allow-scripts=${SCRIPT_PACKAGES.join(",")}` : "";
10307
10940
  }
10941
+ var ORT_INSTALL_SKIP_ENV = { ONNXRUNTIME_NODE_INSTALL: "skip" };
10308
10942
  function detectGlobalInstall(execPath = process.argv[1] || "", cwd = process.cwd()) {
10309
10943
  if (!execPath) return null;
10310
10944
  let resolved = execPath;
10311
10945
  try {
10312
- resolved = fs11.realpathSync(execPath);
10946
+ resolved = fs12.realpathSync(execPath);
10313
10947
  } catch {
10314
10948
  }
10315
10949
  const p = resolved.replace(/\\/g, "/");
@@ -10339,14 +10973,14 @@ async function findGlobalInstall(pkg = PACKAGE_NAME, run = defaultRunner) {
10339
10973
  pm: "yarn",
10340
10974
  root: () => {
10341
10975
  const dir = tryRun("yarn global dir");
10342
- return dir ? path41.join(dir, "node_modules") : null;
10976
+ return dir ? path43.join(dir, "node_modules") : null;
10343
10977
  }
10344
10978
  },
10345
- { pm: "bun", root: () => path41.join(os.homedir(), ".bun", "install", "global", "node_modules") }
10979
+ { pm: "bun", root: () => path43.join(os.homedir(), ".bun", "install", "global", "node_modules") }
10346
10980
  ];
10347
10981
  for (const probe of probes) {
10348
10982
  const root2 = probe.root();
10349
- if (root2 && await pathExists(path41.join(root2, pkg))) return probe.pm;
10983
+ if (root2 && await pathExists(path43.join(root2, pkg))) return probe.pm;
10350
10984
  }
10351
10985
  return null;
10352
10986
  }
@@ -10361,19 +10995,19 @@ function getGlobalUpdateCommand(pm, pkg, version) {
10361
10995
  return `bun add -g ${spec}`;
10362
10996
  case "npm":
10363
10997
  default:
10364
- return `npm install -g${allowScriptsFlag("npm")} ${spec}`;
10998
+ return `npm install -g --no-fund${allowScriptsFlag("npm")} ${spec}`;
10365
10999
  }
10366
11000
  }
10367
11001
  async function detectPackageManager(cwd) {
10368
- if (await pathExists(path41.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10369
- if (await pathExists(path41.join(cwd, "bun.lockb"))) return "bun";
10370
- if (await pathExists(path41.join(cwd, "yarn.lock"))) return "yarn";
11002
+ if (await pathExists(path43.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
11003
+ if (await pathExists(path43.join(cwd, "bun.lockb"))) return "bun";
11004
+ if (await pathExists(path43.join(cwd, "yarn.lock"))) return "yarn";
10371
11005
  return "npm";
10372
11006
  }
10373
11007
  async function detectWorkspaceRoot(cwd) {
10374
- if (await pathExists(path41.join(cwd, "pnpm-workspace.yaml"))) return true;
11008
+ if (await pathExists(path43.join(cwd, "pnpm-workspace.yaml"))) return true;
10375
11009
  try {
10376
- const pkgPath = path41.join(cwd, "package.json");
11010
+ const pkgPath = path43.join(cwd, "package.json");
10377
11011
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
10378
11012
  const pkg = JSON.parse(raw);
10379
11013
  return pkg.workspaces != null;
@@ -10394,13 +11028,13 @@ function getInstallCommand(pm, pkg, version, isDev, opts = {}) {
10394
11028
  case "npm":
10395
11029
  default: {
10396
11030
  const allow = allowScriptsFlag("npm");
10397
- return isDev ? `npm install${allow} --save-dev ${spec}` : `npm install${allow} ${spec}`;
11031
+ return isDev ? `npm install --no-fund${allow} --save-dev ${spec}` : `npm install --no-fund${allow} ${spec}`;
10398
11032
  }
10399
11033
  }
10400
11034
  }
10401
11035
  async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
10402
11036
  try {
10403
- const pkgPath = path41.join(cwd, "package.json");
11037
+ const pkgPath = path43.join(cwd, "package.json");
10404
11038
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
10405
11039
  const parsed = JSON.parse(raw);
10406
11040
  if (parsed.devDependencies?.[pkg]) return "dev";
@@ -10415,19 +11049,24 @@ async function confirmWorkspaceRoot(pm) {
10415
11049
  async function confirm3(question) {
10416
11050
  if (!(process.stdin.isTTY && process.stdout.isTTY)) return false;
10417
11051
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10418
- return new Promise((resolve21) => {
11052
+ return new Promise((resolve23) => {
10419
11053
  rl.question(chalk7.yellow(question), (ans) => {
10420
11054
  rl.close();
10421
11055
  const t = ans.trim().toLowerCase();
10422
- resolve21(t === "y" || t === "yes");
11056
+ resolve23(t === "y" || t === "yes");
10423
11057
  });
10424
11058
  });
10425
11059
  }
10426
11060
  var CAPTURED_OUTPUT_LIMIT = 64e3;
10427
11061
  async function runInstall(cmd, cwd) {
10428
11062
  const { spawn: spawn5 } = await import('child_process');
10429
- return new Promise((resolve21) => {
10430
- const child = spawn5(cmd, { cwd, shell: true, stdio: ["inherit", "pipe", "pipe"] });
11063
+ return new Promise((resolve23) => {
11064
+ const child = spawn5(cmd, {
11065
+ cwd,
11066
+ shell: true,
11067
+ stdio: ["inherit", "pipe", "pipe"],
11068
+ env: { ...process.env, ...ORT_INSTALL_SKIP_ENV }
11069
+ });
10431
11070
  let output = "";
10432
11071
  const tee = (src, dest) => {
10433
11072
  if (!src) return;
@@ -10440,15 +11079,15 @@ async function runInstall(cmd, cwd) {
10440
11079
  };
10441
11080
  tee(child.stdout, process.stdout);
10442
11081
  tee(child.stderr, process.stderr);
10443
- child.on("error", (err) => resolve21({ ok: false, output: `${output}
11082
+ child.on("error", (err) => resolve23({ ok: false, output: `${output}
10444
11083
  ${String(err)}` }));
10445
- child.on("close", (code) => resolve21({ ok: code === 0, output }));
11084
+ child.on("close", (code) => resolve23({ ok: code === 0, output }));
10446
11085
  });
10447
11086
  }
10448
11087
  async function releaseWindowsFileLocks(cwd, keepVersion) {
10449
11088
  reapAndReport(cwd, keepVersion);
10450
11089
  try {
10451
- const { vgdSocketPath: vgdSocketPath2 } = await import('./vgd-Y25XSQGZ.js');
11090
+ const { vgdSocketPath: vgdSocketPath2 } = await import('./vgd-ORPA5C2K.js');
10452
11091
  const result = await stopVgd(vgdSocketPath2());
10453
11092
  if (result === "stopped") {
10454
11093
  console.log(chalk7.dim("Stopped the vgd daemon so its files can be replaced \u2014 it restarts on the next command."));
@@ -10573,7 +11212,7 @@ var updateCommand = new Command("update").description("Update vibgrate to the la
10573
11212
  );
10574
11213
  async function rewarmVgdAndReport(cwd) {
10575
11214
  try {
10576
- const { vgdIsRunning: vgdIsRunning2, vgdRequest: vgdRequest2 } = await import('./vgd-Y25XSQGZ.js');
11215
+ const { vgdIsRunning: vgdIsRunning2, vgdRequest: vgdRequest2 } = await import('./vgd-ORPA5C2K.js');
10577
11216
  if (!await vgdIsRunning2()) return;
10578
11217
  const loaded = await vgdRequest2({ op: "load-graph", root: cwd });
10579
11218
  if (!loaded.ok || !("repositoryId" in loaded)) return;
@@ -10662,13 +11301,13 @@ function collectCandidates(artifact) {
10662
11301
  return out2;
10663
11302
  }
10664
11303
  var defaultFixScanner = async (rootDir) => {
10665
- const scratch = path41.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
11304
+ const scratch = path43.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
10666
11305
  const scanOpts = { vibgrateVersion: VERSION, format: "json", out: scratch, quiet: true, concurrency: 8 };
10667
11306
  const advanced = await loadAdvancedScanHook();
10668
11307
  return runCoreScan(rootDir, scanOpts, advanced);
10669
11308
  };
10670
11309
  async function loadArtifact(rootDir, inFile, scan = defaultFixScanner) {
10671
- const artifactPath = path41.isAbsolute(inFile) ? inFile : path41.join(rootDir, inFile);
11310
+ const artifactPath = path43.isAbsolute(inFile) ? inFile : path43.join(rootDir, inFile);
10672
11311
  if (await pathExists(artifactPath)) {
10673
11312
  const staleness = scanStaleness(rootDir, artifactPath);
10674
11313
  if (!staleness.stale) {
@@ -10695,7 +11334,7 @@ async function repositoryIdentity(rootDir, override) {
10695
11334
  }
10696
11335
  }
10697
11336
  var fixCommand = new Command("fix").description("Get ranked, risk-tiered upgrade plans from the hosted planner and optionally apply them (prompts before changing files; --yes applies non-interactively, --dry-run previews, --no-apply only prints). Requires login/DSN.").argument("[path]", "Path to analyse", ".").option("--in <file>", "Scan artifact to read", ".vibgrate/scan_result.json").option("--format <format>", "Output format (text|json|md)", "text").option("--dsn <dsn>", 'DSN token (or use VIBGRATE_DSN env / "vg login")').option("--region <region>", "Override data residency region (us, eu)").option("--repository-name <name>", "Override the repository name recorded for this plan").option("--plan <tier>", "Apply a specific plan non-interactively (safe|balanced|aggressive)").option("--yes", "Apply the recommended plan without prompting").option("--dry-run", "Preview the recommended plan (or --plan <tier>) without applying; never prompts").option("--no-apply", "Only print the plans; never modify the project").option("--fail-on-vulns <severity>", "Exit non-zero if the recommended plan leaves an advisory at/above this severity unresolved (low|moderate|high|critical)").action(async (targetPath, opts) => {
10698
- const rootDir = path41.resolve(targetPath);
11337
+ const rootDir = path43.resolve(targetPath);
10699
11338
  if (!await pathExists(rootDir)) {
10700
11339
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
10701
11340
  process.exit(1);
@@ -10856,7 +11495,7 @@ function emit(report, format) {
10856
11495
  }
10857
11496
  }
10858
11497
  function relProjectDir(rootDir, projectPath) {
10859
- const rel = path41.isAbsolute(projectPath) ? path41.relative(rootDir, projectPath) : projectPath;
11498
+ const rel = path43.isAbsolute(projectPath) ? path43.relative(rootDir, projectPath) : projectPath;
10860
11499
  return rel === "" ? "." : rel;
10861
11500
  }
10862
11501
  async function buildTargetResolver(rootDir, artifact) {
@@ -10897,14 +11536,14 @@ function promptPlanSelection(response) {
10897
11536
  const defaultIdx = plans.findIndex((p) => p.tier === response.recommended);
10898
11537
  const def = defaultIdx >= 0 ? defaultIdx + 1 : 1;
10899
11538
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10900
- return new Promise((resolve21) => {
11539
+ return new Promise((resolve23) => {
10901
11540
  rl.question(`Plan [1-${plans.length}, default ${def}, q to cancel]: `, (ans) => {
10902
11541
  rl.close();
10903
11542
  const t = ans.trim().toLowerCase();
10904
- if (t === "q" || t === "quit") return resolve21(null);
11543
+ if (t === "q" || t === "quit") return resolve23(null);
10905
11544
  const n = t === "" ? def : Number.parseInt(t, 10);
10906
- if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve21(null);
10907
- resolve21(plans[n - 1].tier);
11545
+ if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve23(null);
11546
+ resolve23(plans[n - 1].tier);
10908
11547
  });
10909
11548
  });
10910
11549
  }
@@ -11699,7 +12338,7 @@ function formatMarkdown(artifact) {
11699
12338
 
11700
12339
  // src/reporting/commands/report.ts
11701
12340
  var reportCommand = new Command("report").description("Generate a drift report from a scan artifact").option("--in <file>", "Input artifact file", ".vibgrate/scan_result.json").option("--format <format>", "Output format (md|text|json)", "text").action(async (opts) => {
11702
- const artifactPath = path41.resolve(opts.in);
12341
+ const artifactPath = path43.resolve(opts.in);
11703
12342
  if (!await pathExists(artifactPath)) {
11704
12343
  console.error(chalk7.red(`Artifact not found: ${artifactPath}`));
11705
12344
  console.error(chalk7.dim('Run "vibgrate scan" first to generate a scan artifact.'));
@@ -11746,10 +12385,10 @@ function openUrl(url) {
11746
12385
  }
11747
12386
 
11748
12387
  // src/reporting/commands/login.ts
11749
- var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
12388
+ var delay = (ms) => new Promise((resolve23) => setTimeout(resolve23, ms));
11750
12389
  function isInside(dir, file) {
11751
- const rel = path41.relative(dir, file);
11752
- return !!rel && !rel.startsWith("..") && !path41.isAbsolute(rel);
12390
+ const rel = path43.relative(dir, file);
12391
+ return !!rel && !rel.startsWith("..") && !path43.isAbsolute(rel);
11753
12392
  }
11754
12393
  var loginCommand = new Command("login").description("Authenticate the CLI with your Vibgrate workspace via the browser").option("--ingest <url>", "Ingest API URL (overrides --region)").option("--region <region>", `Data residency region (${availableRegionIds().join(", ")})`, "us").option("--no-browser", "Do not attempt to open a browser automatically").option(
11755
12394
  "--local",
@@ -12004,7 +12643,7 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
12004
12643
  try {
12005
12644
  const statements = [];
12006
12645
  if (opts.from) {
12007
- const fromPath = path41.resolve(opts.from);
12646
+ const fromPath = path43.resolve(opts.from);
12008
12647
  if (!await pathExists(fromPath)) {
12009
12648
  process.stderr.write(chalk7.red(`Statements file not found: ${fromPath}
12010
12649
  `));
@@ -12022,9 +12661,9 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
12022
12661
  });
12023
12662
  const json2 = JSON.stringify(doc, null, 2);
12024
12663
  if (opts.out) {
12025
- await writeTextFile(path41.resolve(opts.out), json2 + "\n");
12664
+ await writeTextFile(path43.resolve(opts.out), json2 + "\n");
12026
12665
  process.stderr.write(
12027
- chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path41.resolve(opts.out)}
12666
+ chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path43.resolve(opts.out)}
12028
12667
  `
12029
12668
  );
12030
12669
  } else {
@@ -12207,7 +12846,7 @@ function formatDeltaText(base, current) {
12207
12846
  return lines.join("\n");
12208
12847
  }
12209
12848
  async function readArtifactOrExit(filePath) {
12210
- const absolutePath = path41.resolve(filePath);
12849
+ const absolutePath = path43.resolve(filePath);
12211
12850
  if (!await pathExists(absolutePath)) {
12212
12851
  console.error(chalk7.red(`Artifact not found: ${absolutePath}`));
12213
12852
  process.exit(1);
@@ -12224,7 +12863,7 @@ var exportCommand = new Command("export").description("Export scan artifact as S
12224
12863
  const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
12225
12864
  const body = JSON.stringify(sbom, null, 2);
12226
12865
  if (opts.out) {
12227
- await writeTextFile(path41.resolve(opts.out), body);
12866
+ await writeTextFile(path43.resolve(opts.out), body);
12228
12867
  console.log(chalk7.green("\u2714") + ` SBOM written to ${opts.out}`);
12229
12868
  } else {
12230
12869
  console.log(body);
@@ -12235,7 +12874,7 @@ var deltaCommand = new Command("delta").description("Show SBOM delta between two
12235
12874
  const current = await readArtifactOrExit(opts.to);
12236
12875
  const report = formatDeltaText(base, current);
12237
12876
  if (opts.out) {
12238
- await writeTextFile(path41.resolve(opts.out), report);
12877
+ await writeTextFile(path43.resolve(opts.out), report);
12239
12878
  console.log(chalk7.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
12240
12879
  } else {
12241
12880
  console.log(report);
@@ -12366,20 +13005,20 @@ function resolveRegime(id) {
12366
13005
  return regime;
12367
13006
  }
12368
13007
  function evidenceDir(root2) {
12369
- return path41.join(root2, ".vibgrate", "evidence");
13008
+ return path43.join(root2, ".vibgrate", "evidence");
12370
13009
  }
12371
13010
  function orgPath(root2) {
12372
- return path41.join(evidenceDir(root2), "org.json");
13011
+ return path43.join(evidenceDir(root2), "org.json");
12373
13012
  }
12374
13013
  function productsPath(root2) {
12375
- return path41.join(evidenceDir(root2), "products.json");
13014
+ return path43.join(evidenceDir(root2), "products.json");
12376
13015
  }
12377
13016
  function releasesDir(root2) {
12378
- return path41.join(evidenceDir(root2), "releases");
13017
+ return path43.join(evidenceDir(root2), "releases");
12379
13018
  }
12380
13019
  function releasePath(root2, productId, version) {
12381
13020
  const safe = `${productId}@${version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
12382
- return path41.join(releasesDir(root2), `${safe}.json`);
13021
+ return path43.join(releasesDir(root2), `${safe}.json`);
12383
13022
  }
12384
13023
  var DEFAULT_ORG = {
12385
13024
  responsiblePersons: [],
@@ -12410,7 +13049,7 @@ async function freezeRelease(root2, release) {
12410
13049
  const p = releasePath(root2, release.productId, release.version);
12411
13050
  if (await pathExists(p)) {
12412
13051
  throw new CliError(
12413
- `release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${path41.relative(root2, p)} only if it was frozen in error`,
13052
+ `release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${path43.relative(root2, p)} only if it was frozen in error`,
12414
13053
  ExitCode.USAGE_ERROR
12415
13054
  );
12416
13055
  }
@@ -12424,7 +13063,7 @@ async function loadReleases(root2, productId) {
12424
13063
  const files = (await readdir(dir)).filter((f) => f.endsWith(".json")).sort();
12425
13064
  const releases = [];
12426
13065
  for (const f of files) {
12427
- const rel = await readJsonFile(path41.join(dir, f));
13066
+ const rel = await readJsonFile(path43.join(dir, f));
12428
13067
  if (!productId || rel.productId === productId) releases.push(rel);
12429
13068
  }
12430
13069
  return releases;
@@ -13119,19 +13758,19 @@ function verifyEvidenceEnvelope(env, opts = {}) {
13119
13758
  var DEFAULT_KEY = "attest-key.pem";
13120
13759
  function resolveSigningKey(root2, explicit) {
13121
13760
  const chosen = process.env.VG_ATTEST_KEY;
13122
- const keyPath = chosen ? path41.resolve(chosen) : path41.join(root2, ".vibgrate", DEFAULT_KEY);
13761
+ const keyPath = chosen ? path43.resolve(chosen) : path43.join(root2, ".vibgrate", DEFAULT_KEY);
13123
13762
  let minted = false;
13124
- if (!fs11.existsSync(keyPath)) {
13763
+ if (!fs12.existsSync(keyPath)) {
13125
13764
  if (chosen) throw new CliError(`signing key not found: ${chosen}`, ExitCode.USAGE_ERROR);
13126
13765
  const kp = generateKeypair();
13127
- fs11.mkdirSync(path41.dirname(keyPath), { recursive: true });
13128
- fs11.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
13129
- fs11.writeFileSync(`${keyPath}.pub`, kp.publicPem);
13766
+ fs12.mkdirSync(path43.dirname(keyPath), { recursive: true });
13767
+ fs12.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
13768
+ fs12.writeFileSync(`${keyPath}.pub`, kp.publicPem);
13130
13769
  minted = true;
13131
13770
  }
13132
13771
  let key2;
13133
13772
  try {
13134
- key2 = crypto3.createPrivateKey(fs11.readFileSync(keyPath, "utf8"));
13773
+ key2 = crypto3.createPrivateKey(fs12.readFileSync(keyPath, "utf8"));
13135
13774
  } catch {
13136
13775
  throw new CliError(`could not read an Ed25519 private key from ${keyPath}`, ExitCode.USAGE_ERROR);
13137
13776
  }
@@ -13142,16 +13781,16 @@ function resolveSigningKey(root2, explicit) {
13142
13781
  }
13143
13782
  function writeBundle(input) {
13144
13783
  const dir = input.outDir;
13145
- fs11.mkdirSync(path41.join(dir, "inputs", "releases"), { recursive: true });
13146
- const write = (rel, data) => fs11.writeFileSync(path41.join(dir, rel), `${JSON.stringify(data, null, 2)}
13784
+ fs12.mkdirSync(path43.join(dir, "inputs", "releases"), { recursive: true });
13785
+ const write = (rel, data) => fs12.writeFileSync(path43.join(dir, rel), `${JSON.stringify(data, null, 2)}
13147
13786
  `);
13148
13787
  write("result.json", input.result);
13149
- write(path41.join("inputs", "advisory.json"), input.advisory);
13788
+ write(path43.join("inputs", "advisory.json"), input.advisory);
13150
13789
  for (const rel of input.releases) {
13151
13790
  const safe = `${rel.productId}@${rel.version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
13152
- write(path41.join("inputs", "releases", `${safe}.json`), rel);
13791
+ write(path43.join("inputs", "releases", `${safe}.json`), rel);
13153
13792
  }
13154
- write(path41.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
13793
+ write(path43.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
13155
13794
  write("provenance.json", {
13156
13795
  method: "deterministic",
13157
13796
  modelDrafted: [],
@@ -13167,13 +13806,13 @@ function writeBundle(input) {
13167
13806
  disclaimer: input.regime.disclaimer
13168
13807
  });
13169
13808
  if (input.envelope) {
13170
- fs11.writeFileSync(path41.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
13809
+ fs12.writeFileSync(path43.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
13171
13810
  `);
13172
13811
  }
13173
13812
  if (input.timestampToken) {
13174
- fs11.writeFileSync(path41.join(dir, "timestamp.tsr"), input.timestampToken);
13813
+ fs12.writeFileSync(path43.join(dir, "timestamp.tsr"), input.timestampToken);
13175
13814
  }
13176
- fs11.writeFileSync(path41.join(dir, "VERIFY.md"), verifyDoc(input));
13815
+ fs12.writeFileSync(path43.join(dir, "VERIFY.md"), verifyDoc(input));
13177
13816
  return dir;
13178
13817
  }
13179
13818
  function verifyDoc(input) {
@@ -13234,13 +13873,13 @@ function undeterminedFields(result, regime) {
13234
13873
  return gaps.filter((g) => regime.submission.requires.some((r) => g.startsWith(r)) || g.startsWith("exposure") || g.startsWith("member"));
13235
13874
  }
13236
13875
  async function recordDrill(root2, record) {
13237
- const dir = path41.join(evidenceDir(root2), "drills");
13238
- const p = path41.join(dir, `${record.drillId}.json`);
13876
+ const dir = path43.join(evidenceDir(root2), "drills");
13877
+ const p = path43.join(dir, `${record.drillId}.json`);
13239
13878
  await writeJsonFile(p, record);
13240
13879
  return p;
13241
13880
  }
13242
13881
  async function hasRecentDrill(root2, asOf) {
13243
- const dir = path41.join(evidenceDir(root2), "drills");
13882
+ const dir = path43.join(evidenceDir(root2), "drills");
13244
13883
  if (!await pathExists(dir)) return void 0;
13245
13884
  const { readdir } = await import('fs/promises');
13246
13885
  const { readJsonFile: readJsonFile2 } = await import('./fs-4G5A65KS.js');
@@ -13248,7 +13887,7 @@ async function hasRecentDrill(root2, asOf) {
13248
13887
  if (files.length === 0) return void 0;
13249
13888
  const cutoff = new Date(new Date(asOf).getTime() - 90 * 24 * 3600 * 1e3).toISOString();
13250
13889
  for (const f of files) {
13251
- const rec = await readJsonFile2(path41.join(dir, f));
13890
+ const rec = await readJsonFile2(path43.join(dir, f));
13252
13891
  if (rec.ranAt >= cutoff) return true;
13253
13892
  }
13254
13893
  return false;
@@ -13328,7 +13967,7 @@ function formatRegimeList() {
13328
13967
 
13329
13968
  // src/reporting/commands/evidence/index.ts
13330
13969
  function root(opts) {
13331
- return path41.resolve(opts.cwd ?? process.cwd());
13970
+ return path43.resolve(opts.cwd ?? process.cwd());
13332
13971
  }
13333
13972
  function slug(name) {
13334
13973
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "product";
@@ -13416,7 +14055,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
13416
14055
  const release = await buildRelease({
13417
14056
  productId: product.id,
13418
14057
  version,
13419
- from: path41.resolve(rootDir, opts.from),
14058
+ from: path43.resolve(rootDir, opts.from),
13420
14059
  shipDate: opts.shipDate,
13421
14060
  buildId: opts.buildId,
13422
14061
  artefactDigest: opts.digest,
@@ -13424,7 +14063,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
13424
14063
  frozenAt: nowIso()
13425
14064
  });
13426
14065
  const p = await freezeRelease(rootDir, release);
13427
- console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path41.relative(rootDir, p)}`);
14066
+ console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path43.relative(rootDir, p)}`);
13428
14067
  });
13429
14068
  async function runExposure(rootDir, vuln, opts) {
13430
14069
  const org = await loadOrg(rootDir);
@@ -13476,7 +14115,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
13476
14115
  console.log("\n" + buildPack(result, regime, org, stage));
13477
14116
  }
13478
14117
  if (opts.bundle) {
13479
- const dir = path41.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
14118
+ const dir = path43.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
13480
14119
  let envelope;
13481
14120
  if (opts.sign !== false) {
13482
14121
  const { key: key2, minted } = resolveSigningKey(rootDir);
@@ -13484,7 +14123,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
13484
14123
  envelope = signEvidenceStatement(buildEvidenceStatement(result, VERSION), key2);
13485
14124
  }
13486
14125
  writeBundle({ outDir: dir, result, advisory, releases, regime, envelope, timestampToken, cliVersion: VERSION });
13487
- console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path41.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
14126
+ console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path43.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
13488
14127
  }
13489
14128
  process.exitCode = exposureExit(result.overallStatus);
13490
14129
  });
@@ -13516,7 +14155,7 @@ var packCmd = new Command("pack").description("Build the submission pack a human
13516
14155
  const stage = opts.stage ?? regime.clocks[0]?.stage ?? "early-warning";
13517
14156
  const md = buildPack(result, regime, org, stage);
13518
14157
  if (opts.out) {
13519
- fs11.writeFileSync(path41.resolve(rootDir, opts.out), md);
14158
+ fs12.writeFileSync(path43.resolve(rootDir, opts.out), md);
13520
14159
  console.error(chalk7.green("\u2714") + ` pack written to ${opts.out}`);
13521
14160
  } else {
13522
14161
  console.log(md);
@@ -13558,20 +14197,20 @@ var drillCmd = new Command("drill").description("Timed dry-run of the determinat
13558
14197
  }
13559
14198
  });
13560
14199
  var verifyCmd = new Command("verify").description("Verify an evidence bundle offline (no Vibgrate needed)").argument("<bundle>", "Path to an evidence bundle directory or evidence.intoto.jsonl").option("--pub <file>", "Public key PEM to pin the signer (establish trust)").action((bundlePath, opts) => {
13561
- const abs = path41.resolve(bundlePath);
13562
- const envPath = fs11.statSync(abs).isDirectory() ? path41.join(abs, "evidence.intoto.jsonl") : abs;
13563
- if (!fs11.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
13564
- const envelope = JSON.parse(fs11.readFileSync(envPath, "utf8").trim().split("\n")[0]);
13565
- const resultPath = path41.join(path41.dirname(envPath), "result.json");
13566
- const result = fs11.existsSync(resultPath) ? JSON.parse(fs11.readFileSync(resultPath, "utf8")) : void 0;
13567
- const publicKeyPem = opts.pub ? fs11.readFileSync(path41.resolve(opts.pub), "utf8") : void 0;
14200
+ const abs = path43.resolve(bundlePath);
14201
+ const envPath = fs12.statSync(abs).isDirectory() ? path43.join(abs, "evidence.intoto.jsonl") : abs;
14202
+ if (!fs12.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
14203
+ const envelope = JSON.parse(fs12.readFileSync(envPath, "utf8").trim().split("\n")[0]);
14204
+ const resultPath = path43.join(path43.dirname(envPath), "result.json");
14205
+ const result = fs12.existsSync(resultPath) ? JSON.parse(fs12.readFileSync(resultPath, "utf8")) : void 0;
14206
+ const publicKeyPem = opts.pub ? fs12.readFileSync(path43.resolve(opts.pub), "utf8") : void 0;
13568
14207
  const v = verifyEvidenceEnvelope(envelope, { publicKeyPem, result });
13569
14208
  const color = v.status === "verified" ? chalk7.green : v.status === "failed" ? chalk7.red : chalk7.yellow;
13570
14209
  console.log(" " + color(v.status.toUpperCase()) + ` ${v.reason}`);
13571
14210
  if (v.evidenceId) console.log(" " + chalk7.dim(`evidence ${v.evidenceId} \xB7 regime ${v.regime} \xB7 advisory ${v.advisoryId} \xB7 ${v.overallStatus}`));
13572
- const tsrPath = path41.join(path41.dirname(envPath), "timestamp.tsr");
13573
- if (fs11.existsSync(tsrPath) && result) {
13574
- const t = verifyTimestamp(fs11.readFileSync(tsrPath), exposureSubjectDigest(result));
14211
+ const tsrPath = path43.join(path43.dirname(envPath), "timestamp.tsr");
14212
+ if (fs12.existsSync(tsrPath) && result) {
14213
+ const t = verifyTimestamp(fs12.readFileSync(tsrPath), exposureSubjectDigest(result));
13575
14214
  const tcolor = t.imprintMatches ? chalk7.green : chalk7.red;
13576
14215
  console.log(" " + tcolor("TIMESTAMP") + ` ${t.reason}`);
13577
14216
  }
@@ -13638,12 +14277,12 @@ var exportCmd = new Command("export").description("Air-gap bundle of all evidenc
13638
14277
  const releases = [];
13639
14278
  for (const list of releasesByProduct.values()) releases.push(...list);
13640
14279
  const report = computeReadiness({ regime, org, products, releasesByProduct, recentDrill: await hasRecentDrill(rootDir, today()) });
13641
- const dir = path41.resolve(rootDir, opts.out);
13642
- await writeJsonFile(path41.join(dir, "org.json"), org);
13643
- await writeJsonFile(path41.join(dir, "products.json"), products);
13644
- for (const r of releases) await writeJsonFile(path41.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
13645
- await writeJsonFile(path41.join(dir, "readiness.json"), report);
13646
- console.error(chalk7.green("\u2714") + ` exported evidence state to ${path41.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
14280
+ const dir = path43.resolve(rootDir, opts.out);
14281
+ await writeJsonFile(path43.join(dir, "org.json"), org);
14282
+ await writeJsonFile(path43.join(dir, "products.json"), products);
14283
+ for (const r of releases) await writeJsonFile(path43.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
14284
+ await writeJsonFile(path43.join(dir, "readiness.json"), report);
14285
+ console.error(chalk7.green("\u2714") + ` exported evidence state to ${path43.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
13647
14286
  });
13648
14287
  var pushCmd = new Command("push").description("Push the product registry (and an optional exposure result) to Vibgrate Cloud").option(...cwdOption).option("--dsn <dsn>", "DSN token (or use VIBGRATE_DSN env / `vg login`)").option("--regime <id>", "Reporting regime").option("--result <file>", "An exposure result.json (or a bundle dir) to include").option("--signed", "Mark the included exposure result as signed").option("--strict", "Fail on push errors").action(async (opts) => {
13649
14288
  const rootDir = root(opts);
@@ -13669,10 +14308,10 @@ var pushCmd = new Command("push").description("Push the product registry (and an
13669
14308
  }));
13670
14309
  let exposure;
13671
14310
  if (opts.result) {
13672
- const raw = path41.resolve(rootDir, opts.result);
13673
- const resultPath = fs11.existsSync(raw) && fs11.statSync(raw).isDirectory() ? path41.join(raw, "result.json") : raw;
13674
- if (!fs11.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
13675
- exposure = JSON.parse(fs11.readFileSync(resultPath, "utf8"));
14311
+ const raw = path43.resolve(rootDir, opts.result);
14312
+ const resultPath = fs12.existsSync(raw) && fs12.statSync(raw).isDirectory() ? path43.join(raw, "result.json") : raw;
14313
+ if (!fs12.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
14314
+ exposure = JSON.parse(fs12.readFileSync(resultPath, "utf8"));
13676
14315
  }
13677
14316
  const payload = { schemaVersion: "evidence-push-1", regime: regime.id, generatedAt: nowIso(), signed: Boolean(opts.signed), products: productPayload, exposure };
13678
14317
  const body = JSON.stringify(payload);
@@ -13734,6 +14373,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
13734
14373
  "daemon",
13735
14374
  "policy",
13736
14375
  "llm-host",
14376
+ "hcs",
13737
14377
  "install",
13738
14378
  "uninstall",
13739
14379
  "share",
@@ -13798,6 +14438,7 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
13798
14438
  registerDaemon(program);
13799
14439
  registerPolicy(program);
13800
14440
  registerLlmHost(program);
14441
+ registerHcs(program);
13801
14442
  program.addCommand(initCommand);
13802
14443
  program.addCommand(scanCommand);
13803
14444
  program.addCommand(fixCommand);
@@ -13866,7 +14507,7 @@ function dispatch(argv, cwd) {
13866
14507
  }
13867
14508
  const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
13868
14509
  if (looksLikeQuestion) return ["ask", ...args];
13869
- if (fs11.existsSync(path41.resolve(cwd, first))) {
14510
+ if (fs12.existsSync(path43.resolve(cwd, first))) {
13870
14511
  return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
13871
14512
  }
13872
14513
  const moved = MOVED_COMMANDS[first];
@@ -13911,9 +14552,9 @@ async function main(argv = process.argv) {
13911
14552
  }
13912
14553
  function readCwd(raw) {
13913
14554
  const i = raw.findIndex((a) => a === "-C" || a === "--cwd");
13914
- if (i >= 0 && raw[i + 1]) return path41.resolve(raw[i + 1]);
14555
+ if (i >= 0 && raw[i + 1]) return path43.resolve(raw[i + 1]);
13915
14556
  const eq = raw.find((a) => a.startsWith("--cwd="));
13916
- if (eq) return path41.resolve(eq.slice("--cwd=".length));
14557
+ if (eq) return path43.resolve(eq.slice("--cwd=".length));
13917
14558
  return process.cwd();
13918
14559
  }
13919
14560
  function handleError(err) {