@vibgrate/cli 2026.807.1 → 2026.814.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/NOTICE +7 -0
  2. package/dist/agent-2ZISYEQF.js +26 -0
  3. package/dist/{agent-K3J6EHLI.js.map → agent-2ZISYEQF.js.map} +1 -1
  4. package/dist/approvals-DOZ5RWJP.js +9 -0
  5. package/dist/approvals-DOZ5RWJP.js.map +1 -0
  6. package/dist/baseline-AGX42TZM.js +9 -0
  7. package/dist/{baseline-IAFWF2ET.js.map → baseline-AGX42TZM.js.map} +1 -1
  8. package/dist/{checkpoint-4WFZMKEO.js → checkpoint-UYMYMMQO.js} +6 -3
  9. package/dist/checkpoint-UYMYMMQO.js.map +1 -0
  10. package/dist/{chunk-N5EP5ZR2.js → chunk-2HNPL4OB.js} +5 -5
  11. package/dist/{chunk-N5EP5ZR2.js.map → chunk-2HNPL4OB.js.map} +1 -1
  12. package/dist/{chunk-2HAJCW7Z.js → chunk-2W3GBKSV.js} +5 -5
  13. package/dist/{chunk-2HAJCW7Z.js.map → chunk-2W3GBKSV.js.map} +1 -1
  14. package/dist/{chunk-XSHGXGVJ.js → chunk-5KY5UCDJ.js} +4 -4
  15. package/dist/{chunk-XSHGXGVJ.js.map → chunk-5KY5UCDJ.js.map} +1 -1
  16. package/dist/{chunk-NWX4VUFS.js → chunk-6OP5U55G.js} +8 -8
  17. package/dist/{chunk-NWX4VUFS.js.map → chunk-6OP5U55G.js.map} +1 -1
  18. package/dist/{chunk-KEIMMCS5.js → chunk-7CDW25VY.js} +4 -4
  19. package/dist/{chunk-KEIMMCS5.js.map → chunk-7CDW25VY.js.map} +1 -1
  20. package/dist/chunk-A4F7ESUR.js +174 -0
  21. package/dist/chunk-A4F7ESUR.js.map +1 -0
  22. package/dist/chunk-AJS4EL2C.js +266 -0
  23. package/dist/chunk-AJS4EL2C.js.map +1 -0
  24. package/dist/{chunk-5ESL76CM.js → chunk-BTYFZ3NM.js} +9 -8
  25. package/dist/chunk-BTYFZ3NM.js.map +1 -0
  26. package/dist/{chunk-JFCCJWXD.js → chunk-BXPWVTGS.js} +4 -3
  27. package/dist/chunk-BXPWVTGS.js.map +1 -0
  28. package/dist/{chunk-7CYFCSY2.js → chunk-EBUTRJHX.js} +24 -6
  29. package/dist/chunk-EBUTRJHX.js.map +1 -0
  30. package/dist/{chunk-EXOYSXH6.js → chunk-HYC3A2AT.js} +3 -3
  31. package/dist/{chunk-EXOYSXH6.js.map → chunk-HYC3A2AT.js.map} +1 -1
  32. package/dist/{chunk-G4KO5W6H.js → chunk-J3IDTLF4.js} +19 -9
  33. package/dist/chunk-J3IDTLF4.js.map +1 -0
  34. package/dist/chunk-JYY6G46J.js +64 -0
  35. package/dist/chunk-JYY6G46J.js.map +1 -0
  36. package/dist/{chunk-2M6B5V2U.js → chunk-K7MONYIM.js} +30 -66
  37. package/dist/chunk-K7MONYIM.js.map +1 -0
  38. package/dist/{chunk-ADP6ITGF.js → chunk-N3XFY3PX.js} +68 -11
  39. package/dist/chunk-N3XFY3PX.js.map +1 -0
  40. package/dist/{chunk-INIULQEP.js → chunk-N6ZMZ5AI.js} +11 -2
  41. package/dist/chunk-N6ZMZ5AI.js.map +1 -0
  42. package/dist/{chunk-QXIWQ2WG.js → chunk-NXDYWBZB.js} +4 -4
  43. package/dist/{chunk-QXIWQ2WG.js.map → chunk-NXDYWBZB.js.map} +1 -1
  44. package/dist/{chunk-GQ2EQXBG.js → chunk-QFCJY6FQ.js} +6 -5
  45. package/dist/chunk-QFCJY6FQ.js.map +1 -0
  46. package/dist/chunk-QIUQH2ND.js +6 -0
  47. package/dist/{chunk-ITY2NPIQ.js.map → chunk-QIUQH2ND.js.map} +1 -1
  48. package/dist/{chunk-FOKURZL3.js → chunk-RBBP4SP7.js} +12 -10
  49. package/dist/chunk-RBBP4SP7.js.map +1 -0
  50. package/dist/{chunk-VNAOFA6X.js → chunk-RNZP2XAL.js} +8 -8
  51. package/dist/chunk-RNZP2XAL.js.map +1 -0
  52. package/dist/{chunk-Y4JO6LYP.js → chunk-TFAXW7VM.js} +302 -11
  53. package/dist/chunk-TFAXW7VM.js.map +1 -0
  54. package/dist/{chunk-LS7GZBKP.js → chunk-UJAOCFQQ.js} +19 -9
  55. package/dist/chunk-UJAOCFQQ.js.map +1 -0
  56. package/dist/{chunk-PT2XQTSK.js → chunk-VD6TVFGA.js} +7 -6
  57. package/dist/chunk-VD6TVFGA.js.map +1 -0
  58. package/dist/{chunk-VQVLY63G.js → chunk-WN2AAB5O.js} +212 -59
  59. package/dist/chunk-WN2AAB5O.js.map +1 -0
  60. package/dist/{chunk-EJUMV5HU.js → chunk-XEI7UU6G.js} +3 -3
  61. package/dist/{chunk-EJUMV5HU.js.map → chunk-XEI7UU6G.js.map} +1 -1
  62. package/dist/cli.js +1179 -511
  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-TYMYYIJE.js → ensure-map-EURJPSAK.js} +15 -14
  67. package/dist/{ensure-map-TYMYYIJE.js.map → ensure-map-EURJPSAK.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-VUW2QWPI.js +14 -0
  71. package/dist/{graph-backend-5YOWNHHG.js.map → graph-backend-VUW2QWPI.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-YEMXHGBO.js → interactive-WRA477OW.js} +32 -30
  76. package/dist/interactive-WRA477OW.js.map +1 -0
  77. package/dist/load-XZV5LEGA.js +10 -0
  78. package/dist/{load-IIWVYUN7.js.map → load-XZV5LEGA.js.map} +1 -1
  79. package/dist/{run-outcome-2JO55QCC.js → run-outcome-X5KS6AUE.js} +6 -5
  80. package/dist/run-outcome-X5KS6AUE.js.map +1 -0
  81. package/dist/runtime-session-J7GDVRFU.js +21 -0
  82. package/dist/{runtime-session-HFKGKQV7.js.map → runtime-session-J7GDVRFU.js.map} +1 -1
  83. package/dist/session-3R34WA5S.js +16 -0
  84. package/dist/{session-5LFX4U2E.js.map → session-3R34WA5S.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-DUCFTBUF.js → stream-json-LKVPDKXP.js} +76 -24
  88. package/dist/stream-json-LKVPDKXP.js.map +1 -0
  89. package/dist/version-55TOTJTF.js +4 -0
  90. package/dist/version-55TOTJTF.js.map +1 -0
  91. package/dist/{vg-mcp-bridge-4KPDQUFN.js → vg-mcp-bridge-ZPJAHP7T.js} +11 -10
  92. package/dist/vg-mcp-bridge-ZPJAHP7T.js.map +1 -0
  93. package/dist/{vgd-LFHQ4GWC.js → vgd-UIFH5TTW.js} +12 -11
  94. package/dist/vgd-UIFH5TTW.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 +9 -7
  98. package/dist/agent-K3J6EHLI.js +0 -24
  99. package/dist/baseline-IAFWF2ET.js +0 -9
  100. package/dist/checkpoint-4WFZMKEO.js.map +0 -1
  101. package/dist/chunk-2M6B5V2U.js.map +0 -1
  102. package/dist/chunk-5ESL76CM.js.map +0 -1
  103. package/dist/chunk-7CYFCSY2.js.map +0 -1
  104. package/dist/chunk-ADP6ITGF.js.map +0 -1
  105. package/dist/chunk-FOKURZL3.js.map +0 -1
  106. package/dist/chunk-G4KO5W6H.js.map +0 -1
  107. package/dist/chunk-GQ2EQXBG.js.map +0 -1
  108. package/dist/chunk-INIULQEP.js.map +0 -1
  109. package/dist/chunk-ITY2NPIQ.js +0 -6
  110. package/dist/chunk-JFCCJWXD.js.map +0 -1
  111. package/dist/chunk-LS7GZBKP.js.map +0 -1
  112. package/dist/chunk-PT2XQTSK.js.map +0 -1
  113. package/dist/chunk-VNAOFA6X.js.map +0 -1
  114. package/dist/chunk-VQVLY63G.js.map +0 -1
  115. package/dist/chunk-Y4JO6LYP.js.map +0 -1
  116. package/dist/chunk-Z7FM3ETS.js +0 -126
  117. package/dist/chunk-Z7FM3ETS.js.map +0 -1
  118. package/dist/graph-backend-5YOWNHHG.js +0 -13
  119. package/dist/interactive-YEMXHGBO.js.map +0 -1
  120. package/dist/load-IIWVYUN7.js +0 -9
  121. package/dist/run-outcome-2JO55QCC.js.map +0 -1
  122. package/dist/runtime-session-HFKGKQV7.js +0 -20
  123. package/dist/session-5LFX4U2E.js +0 -15
  124. package/dist/session-store-KGONLWHN.js +0 -4
  125. package/dist/stream-json-DUCFTBUF.js.map +0 -1
  126. package/dist/vg-mcp-bridge-4KPDQUFN.js.map +0 -1
  127. package/dist/vgd-LFHQ4GWC.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-Y4JO6LYP.js';
3
- import { fetchCatalog, resolveProviders } from './chunk-N5EP5ZR2.js';
4
- import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-2HAJCW7Z.js';
2
+ import { fetchCatalog, resolveProviders } from './chunk-2HNPL4OB.js';
3
+ import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-5KY5UCDJ.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-6OP5U55G.js';
6
+ export { runBuild } from './chunk-6OP5U55G.js';
7
+ import { disableColor, info, c, json, out } from './chunk-CT5BS56U.js';
8
+ import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-2W3GBKSV.js';
5
9
  import './chunk-IS7VTH2Q.js';
6
- import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-XSHGXGVJ.js';
7
- import { runCodeSession } from './chunk-PT2XQTSK.js';
8
- import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-VQVLY63G.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-VD6TVFGA.js';
13
+ import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-WN2AAB5O.js';
9
14
  import './chunk-543E6WDJ.js';
10
- import { summarizeDiffs, ScriptedProvider } from './chunk-ADP6ITGF.js';
15
+ import './chunk-A4F7ESUR.js';
16
+ import './chunk-HYC3A2AT.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-NWX4VUFS.js';
15
- export { runBuild } from './chunk-NWX4VUFS.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-EXOYSXH6.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-VNAOFA6X.js';
27
- import { refreshIfStale } from './chunk-GQ2EQXBG.js';
28
- import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-FOKURZL3.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-G4KO5W6H.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-5ESL76CM.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-INIULQEP.js';
27
+ import { serveStdio, isRelevantChange, exportGraph, GraphSource, createServer, formatForExt, RefreshScheduler } from './chunk-RNZP2XAL.js';
28
+ import { refreshIfStale } from './chunk-QFCJY6FQ.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-J3IDTLF4.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-BTYFZ3NM.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-QXIWQ2WG.js';
34
+ import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-NXDYWBZB.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-RBBP4SP7.js';
37
+ import { queryGraphSemantic, queryGraph, indexFor, impactOf } from './chunk-EBUTRJHX.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-BXPWVTGS.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-7CYFCSY2.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-LS7GZBKP.js';
46
- import { loadGraph, loadGraphPreferIndex, SCHEMA_VERSION } from './chunk-JFCCJWXD.js';
47
- import { cacheDir, resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, resetRelevanceProviderCache, loadRelevanceProvider, loadGraphFileWithSnapshot, serializeGraph, stableStringify, writeArtifacts, vibgrateDir, mapFileExists, relevanceModuleDir, parseGraph, ensureVibgrateGitignore } from './chunk-2M6B5V2U.js';
48
- import { VERSION } from './chunk-ITY2NPIQ.js';
47
+ import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, unavailableMessage, countPending, modelCacheInfo, embeddingsPath, clearModelCache, withTimeout } from './chunk-UJAOCFQQ.js';
48
+ import { cacheDir } from './chunk-JYY6G46J.js';
49
+ import { resetRelevanceProviderCache, loadRelevanceProvider, relevanceModuleDir, resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, loadGraphFileWithSnapshot, serializeGraph, stableStringify, writeArtifacts, vibgrateDir, mapFileExists, parseGraph, ensureVibgrateGitignore } from './chunk-K7MONYIM.js';
50
+ import { VERSION } from './chunk-QIUQH2ND.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,10 +3095,10 @@ function pruneArtifactProjects(a) {
3092
3095
  return { ...a, projects, findings };
3093
3096
  }
3094
3097
  function projectByPath(a, projectPath) {
3095
- const want = path41.normalize(projectPath === "" ? "." : projectPath);
3098
+ const norm = (p) => path43.normalize((p === "" ? "." : p).replace(/\\/g, "/"));
3099
+ const want = norm(projectPath);
3096
3100
  for (const proj of a.projects ?? []) {
3097
- const got = path41.normalize(proj.path === "" ? "." : proj.path);
3098
- if (got === want) return proj;
3101
+ if (norm(proj.path) === want) return proj;
3099
3102
  }
3100
3103
  return void 0;
3101
3104
  }
@@ -3103,7 +3106,7 @@ function buildProjectRefs(rootDir, projects) {
3103
3106
  if (projects.length === 0) return void 0;
3104
3107
  const byPath = /* @__PURE__ */ new Map();
3105
3108
  for (const p of projects) {
3106
- const rel = p.path === "" ? "." : p.path;
3109
+ const rel = (p.path === "" ? "." : p.path).replace(/\\/g, "/");
3107
3110
  const prev = byPath.get(rel);
3108
3111
  if (!prev) {
3109
3112
  byPath.set(rel, p);
@@ -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("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 [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-IIWVYUN7.js');
7264
+ const { loadGraph: loadGraph2 } = await import('./load-XZV5LEGA.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-YEMXHGBO.js');
7349
+ const { runInteractive } = await import('./interactive-WRA477OW.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-TYMYYIJE.js');
7379
+ const { ensureCodeMap } = await import('./ensure-map-EURJPSAK.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-2JO55QCC.js');
7464
+ const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-X5KS6AUE.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-DUCFTBUF.js');
7192
- const { nodeCodeFs } = await import('./session-5LFX4U2E.js');
7466
+ const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-LKVPDKXP.js');
7467
+ const { nodeCodeFs } = await import('./session-3R34WA5S.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-HFKGKQV7.js');
7199
- const { resolveGraphBackend } = await import('./graph-backend-5YOWNHHG.js');
7473
+ const { startCodeRuntimeSession } = await import('./runtime-session-J7GDVRFU.js');
7474
+ const { resolveGraphBackend } = await import('./graph-backend-VUW2QWPI.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-LFHQ4GWC.js');
7477
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-UIFH5TTW.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-4KPDQUFN.js');
7535
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-ZPJAHP7T.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-DOZ5RWJP.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-DUCFTBUF.js');
7355
- const { runAgent: runAgent2 } = await import('./agent-K3J6EHLI.js');
7638
+ const { runCodeStreamJsonSession, STREAM_JSON_PROTOCOL_VERSION } = await import('./stream-json-LKVPDKXP.js');
7639
+ const { runAgent: runAgent2 } = await import('./agent-2ZISYEQF.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-55TOTJTF.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-YEMXHGBO.js');
7524
- const { nodeCodeFs } = await import('./session-5LFX4U2E.js');
7862
+ const { agentTask } = await import('./interactive-WRA477OW.js');
7863
+ const { nodeCodeFs } = await import('./session-3R34WA5S.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-4KPDQUFN.js');
7878
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-ZPJAHP7T.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-HFKGKQV7.js');
7562
- const { resolveGraphBackend } = await import('./graph-backend-5YOWNHHG.js');
7902
+ const { startCodeRuntimeSession } = await import('./runtime-session-J7GDVRFU.js');
7903
+ const { resolveGraphBackend } = await import('./graph-backend-VUW2QWPI.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-LFHQ4GWC.js');
7906
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-UIFH5TTW.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) {
@@ -8333,10 +8674,16 @@ function registerDaemon(program) {
8333
8674
  }
8334
8675
  const child = await startDetachedVgd(socketPath);
8335
8676
  const res = await vgdRequest({ op: "status" }, { socketPath });
8677
+ if (!res.ok) {
8678
+ throw new CliError(
8679
+ `vgd started (pid ${child ?? "?"}) but status failed: ${res.error} (${socketPath})`,
8680
+ ExitCode.ERROR
8681
+ );
8682
+ }
8336
8683
  if (global.json) {
8337
- json({ running: true, ensured: true, ...res.ok ? res : { socketPath } });
8684
+ json({ running: true, ensured: true, ...res });
8338
8685
  } else if (!global.quiet) {
8339
- const pid = res.ok && "pid" in res ? res.pid : child;
8686
+ const pid = "pid" in res ? res.pid : child;
8340
8687
  info(`vgd \xB7 started in background pid ${pid} \xB7 ${c.dim(socketPath)}`);
8341
8688
  }
8342
8689
  });
@@ -8394,7 +8741,7 @@ function registerDaemon(program) {
8394
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) {
8395
8742
  const global = readGlobal(this);
8396
8743
  const socketPath = socketOf(this);
8397
- const root2 = path41.resolve(rootArg ?? rootOf(global));
8744
+ const root2 = path43.resolve(rootArg ?? rootOf(global));
8398
8745
  if (!await vgdIsRunning({ socketPath })) {
8399
8746
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
8400
8747
  }
@@ -8430,7 +8777,7 @@ function registerDaemon(program) {
8430
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) {
8431
8778
  const global = readGlobal(this);
8432
8779
  const socketPath = socketOf(this);
8433
- const primary = path41.resolve(rootArg ?? rootOf(global));
8780
+ const primary = path43.resolve(rootArg ?? rootOf(global));
8434
8781
  if (!await vgdIsRunning({ socketPath })) {
8435
8782
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
8436
8783
  }
@@ -8458,7 +8805,7 @@ function registerDaemon(program) {
8458
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) {
8459
8806
  const global = readGlobal(this);
8460
8807
  const socketPath = socketOf(this);
8461
- const root2 = path41.resolve(rootArg ?? rootOf(global));
8808
+ const root2 = path43.resolve(rootArg ?? rootOf(global));
8462
8809
  if (!await vgdIsRunning({ socketPath })) {
8463
8810
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon ensure\` (${socketPath})`, ExitCode.NOT_FOUND);
8464
8811
  }
@@ -8472,7 +8819,7 @@ function registerDaemon(program) {
8472
8819
  throw new CliError(loaded.error, ExitCode.NOT_FOUND);
8473
8820
  }
8474
8821
  if (!loaded.ok) {
8475
- const { loadGraph: loadGraph2 } = await import('./load-IIWVYUN7.js');
8822
+ const { loadGraph: loadGraph2 } = await import('./load-XZV5LEGA.js');
8476
8823
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
8477
8824
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
8478
8825
  const graph = loadGraph2(root2, global.graph);
@@ -8588,25 +8935,23 @@ function socketOf(cmd) {
8588
8935
  let c2 = cmd;
8589
8936
  while (c2) {
8590
8937
  const opts = c2.opts();
8591
- if (opts.socket) return path41.resolve(opts.socket);
8938
+ if (opts.socket) return path43.resolve(opts.socket);
8592
8939
  c2 = c2.parent;
8593
8940
  }
8594
8941
  return vgdSocketPath();
8595
8942
  }
8596
8943
  function spawnDetachedDaemonStart(socketPath) {
8944
+ const opts = {
8945
+ detached: true,
8946
+ stdio: "ignore",
8947
+ env: process.env,
8948
+ windowsHide: true
8949
+ };
8597
8950
  const entry = process.argv[1];
8598
8951
  if (entry && (entry.endsWith(".js") || entry.endsWith(".mjs") || entry.endsWith(".cjs"))) {
8599
- return spawn(process.execPath, [entry, "daemon", "start", "--socket", socketPath], {
8600
- detached: true,
8601
- stdio: "ignore",
8602
- env: process.env
8603
- });
8952
+ return spawn(process.execPath, [entry, "daemon", "start", "--socket", socketPath], opts);
8604
8953
  }
8605
- return spawn(process.argv[0] || "vg", ["daemon", "start", "--socket", socketPath], {
8606
- detached: true,
8607
- stdio: "ignore",
8608
- env: process.env
8609
- });
8954
+ return spawn(process.argv[0] || "vg", ["daemon", "start", "--socket", socketPath], opts);
8610
8955
  }
8611
8956
  function sleep(ms) {
8612
8957
  return new Promise((r) => setTimeout(r, ms));
@@ -8614,12 +8959,22 @@ function sleep(ms) {
8614
8959
  async function startDetachedVgd(socketPath) {
8615
8960
  const child = spawnDetachedDaemonStart(socketPath);
8616
8961
  child.unref();
8617
- const deadline = Date.now() + 8e3;
8962
+ const readyMs = 3e4;
8963
+ const deadline = Date.now() + readyMs;
8618
8964
  while (Date.now() < deadline) {
8619
- await sleep(100);
8965
+ await sleep(150);
8620
8966
  if (await vgdIsRunning({ socketPath })) return child.pid;
8967
+ if (child.exitCode != null && child.exitCode !== 0) {
8968
+ throw new CliError(
8969
+ `vgd child exited ${child.exitCode} before becoming ready at ${socketPath}`,
8970
+ ExitCode.ERROR
8971
+ );
8972
+ }
8621
8973
  }
8622
- throw new CliError(`vgd failed to become ready at ${socketPath}`, ExitCode.ERROR);
8974
+ throw new CliError(
8975
+ `vgd failed to become ready within ${Math.round(readyMs / 1e3)}s at ${socketPath}`,
8976
+ ExitCode.ERROR
8977
+ );
8623
8978
  }
8624
8979
  async function stopVgd(socketPath) {
8625
8980
  if (!await vgdIsRunning({ socketPath })) return "not-running";
@@ -8660,7 +9015,7 @@ async function restartVgdIfRunning(socketPath = vgdSocketPath()) {
8660
9015
  }
8661
9016
  function readVgdPid() {
8662
9017
  try {
8663
- const raw = fs11.readFileSync(vgdPidPath(), "utf8").trim();
9018
+ const raw = fs12.readFileSync(vgdPidPath(), "utf8").trim();
8664
9019
  const pid = Number.parseInt(raw, 10);
8665
9020
  return Number.isInteger(pid) && pid > 0 ? pid : null;
8666
9021
  } catch {
@@ -8745,7 +9100,7 @@ function registerPolicy(program) {
8745
9100
  const global = readGlobal(this);
8746
9101
  let raw;
8747
9102
  try {
8748
- raw = fs11.readFileSync(file, "utf8");
9103
+ raw = fs12.readFileSync(file, "utf8");
8749
9104
  } catch {
8750
9105
  throw new CliError(`cannot read ${file}`, ExitCode.NOT_FOUND);
8751
9106
  }
@@ -8864,12 +9219,299 @@ function registerLlmHost(program) {
8864
9219
  });
8865
9220
  applyGlobalOptions(cmd);
8866
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
+ }
8867
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) => {
8868
- const rootDir = path41.resolve(targetPath);
8869
- const vibgrateDir2 = path41.join(rootDir, ".vibgrate");
9510
+ const rootDir = path43.resolve(targetPath);
9511
+ const vibgrateDir2 = path43.join(rootDir, ".vibgrate");
8870
9512
  await ensureDir(vibgrateDir2);
8871
9513
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold(".vibgrate/")} directory`);
8872
- const configPath = path41.join(rootDir, "vibgrate.config.ts");
9514
+ const configPath = path43.join(rootDir, "vibgrate.config.ts");
8873
9515
  if (await pathExists(configPath)) {
8874
9516
  console.log(chalk7.dim(" vibgrate.config.ts already exists, skipping"));
8875
9517
  } else {
@@ -8877,7 +9519,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
8877
9519
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold("vibgrate.config.ts")}`);
8878
9520
  }
8879
9521
  if (opts.baseline) {
8880
- const { runBaseline } = await import('./baseline-IAFWF2ET.js');
9522
+ const { runBaseline } = await import('./baseline-AGX42TZM.js');
8881
9523
  await runBaseline(rootDir);
8882
9524
  }
8883
9525
  console.log("");
@@ -8980,7 +9622,7 @@ function collectPackageImports(graph, ecosystem, pkg) {
8980
9622
  };
8981
9623
  }
8982
9624
  async function firstReferenceLine(rootDir, relFile, identifier, readFile3) {
8983
- const content = await readFile3(path41.join(rootDir, relFile));
9625
+ const content = await readFile3(path43.join(rootDir, relFile));
8984
9626
  if (!content) return null;
8985
9627
  const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8986
9628
  const re = new RegExp(`\\b${escaped}\\b`);
@@ -9018,9 +9660,9 @@ function sitesFromImportFiles(files, limit = 10) {
9018
9660
  }
9019
9661
  async function defaultReadFile(absPath) {
9020
9662
  try {
9021
- const stat2 = await fs25.stat(absPath);
9663
+ const stat2 = await fs27.stat(absPath);
9022
9664
  if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
9023
- return await fs25.readFile(absPath, "utf8");
9665
+ return await fs27.readFile(absPath, "utf8");
9024
9666
  } catch {
9025
9667
  return null;
9026
9668
  }
@@ -9216,7 +9858,7 @@ var AI_ASSISTANT_DETECTORS = [
9216
9858
  async function detectAiAssistant(rootDir) {
9217
9859
  for (const detector of AI_ASSISTANT_DETECTORS) {
9218
9860
  for (const file of detector.files) {
9219
- if (await pathExists$1(path41.join(rootDir, file))) {
9861
+ if (await pathExists$1(path43.join(rootDir, file))) {
9220
9862
  return detector.name;
9221
9863
  }
9222
9864
  }
@@ -9410,18 +10052,31 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
9410
10052
  collectExcludes,
9411
10053
  []
9412
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) => {
9413
- const rootDir = path41.resolve(targetPath);
10055
+ const rootDir = path43.resolve(targetPath);
9414
10056
  if (!await pathExists$1(rootDir)) {
9415
10057
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
9416
10058
  process.exit(1);
9417
10059
  }
9418
10060
  const hasDsn = !!resolveDsn(opts.dsn);
9419
- const willPush = !opts.offline && (opts.push || hasDsn);
10061
+ let willPush = !opts.offline && (opts.push || hasDsn);
9420
10062
  const noLocalArtifacts = opts.localArtifacts === false;
9421
- 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"));
9422
10064
  let pinnedRegion;
9423
10065
  let planTier;
9424
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
+ };
9425
10080
  if (willPush && hasDsn) {
9426
10081
  const dsn = resolveDsn(opts.dsn);
9427
10082
  const parsed = parseDsn(dsn);
@@ -9433,65 +10088,56 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
9433
10088
  try {
9434
10089
  const preflight = await fetchScanPreflight(parsed, ingestHost, {
9435
10090
  repositoryName,
9436
- vcsSha: fingerprint.vcsSha
10091
+ vcsSha: fingerprint.vcsSha,
10092
+ // Canonical repo identity (credential-redacted by detectVcs) — the
10093
+ // server matches on this first, so re-scanning an already-mapped
10094
+ // repository under a different display name (e.g. a fresh clone in
10095
+ // a temp dir) is not miscounted as a NEW repo against the plan cap.
10096
+ remoteUrl: vcs.remoteUrl
9437
10097
  });
9438
10098
  pinnedRegion = preflight.region;
9439
10099
  planTier = preflight.plan?.tier;
9440
10100
  upgradeUrl = preflight.upgradeUrl ?? `https://${dashHostForIngestHost(preflight.ingestHost ?? ingestHost)}/${parsed.workspaceId}`;
9441
10101
  if (preflight.vm && !preflight.vm.allowed) {
9442
- console.error(chalk7.red(preflight.error ?? "VM meter usage exhausted"));
9443
- console.error(
9444
- chalk7.dim(
9445
- `VM minutes: ${preflight.vm.used}/${preflight.vm.limit} (${preflight.plan.label} plan) \u2014 enable overages or upgrade your plan.`
9446
- )
9447
- );
9448
- process.exit(1);
9449
- }
9450
- if (preflight.repositories && !preflight.repositories.allowed) {
9451
- console.error(
9452
- chalk7.red(
9453
- preflight.error ?? `Repository limit reached for the ${preflight.plan.label} plan \u2014 cannot scan a new repository.`
9454
- )
9455
- );
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) {
9456
10106
  const max = preflight.repositories.max < 0 ? "unlimited" : String(preflight.repositories.max);
9457
- console.error(
9458
- chalk7.dim(
9459
- `Repositories: ${preflight.repositories.total}/${max} (${preflight.plan.label} plan) \u2014 archive a repository or upgrade your plan.`
9460
- )
9461
- );
10107
+ const detail = [
10108
+ `Repositories: ${preflight.repositories.total}/${max} (${preflight.plan.label} plan) \u2014 archive a repository or upgrade your plan.`
10109
+ ];
9462
10110
  if (preflight.upgradeUrl) {
9463
- console.error(chalk7.dim(` Upgrade: ${preflight.upgradeUrl}`));
10111
+ detail.push(`Upgrade: ${preflight.upgradeUrl}`);
9464
10112
  }
9465
- process.exit(1);
9466
- }
9467
- if (preflight.status === "error" || !preflight.scans.allowed) {
9468
- console.error(chalk7.red(preflight.error ?? "Scan ingestion not allowed for this workspace."));
9469
- console.error(
9470
- chalk7.dim(
9471
- `Credits: ${preflight.scans.used}/${preflight.scans.limit} (${preflight.plan.label} plan)`
9472
- )
10113
+ blockPush(
10114
+ preflight.error ?? `Repository limit reached for the ${preflight.plan.label} plan \u2014 cannot upload a new repository.`,
10115
+ detail
9473
10116
  );
9474
- if (opts.strict) process.exit(1);
9475
- process.exit(1);
9476
- }
9477
- console.log(
9478
- chalk7.dim(
9479
- `Plan: ${preflight.plan.label} \u2014 scan credits ${preflight.scans.used}/${preflight.scans.limit} this month`
9480
- )
9481
- );
9482
- 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 {
9483
10122
  console.log(
9484
- 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
+ )
9485
10126
  );
9486
- if (preflight.repository.lastIngestId) {
9487
- emitIngestIdLine(preflight.repository.lastIngestId, { unchanged: true });
9488
- const dashUrl = `https://${dashHostForIngestHost(ingestHost)}/${parsed.workspaceId}/scan/${preflight.repository.lastIngestId}`;
9489
- console.log(chalk7.dim(` Latest report: ${dashUrl}`));
9490
- } else if (opts.strict) {
9491
- console.error(chalk7.red("Repository unchanged but no previous ingest id available."));
9492
- 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;
9493
10140
  }
9494
- return;
9495
10141
  }
9496
10142
  } catch (e) {
9497
10143
  const msg = e instanceof Error ? e.message : String(e);
@@ -9607,6 +10253,12 @@ Failing fitness function: drift worsened by ${worseningPercent.toFixed(2)}% (thr
9607
10253
  }
9608
10254
  if (willPush) {
9609
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
+ }
9610
10262
  }
9611
10263
  const showAiPrompt = scanOpts.format === "text" && !opts.quiet && !hasDsn && !opts.offline && !noLocalArtifacts && !opts.maxPrivacy && isFirstRun;
9612
10264
  if (showAiPrompt) {
@@ -9656,7 +10308,7 @@ var WATCHED_FILES = /* @__PURE__ */ new Set([
9656
10308
  "packages.lock.json"
9657
10309
  ]);
9658
10310
  var WATCHED_EXT = /\.(cs|fs)proj$/i;
9659
- var SKIP_DIRS2 = /* @__PURE__ */ new Set([
10311
+ var SKIP_DIRS3 = /* @__PURE__ */ new Set([
9660
10312
  "node_modules",
9661
10313
  ".git",
9662
10314
  "dist",
@@ -9677,7 +10329,7 @@ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
9677
10329
  function scanStaleness(rootDir, artifactPath) {
9678
10330
  let ref;
9679
10331
  try {
9680
- ref = fs11.statSync(artifactPath).mtimeMs;
10332
+ ref = fs12.statSync(artifactPath).mtimeMs;
9681
10333
  } catch {
9682
10334
  return { stale: false };
9683
10335
  }
@@ -9689,7 +10341,7 @@ function scanStaleness(rootDir, artifactPath) {
9689
10341
  if (depth > 8 || scanned > MAX_ENTRIES2) return;
9690
10342
  let entries;
9691
10343
  try {
9692
- entries = fs11.readdirSync(dir, { withFileTypes: true });
10344
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
9693
10345
  } catch {
9694
10346
  return;
9695
10347
  }
@@ -9697,20 +10349,20 @@ function scanStaleness(rootDir, artifactPath) {
9697
10349
  scanned++;
9698
10350
  if (scanned > MAX_ENTRIES2) break;
9699
10351
  if (e.isDirectory()) {
9700
- 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);
9701
10353
  continue;
9702
10354
  }
9703
10355
  if (!WATCHED_FILES.has(e.name) && !WATCHED_EXT.test(e.name)) continue;
9704
- const abs = path41.join(dir, e.name);
10356
+ const abs = path43.join(dir, e.name);
9705
10357
  let mtimeMs;
9706
10358
  try {
9707
- mtimeMs = fs11.statSync(abs).mtimeMs;
10359
+ mtimeMs = fs12.statSync(abs).mtimeMs;
9708
10360
  } catch {
9709
10361
  continue;
9710
10362
  }
9711
10363
  if (mtimeMs > newest) {
9712
10364
  newest = mtimeMs;
9713
- newestChanged = path41.relative(rootDir, abs) || e.name;
10365
+ newestChanged = path43.relative(rootDir, abs) || e.name;
9714
10366
  }
9715
10367
  }
9716
10368
  };
@@ -9774,7 +10426,7 @@ function extractContracts(content, pkg, ecosystem) {
9774
10426
  }
9775
10427
 
9776
10428
  // src/reporting/planning/usage.ts
9777
- var SKIP_DIRS3 = /* @__PURE__ */ new Set([
10429
+ var SKIP_DIRS4 = /* @__PURE__ */ new Set([
9778
10430
  "node_modules",
9779
10431
  ".git",
9780
10432
  "dist",
@@ -9841,7 +10493,7 @@ function analyzeTree(root2, packages) {
9841
10493
  if (depth > MAX_DEPTH || filesSeen >= MAX_FILES) return;
9842
10494
  let entries;
9843
10495
  try {
9844
- entries = fs11.readdirSync(dir, { withFileTypes: true });
10496
+ entries = fs12.readdirSync(dir, { withFileTypes: true });
9845
10497
  } catch {
9846
10498
  return;
9847
10499
  }
@@ -9849,18 +10501,18 @@ function analyzeTree(root2, packages) {
9849
10501
  for (const entry of entries) {
9850
10502
  if (filesSeen >= MAX_FILES) return;
9851
10503
  if (entry.isDirectory()) {
9852
- if (SKIP_DIRS3.has(entry.name) || entry.name.startsWith(".")) continue;
9853
- 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);
9854
10506
  continue;
9855
10507
  }
9856
- const fileEco = EXT_ECOSYSTEM[path41.extname(entry.name)];
10508
+ const fileEco = EXT_ECOSYSTEM[path43.extname(entry.name)];
9857
10509
  if (!fileEco || fileEco === "unknown") continue;
9858
10510
  filesSeen++;
9859
- const full = path41.join(dir, entry.name);
10511
+ const full = path43.join(dir, entry.name);
9860
10512
  let content;
9861
10513
  try {
9862
- if (fs11.statSync(full).size > MAX_FILE_BYTES2) continue;
9863
- content = fs11.readFileSync(full, "utf8");
10514
+ if (fs12.statSync(full).size > MAX_FILE_BYTES2) continue;
10515
+ content = fs12.readFileSync(full, "utf8");
9864
10516
  } catch {
9865
10517
  continue;
9866
10518
  }
@@ -10171,7 +10823,7 @@ function applyPlan(rootDir, upgrades, opts = {}) {
10171
10823
  }
10172
10824
  const outcomes = effective.map((t) => {
10173
10825
  const c2 = pmCommandFor(u.ecosystem, u.package, u.to, opts.packageManager, { workspaceRoot: t.isWorkspaceRoot });
10174
- return { t, res: run(c2, path41.join(rootDir, t.dir)) };
10826
+ return { t, res: run(c2, path43.join(rootDir, t.dir)) };
10175
10827
  });
10176
10828
  const failures = outcomes.filter((o) => !o.res.ok);
10177
10829
  if (failures.length === 0) {
@@ -10200,8 +10852,8 @@ function applyPlan(rootDir, upgrades, opts = {}) {
10200
10852
  return results;
10201
10853
  }
10202
10854
  var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
10203
- var CACHE_DIR = path41.join(os.homedir(), ".vibgrate");
10204
- 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");
10205
10857
  async function fetchLatestVersion() {
10206
10858
  try {
10207
10859
  const controller = new AbortController();
@@ -10228,8 +10880,8 @@ async function fetchLatestVersion() {
10228
10880
  }
10229
10881
  async function writeCache(data) {
10230
10882
  try {
10231
- await fs25.mkdir(CACHE_DIR, { recursive: true });
10232
- 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");
10233
10885
  } catch {
10234
10886
  }
10235
10887
  }
@@ -10264,10 +10916,10 @@ function buildDeferredUpdateScript(opts) {
10264
10916
  }
10265
10917
  function scheduleDeferredUpdate(command, pid = process.pid, dir = os.tmpdir()) {
10266
10918
  const stamp = `${pid}-${process.hrtime.bigint().toString(36)}`;
10267
- const scriptPath = path41.join(dir, `vg-update-${stamp}.cmd`);
10268
- 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`);
10269
10921
  try {
10270
- fs11.writeFileSync(scriptPath, buildDeferredUpdateScript({ pid, command, logPath }), "utf8");
10922
+ fs12.writeFileSync(scriptPath, buildDeferredUpdateScript({ pid, command, logPath }), "utf8");
10271
10923
  const child = spawn(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", scriptPath], {
10272
10924
  detached: true,
10273
10925
  stdio: "ignore",
@@ -10286,11 +10938,12 @@ var SCRIPT_PACKAGES = [PACKAGE_NAME, "onnxruntime-node", "msgpackr-extract"];
10286
10938
  function allowScriptsFlag(pm) {
10287
10939
  return pm === "npm" ? ` --allow-scripts=${SCRIPT_PACKAGES.join(",")}` : "";
10288
10940
  }
10941
+ var ORT_INSTALL_SKIP_ENV = { ONNXRUNTIME_NODE_INSTALL: "skip" };
10289
10942
  function detectGlobalInstall(execPath = process.argv[1] || "", cwd = process.cwd()) {
10290
10943
  if (!execPath) return null;
10291
10944
  let resolved = execPath;
10292
10945
  try {
10293
- resolved = fs11.realpathSync(execPath);
10946
+ resolved = fs12.realpathSync(execPath);
10294
10947
  } catch {
10295
10948
  }
10296
10949
  const p = resolved.replace(/\\/g, "/");
@@ -10320,14 +10973,14 @@ async function findGlobalInstall(pkg = PACKAGE_NAME, run = defaultRunner) {
10320
10973
  pm: "yarn",
10321
10974
  root: () => {
10322
10975
  const dir = tryRun("yarn global dir");
10323
- return dir ? path41.join(dir, "node_modules") : null;
10976
+ return dir ? path43.join(dir, "node_modules") : null;
10324
10977
  }
10325
10978
  },
10326
- { 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") }
10327
10980
  ];
10328
10981
  for (const probe of probes) {
10329
10982
  const root2 = probe.root();
10330
- if (root2 && await pathExists(path41.join(root2, pkg))) return probe.pm;
10983
+ if (root2 && await pathExists(path43.join(root2, pkg))) return probe.pm;
10331
10984
  }
10332
10985
  return null;
10333
10986
  }
@@ -10342,19 +10995,19 @@ function getGlobalUpdateCommand(pm, pkg, version) {
10342
10995
  return `bun add -g ${spec}`;
10343
10996
  case "npm":
10344
10997
  default:
10345
- return `npm install -g${allowScriptsFlag("npm")} ${spec}`;
10998
+ return `npm install -g --no-fund${allowScriptsFlag("npm")} ${spec}`;
10346
10999
  }
10347
11000
  }
10348
11001
  async function detectPackageManager(cwd) {
10349
- if (await pathExists(path41.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10350
- if (await pathExists(path41.join(cwd, "bun.lockb"))) return "bun";
10351
- 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";
10352
11005
  return "npm";
10353
11006
  }
10354
11007
  async function detectWorkspaceRoot(cwd) {
10355
- if (await pathExists(path41.join(cwd, "pnpm-workspace.yaml"))) return true;
11008
+ if (await pathExists(path43.join(cwd, "pnpm-workspace.yaml"))) return true;
10356
11009
  try {
10357
- const pkgPath = path41.join(cwd, "package.json");
11010
+ const pkgPath = path43.join(cwd, "package.json");
10358
11011
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
10359
11012
  const pkg = JSON.parse(raw);
10360
11013
  return pkg.workspaces != null;
@@ -10375,13 +11028,13 @@ function getInstallCommand(pm, pkg, version, isDev, opts = {}) {
10375
11028
  case "npm":
10376
11029
  default: {
10377
11030
  const allow = allowScriptsFlag("npm");
10378
- 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}`;
10379
11032
  }
10380
11033
  }
10381
11034
  }
10382
11035
  async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
10383
11036
  try {
10384
- const pkgPath = path41.join(cwd, "package.json");
11037
+ const pkgPath = path43.join(cwd, "package.json");
10385
11038
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
10386
11039
  const parsed = JSON.parse(raw);
10387
11040
  if (parsed.devDependencies?.[pkg]) return "dev";
@@ -10396,19 +11049,24 @@ async function confirmWorkspaceRoot(pm) {
10396
11049
  async function confirm3(question) {
10397
11050
  if (!(process.stdin.isTTY && process.stdout.isTTY)) return false;
10398
11051
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10399
- return new Promise((resolve21) => {
11052
+ return new Promise((resolve23) => {
10400
11053
  rl.question(chalk7.yellow(question), (ans) => {
10401
11054
  rl.close();
10402
11055
  const t = ans.trim().toLowerCase();
10403
- resolve21(t === "y" || t === "yes");
11056
+ resolve23(t === "y" || t === "yes");
10404
11057
  });
10405
11058
  });
10406
11059
  }
10407
11060
  var CAPTURED_OUTPUT_LIMIT = 64e3;
10408
11061
  async function runInstall(cmd, cwd) {
10409
11062
  const { spawn: spawn5 } = await import('child_process');
10410
- return new Promise((resolve21) => {
10411
- 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
+ });
10412
11070
  let output = "";
10413
11071
  const tee = (src, dest) => {
10414
11072
  if (!src) return;
@@ -10421,15 +11079,15 @@ async function runInstall(cmd, cwd) {
10421
11079
  };
10422
11080
  tee(child.stdout, process.stdout);
10423
11081
  tee(child.stderr, process.stderr);
10424
- child.on("error", (err) => resolve21({ ok: false, output: `${output}
11082
+ child.on("error", (err) => resolve23({ ok: false, output: `${output}
10425
11083
  ${String(err)}` }));
10426
- child.on("close", (code) => resolve21({ ok: code === 0, output }));
11084
+ child.on("close", (code) => resolve23({ ok: code === 0, output }));
10427
11085
  });
10428
11086
  }
10429
11087
  async function releaseWindowsFileLocks(cwd, keepVersion) {
10430
11088
  reapAndReport(cwd, keepVersion);
10431
11089
  try {
10432
- const { vgdSocketPath: vgdSocketPath2 } = await import('./vgd-LFHQ4GWC.js');
11090
+ const { vgdSocketPath: vgdSocketPath2 } = await import('./vgd-UIFH5TTW.js');
10433
11091
  const result = await stopVgd(vgdSocketPath2());
10434
11092
  if (result === "stopped") {
10435
11093
  console.log(chalk7.dim("Stopped the vgd daemon so its files can be replaced \u2014 it restarts on the next command."));
@@ -10554,7 +11212,7 @@ var updateCommand = new Command("update").description("Update vibgrate to the la
10554
11212
  );
10555
11213
  async function rewarmVgdAndReport(cwd) {
10556
11214
  try {
10557
- const { vgdIsRunning: vgdIsRunning2, vgdRequest: vgdRequest2 } = await import('./vgd-LFHQ4GWC.js');
11215
+ const { vgdIsRunning: vgdIsRunning2, vgdRequest: vgdRequest2 } = await import('./vgd-UIFH5TTW.js');
10558
11216
  if (!await vgdIsRunning2()) return;
10559
11217
  const loaded = await vgdRequest2({ op: "load-graph", root: cwd });
10560
11218
  if (!loaded.ok || !("repositoryId" in loaded)) return;
@@ -10643,13 +11301,13 @@ function collectCandidates(artifact) {
10643
11301
  return out2;
10644
11302
  }
10645
11303
  var defaultFixScanner = async (rootDir) => {
10646
- 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`);
10647
11305
  const scanOpts = { vibgrateVersion: VERSION, format: "json", out: scratch, quiet: true, concurrency: 8 };
10648
11306
  const advanced = await loadAdvancedScanHook();
10649
11307
  return runCoreScan(rootDir, scanOpts, advanced);
10650
11308
  };
10651
11309
  async function loadArtifact(rootDir, inFile, scan = defaultFixScanner) {
10652
- const artifactPath = path41.isAbsolute(inFile) ? inFile : path41.join(rootDir, inFile);
11310
+ const artifactPath = path43.isAbsolute(inFile) ? inFile : path43.join(rootDir, inFile);
10653
11311
  if (await pathExists(artifactPath)) {
10654
11312
  const staleness = scanStaleness(rootDir, artifactPath);
10655
11313
  if (!staleness.stale) {
@@ -10675,8 +11333,8 @@ async function repositoryIdentity(rootDir, override) {
10675
11333
  return { name: override?.trim() || void 0 };
10676
11334
  }
10677
11335
  }
10678
- 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", "Show what would change without applying").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) => {
10679
- const rootDir = path41.resolve(targetPath);
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) => {
11337
+ const rootDir = path43.resolve(targetPath);
10680
11338
  if (!await pathExists(rootDir)) {
10681
11339
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
10682
11340
  process.exit(1);
@@ -10837,7 +11495,7 @@ function emit(report, format) {
10837
11495
  }
10838
11496
  }
10839
11497
  function relProjectDir(rootDir, projectPath) {
10840
- const rel = path41.isAbsolute(projectPath) ? path41.relative(rootDir, projectPath) : projectPath;
11498
+ const rel = path43.isAbsolute(projectPath) ? path43.relative(rootDir, projectPath) : projectPath;
10841
11499
  return rel === "" ? "." : rel;
10842
11500
  }
10843
11501
  async function buildTargetResolver(rootDir, artifact) {
@@ -10878,14 +11536,14 @@ function promptPlanSelection(response) {
10878
11536
  const defaultIdx = plans.findIndex((p) => p.tier === response.recommended);
10879
11537
  const def = defaultIdx >= 0 ? defaultIdx + 1 : 1;
10880
11538
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
10881
- return new Promise((resolve21) => {
11539
+ return new Promise((resolve23) => {
10882
11540
  rl.question(`Plan [1-${plans.length}, default ${def}, q to cancel]: `, (ans) => {
10883
11541
  rl.close();
10884
11542
  const t = ans.trim().toLowerCase();
10885
- if (t === "q" || t === "quit") return resolve21(null);
11543
+ if (t === "q" || t === "quit") return resolve23(null);
10886
11544
  const n = t === "" ? def : Number.parseInt(t, 10);
10887
- if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve21(null);
10888
- resolve21(plans[n - 1].tier);
11545
+ if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve23(null);
11546
+ resolve23(plans[n - 1].tier);
10889
11547
  });
10890
11548
  });
10891
11549
  }
@@ -10905,8 +11563,16 @@ async function runApplyFlow(rootDir, artifact, response, opts, canonicalTier) {
10905
11563
  }
10906
11564
  } else if (nonEmpty.length === 1) {
10907
11565
  chosen = nonEmpty[0];
10908
- } else if (opts.yes) {
11566
+ } else if (opts.yes || opts.dryRun) {
10909
11567
  chosen = response.plans.find((p) => p.tier === response.recommended) ?? nonEmpty[0];
11568
+ if (opts.dryRun && !opts.yes && nonEmpty.length > 1) {
11569
+ console.log(
11570
+ chalk7.dim(
11571
+ `
11572
+ Dry-run previews the recommended (${chosen.tier}) plan \u2014 nothing will be written. Pass --plan <safe|balanced|aggressive> to preview another tier.`
11573
+ )
11574
+ );
11575
+ }
10910
11576
  } else if (process.stdin.isTTY && process.stdout.isTTY) {
10911
11577
  const tier = await promptPlanSelection(response);
10912
11578
  if (!tier) {
@@ -10915,7 +11581,7 @@ async function runApplyFlow(rootDir, artifact, response, opts, canonicalTier) {
10915
11581
  }
10916
11582
  chosen = response.plans.find((p) => p.tier === tier);
10917
11583
  } else {
10918
- console.log(chalk7.dim("\nMultiple plans available \u2014 re-run with --plan <tier> or --yes to apply, or --dry-run to preview."));
11584
+ console.log(chalk7.dim("\nMultiple plans available \u2014 re-run with --plan <tier> or --yes to apply, or --dry-run to preview the recommended plan."));
10919
11585
  return;
10920
11586
  }
10921
11587
  if (!chosen || chosen.upgrades.length === 0) {
@@ -11672,7 +12338,7 @@ function formatMarkdown(artifact) {
11672
12338
 
11673
12339
  // src/reporting/commands/report.ts
11674
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) => {
11675
- const artifactPath = path41.resolve(opts.in);
12341
+ const artifactPath = path43.resolve(opts.in);
11676
12342
  if (!await pathExists(artifactPath)) {
11677
12343
  console.error(chalk7.red(`Artifact not found: ${artifactPath}`));
11678
12344
  console.error(chalk7.dim('Run "vibgrate scan" first to generate a scan artifact.'));
@@ -11719,10 +12385,10 @@ function openUrl(url) {
11719
12385
  }
11720
12386
 
11721
12387
  // src/reporting/commands/login.ts
11722
- var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
12388
+ var delay = (ms) => new Promise((resolve23) => setTimeout(resolve23, ms));
11723
12389
  function isInside(dir, file) {
11724
- const rel = path41.relative(dir, file);
11725
- return !!rel && !rel.startsWith("..") && !path41.isAbsolute(rel);
12390
+ const rel = path43.relative(dir, file);
12391
+ return !!rel && !rel.startsWith("..") && !path43.isAbsolute(rel);
11726
12392
  }
11727
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(
11728
12394
  "--local",
@@ -11977,7 +12643,7 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
11977
12643
  try {
11978
12644
  const statements = [];
11979
12645
  if (opts.from) {
11980
- const fromPath = path41.resolve(opts.from);
12646
+ const fromPath = path43.resolve(opts.from);
11981
12647
  if (!await pathExists(fromPath)) {
11982
12648
  process.stderr.write(chalk7.red(`Statements file not found: ${fromPath}
11983
12649
  `));
@@ -11995,9 +12661,9 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
11995
12661
  });
11996
12662
  const json2 = JSON.stringify(doc, null, 2);
11997
12663
  if (opts.out) {
11998
- await writeTextFile(path41.resolve(opts.out), json2 + "\n");
12664
+ await writeTextFile(path43.resolve(opts.out), json2 + "\n");
11999
12665
  process.stderr.write(
12000
- 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)}
12001
12667
  `
12002
12668
  );
12003
12669
  } else {
@@ -12180,7 +12846,7 @@ function formatDeltaText(base, current) {
12180
12846
  return lines.join("\n");
12181
12847
  }
12182
12848
  async function readArtifactOrExit(filePath) {
12183
- const absolutePath = path41.resolve(filePath);
12849
+ const absolutePath = path43.resolve(filePath);
12184
12850
  if (!await pathExists(absolutePath)) {
12185
12851
  console.error(chalk7.red(`Artifact not found: ${absolutePath}`));
12186
12852
  process.exit(1);
@@ -12197,7 +12863,7 @@ var exportCommand = new Command("export").description("Export scan artifact as S
12197
12863
  const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
12198
12864
  const body = JSON.stringify(sbom, null, 2);
12199
12865
  if (opts.out) {
12200
- await writeTextFile(path41.resolve(opts.out), body);
12866
+ await writeTextFile(path43.resolve(opts.out), body);
12201
12867
  console.log(chalk7.green("\u2714") + ` SBOM written to ${opts.out}`);
12202
12868
  } else {
12203
12869
  console.log(body);
@@ -12208,7 +12874,7 @@ var deltaCommand = new Command("delta").description("Show SBOM delta between two
12208
12874
  const current = await readArtifactOrExit(opts.to);
12209
12875
  const report = formatDeltaText(base, current);
12210
12876
  if (opts.out) {
12211
- await writeTextFile(path41.resolve(opts.out), report);
12877
+ await writeTextFile(path43.resolve(opts.out), report);
12212
12878
  console.log(chalk7.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
12213
12879
  } else {
12214
12880
  console.log(report);
@@ -12339,20 +13005,20 @@ function resolveRegime(id) {
12339
13005
  return regime;
12340
13006
  }
12341
13007
  function evidenceDir(root2) {
12342
- return path41.join(root2, ".vibgrate", "evidence");
13008
+ return path43.join(root2, ".vibgrate", "evidence");
12343
13009
  }
12344
13010
  function orgPath(root2) {
12345
- return path41.join(evidenceDir(root2), "org.json");
13011
+ return path43.join(evidenceDir(root2), "org.json");
12346
13012
  }
12347
13013
  function productsPath(root2) {
12348
- return path41.join(evidenceDir(root2), "products.json");
13014
+ return path43.join(evidenceDir(root2), "products.json");
12349
13015
  }
12350
13016
  function releasesDir(root2) {
12351
- return path41.join(evidenceDir(root2), "releases");
13017
+ return path43.join(evidenceDir(root2), "releases");
12352
13018
  }
12353
13019
  function releasePath(root2, productId, version) {
12354
13020
  const safe = `${productId}@${version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
12355
- return path41.join(releasesDir(root2), `${safe}.json`);
13021
+ return path43.join(releasesDir(root2), `${safe}.json`);
12356
13022
  }
12357
13023
  var DEFAULT_ORG = {
12358
13024
  responsiblePersons: [],
@@ -12383,7 +13049,7 @@ async function freezeRelease(root2, release) {
12383
13049
  const p = releasePath(root2, release.productId, release.version);
12384
13050
  if (await pathExists(p)) {
12385
13051
  throw new CliError(
12386
- `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`,
12387
13053
  ExitCode.USAGE_ERROR
12388
13054
  );
12389
13055
  }
@@ -12397,7 +13063,7 @@ async function loadReleases(root2, productId) {
12397
13063
  const files = (await readdir(dir)).filter((f) => f.endsWith(".json")).sort();
12398
13064
  const releases = [];
12399
13065
  for (const f of files) {
12400
- const rel = await readJsonFile(path41.join(dir, f));
13066
+ const rel = await readJsonFile(path43.join(dir, f));
12401
13067
  if (!productId || rel.productId === productId) releases.push(rel);
12402
13068
  }
12403
13069
  return releases;
@@ -13092,19 +13758,19 @@ function verifyEvidenceEnvelope(env, opts = {}) {
13092
13758
  var DEFAULT_KEY = "attest-key.pem";
13093
13759
  function resolveSigningKey(root2, explicit) {
13094
13760
  const chosen = process.env.VG_ATTEST_KEY;
13095
- 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);
13096
13762
  let minted = false;
13097
- if (!fs11.existsSync(keyPath)) {
13763
+ if (!fs12.existsSync(keyPath)) {
13098
13764
  if (chosen) throw new CliError(`signing key not found: ${chosen}`, ExitCode.USAGE_ERROR);
13099
13765
  const kp = generateKeypair();
13100
- fs11.mkdirSync(path41.dirname(keyPath), { recursive: true });
13101
- fs11.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
13102
- 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);
13103
13769
  minted = true;
13104
13770
  }
13105
13771
  let key2;
13106
13772
  try {
13107
- key2 = crypto3.createPrivateKey(fs11.readFileSync(keyPath, "utf8"));
13773
+ key2 = crypto3.createPrivateKey(fs12.readFileSync(keyPath, "utf8"));
13108
13774
  } catch {
13109
13775
  throw new CliError(`could not read an Ed25519 private key from ${keyPath}`, ExitCode.USAGE_ERROR);
13110
13776
  }
@@ -13115,16 +13781,16 @@ function resolveSigningKey(root2, explicit) {
13115
13781
  }
13116
13782
  function writeBundle(input) {
13117
13783
  const dir = input.outDir;
13118
- fs11.mkdirSync(path41.join(dir, "inputs", "releases"), { recursive: true });
13119
- 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)}
13120
13786
  `);
13121
13787
  write("result.json", input.result);
13122
- write(path41.join("inputs", "advisory.json"), input.advisory);
13788
+ write(path43.join("inputs", "advisory.json"), input.advisory);
13123
13789
  for (const rel of input.releases) {
13124
13790
  const safe = `${rel.productId}@${rel.version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
13125
- write(path41.join("inputs", "releases", `${safe}.json`), rel);
13791
+ write(path43.join("inputs", "releases", `${safe}.json`), rel);
13126
13792
  }
13127
- 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 });
13128
13794
  write("provenance.json", {
13129
13795
  method: "deterministic",
13130
13796
  modelDrafted: [],
@@ -13140,13 +13806,13 @@ function writeBundle(input) {
13140
13806
  disclaimer: input.regime.disclaimer
13141
13807
  });
13142
13808
  if (input.envelope) {
13143
- 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)}
13144
13810
  `);
13145
13811
  }
13146
13812
  if (input.timestampToken) {
13147
- fs11.writeFileSync(path41.join(dir, "timestamp.tsr"), input.timestampToken);
13813
+ fs12.writeFileSync(path43.join(dir, "timestamp.tsr"), input.timestampToken);
13148
13814
  }
13149
- fs11.writeFileSync(path41.join(dir, "VERIFY.md"), verifyDoc(input));
13815
+ fs12.writeFileSync(path43.join(dir, "VERIFY.md"), verifyDoc(input));
13150
13816
  return dir;
13151
13817
  }
13152
13818
  function verifyDoc(input) {
@@ -13207,13 +13873,13 @@ function undeterminedFields(result, regime) {
13207
13873
  return gaps.filter((g) => regime.submission.requires.some((r) => g.startsWith(r)) || g.startsWith("exposure") || g.startsWith("member"));
13208
13874
  }
13209
13875
  async function recordDrill(root2, record) {
13210
- const dir = path41.join(evidenceDir(root2), "drills");
13211
- 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`);
13212
13878
  await writeJsonFile(p, record);
13213
13879
  return p;
13214
13880
  }
13215
13881
  async function hasRecentDrill(root2, asOf) {
13216
- const dir = path41.join(evidenceDir(root2), "drills");
13882
+ const dir = path43.join(evidenceDir(root2), "drills");
13217
13883
  if (!await pathExists(dir)) return void 0;
13218
13884
  const { readdir } = await import('fs/promises');
13219
13885
  const { readJsonFile: readJsonFile2 } = await import('./fs-4G5A65KS.js');
@@ -13221,7 +13887,7 @@ async function hasRecentDrill(root2, asOf) {
13221
13887
  if (files.length === 0) return void 0;
13222
13888
  const cutoff = new Date(new Date(asOf).getTime() - 90 * 24 * 3600 * 1e3).toISOString();
13223
13889
  for (const f of files) {
13224
- const rec = await readJsonFile2(path41.join(dir, f));
13890
+ const rec = await readJsonFile2(path43.join(dir, f));
13225
13891
  if (rec.ranAt >= cutoff) return true;
13226
13892
  }
13227
13893
  return false;
@@ -13301,7 +13967,7 @@ function formatRegimeList() {
13301
13967
 
13302
13968
  // src/reporting/commands/evidence/index.ts
13303
13969
  function root(opts) {
13304
- return path41.resolve(opts.cwd ?? process.cwd());
13970
+ return path43.resolve(opts.cwd ?? process.cwd());
13305
13971
  }
13306
13972
  function slug(name) {
13307
13973
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "product";
@@ -13389,7 +14055,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
13389
14055
  const release = await buildRelease({
13390
14056
  productId: product.id,
13391
14057
  version,
13392
- from: path41.resolve(rootDir, opts.from),
14058
+ from: path43.resolve(rootDir, opts.from),
13393
14059
  shipDate: opts.shipDate,
13394
14060
  buildId: opts.buildId,
13395
14061
  artefactDigest: opts.digest,
@@ -13397,7 +14063,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
13397
14063
  frozenAt: nowIso()
13398
14064
  });
13399
14065
  const p = await freezeRelease(rootDir, release);
13400
- 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)}`);
13401
14067
  });
13402
14068
  async function runExposure(rootDir, vuln, opts) {
13403
14069
  const org = await loadOrg(rootDir);
@@ -13449,7 +14115,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
13449
14115
  console.log("\n" + buildPack(result, regime, org, stage));
13450
14116
  }
13451
14117
  if (opts.bundle) {
13452
- const dir = path41.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
14118
+ const dir = path43.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
13453
14119
  let envelope;
13454
14120
  if (opts.sign !== false) {
13455
14121
  const { key: key2, minted } = resolveSigningKey(rootDir);
@@ -13457,7 +14123,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
13457
14123
  envelope = signEvidenceStatement(buildEvidenceStatement(result, VERSION), key2);
13458
14124
  }
13459
14125
  writeBundle({ outDir: dir, result, advisory, releases, regime, envelope, timestampToken, cliVersion: VERSION });
13460
- 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" : ""}`);
13461
14127
  }
13462
14128
  process.exitCode = exposureExit(result.overallStatus);
13463
14129
  });
@@ -13489,7 +14155,7 @@ var packCmd = new Command("pack").description("Build the submission pack a human
13489
14155
  const stage = opts.stage ?? regime.clocks[0]?.stage ?? "early-warning";
13490
14156
  const md = buildPack(result, regime, org, stage);
13491
14157
  if (opts.out) {
13492
- fs11.writeFileSync(path41.resolve(rootDir, opts.out), md);
14158
+ fs12.writeFileSync(path43.resolve(rootDir, opts.out), md);
13493
14159
  console.error(chalk7.green("\u2714") + ` pack written to ${opts.out}`);
13494
14160
  } else {
13495
14161
  console.log(md);
@@ -13531,20 +14197,20 @@ var drillCmd = new Command("drill").description("Timed dry-run of the determinat
13531
14197
  }
13532
14198
  });
13533
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) => {
13534
- const abs = path41.resolve(bundlePath);
13535
- const envPath = fs11.statSync(abs).isDirectory() ? path41.join(abs, "evidence.intoto.jsonl") : abs;
13536
- if (!fs11.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
13537
- const envelope = JSON.parse(fs11.readFileSync(envPath, "utf8").trim().split("\n")[0]);
13538
- const resultPath = path41.join(path41.dirname(envPath), "result.json");
13539
- const result = fs11.existsSync(resultPath) ? JSON.parse(fs11.readFileSync(resultPath, "utf8")) : void 0;
13540
- 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;
13541
14207
  const v = verifyEvidenceEnvelope(envelope, { publicKeyPem, result });
13542
14208
  const color = v.status === "verified" ? chalk7.green : v.status === "failed" ? chalk7.red : chalk7.yellow;
13543
14209
  console.log(" " + color(v.status.toUpperCase()) + ` ${v.reason}`);
13544
14210
  if (v.evidenceId) console.log(" " + chalk7.dim(`evidence ${v.evidenceId} \xB7 regime ${v.regime} \xB7 advisory ${v.advisoryId} \xB7 ${v.overallStatus}`));
13545
- const tsrPath = path41.join(path41.dirname(envPath), "timestamp.tsr");
13546
- if (fs11.existsSync(tsrPath) && result) {
13547
- 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));
13548
14214
  const tcolor = t.imprintMatches ? chalk7.green : chalk7.red;
13549
14215
  console.log(" " + tcolor("TIMESTAMP") + ` ${t.reason}`);
13550
14216
  }
@@ -13611,12 +14277,12 @@ var exportCmd = new Command("export").description("Air-gap bundle of all evidenc
13611
14277
  const releases = [];
13612
14278
  for (const list of releasesByProduct.values()) releases.push(...list);
13613
14279
  const report = computeReadiness({ regime, org, products, releasesByProduct, recentDrill: await hasRecentDrill(rootDir, today()) });
13614
- const dir = path41.resolve(rootDir, opts.out);
13615
- await writeJsonFile(path41.join(dir, "org.json"), org);
13616
- await writeJsonFile(path41.join(dir, "products.json"), products);
13617
- for (const r of releases) await writeJsonFile(path41.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
13618
- await writeJsonFile(path41.join(dir, "readiness.json"), report);
13619
- 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)`);
13620
14286
  });
13621
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) => {
13622
14288
  const rootDir = root(opts);
@@ -13642,10 +14308,10 @@ var pushCmd = new Command("push").description("Push the product registry (and an
13642
14308
  }));
13643
14309
  let exposure;
13644
14310
  if (opts.result) {
13645
- const raw = path41.resolve(rootDir, opts.result);
13646
- const resultPath = fs11.existsSync(raw) && fs11.statSync(raw).isDirectory() ? path41.join(raw, "result.json") : raw;
13647
- if (!fs11.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
13648
- 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"));
13649
14315
  }
13650
14316
  const payload = { schemaVersion: "evidence-push-1", regime: regime.id, generatedAt: nowIso(), signed: Boolean(opts.signed), products: productPayload, exposure };
13651
14317
  const body = JSON.stringify(payload);
@@ -13707,6 +14373,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
13707
14373
  "daemon",
13708
14374
  "policy",
13709
14375
  "llm-host",
14376
+ "hcs",
13710
14377
  "install",
13711
14378
  "uninstall",
13712
14379
  "share",
@@ -13771,6 +14438,7 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
13771
14438
  registerDaemon(program);
13772
14439
  registerPolicy(program);
13773
14440
  registerLlmHost(program);
14441
+ registerHcs(program);
13774
14442
  program.addCommand(initCommand);
13775
14443
  program.addCommand(scanCommand);
13776
14444
  program.addCommand(fixCommand);
@@ -13839,7 +14507,7 @@ function dispatch(argv, cwd) {
13839
14507
  }
13840
14508
  const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
13841
14509
  if (looksLikeQuestion) return ["ask", ...args];
13842
- if (fs11.existsSync(path41.resolve(cwd, first))) {
14510
+ if (fs12.existsSync(path43.resolve(cwd, first))) {
13843
14511
  return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
13844
14512
  }
13845
14513
  const moved = MOVED_COMMANDS[first];
@@ -13884,9 +14552,9 @@ async function main(argv = process.argv) {
13884
14552
  }
13885
14553
  function readCwd(raw) {
13886
14554
  const i = raw.findIndex((a) => a === "-C" || a === "--cwd");
13887
- 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]);
13888
14556
  const eq = raw.find((a) => a.startsWith("--cwd="));
13889
- if (eq) return path41.resolve(eq.slice("--cwd=".length));
14557
+ if (eq) return path43.resolve(eq.slice("--cwd=".length));
13890
14558
  return process.cwd();
13891
14559
  }
13892
14560
  function handleError(err) {