@vibgrate/cli 2026.801.1 → 2026.803.3

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 (110) hide show
  1. package/dist/agent-JTA4YWMQ.js +24 -0
  2. package/dist/{agent-4DAECASW.js.map → agent-JTA4YWMQ.js.map} +1 -1
  3. package/dist/baseline-2V7PKA7Q.js +9 -0
  4. package/dist/{baseline-4BDH4F2W.js.map → baseline-2V7PKA7Q.js.map} +1 -1
  5. package/dist/{chunk-76TDXGGF.js → chunk-3Q3ZXJZP.js} +218 -51
  6. package/dist/chunk-3Q3ZXJZP.js.map +1 -0
  7. package/dist/{chunk-G7W4MFPZ.js → chunk-4ACXDVON.js} +4 -4
  8. package/dist/{chunk-G7W4MFPZ.js.map → chunk-4ACXDVON.js.map} +1 -1
  9. package/dist/{chunk-E6H2F2XF.js → chunk-6DFV4WCQ.js} +3 -3
  10. package/dist/{chunk-E6H2F2XF.js.map → chunk-6DFV4WCQ.js.map} +1 -1
  11. package/dist/{chunk-FF5ZQ6KI.js → chunk-6JP7HGIF.js} +4 -4
  12. package/dist/{chunk-FF5ZQ6KI.js.map → chunk-6JP7HGIF.js.map} +1 -1
  13. package/dist/chunk-7KNFG44U.js +6 -0
  14. package/dist/{chunk-TGDHOAXX.js.map → chunk-7KNFG44U.js.map} +1 -1
  15. package/dist/{chunk-T6DRYOMT.js → chunk-CPLG4GFB.js} +4 -4
  16. package/dist/{chunk-T6DRYOMT.js.map → chunk-CPLG4GFB.js.map} +1 -1
  17. package/dist/{chunk-SDG242R4.js → chunk-HC44772H.js} +132 -365
  18. package/dist/chunk-HC44772H.js.map +1 -0
  19. package/dist/{chunk-MPP4S4OE.js → chunk-K6Q6HTFD.js} +32 -11
  20. package/dist/chunk-K6Q6HTFD.js.map +1 -0
  21. package/dist/{chunk-7G5S5KZN.js → chunk-KUZLILN3.js} +16 -3
  22. package/dist/chunk-KUZLILN3.js.map +1 -0
  23. package/dist/{chunk-XEJJGDGX.js → chunk-KYX2YCXT.js} +134 -9
  24. package/dist/chunk-KYX2YCXT.js.map +1 -0
  25. package/dist/{chunk-V2QK3IUY.js → chunk-L5PUNO3T.js} +4 -4
  26. package/dist/{chunk-V2QK3IUY.js.map → chunk-L5PUNO3T.js.map} +1 -1
  27. package/dist/{chunk-7PVCHLR2.js → chunk-M452MRWI.js} +109 -10
  28. package/dist/chunk-M452MRWI.js.map +1 -0
  29. package/dist/{chunk-WIDZ5IE7.js → chunk-M7773OUN.js} +14 -7
  30. package/dist/chunk-M7773OUN.js.map +1 -0
  31. package/dist/{chunk-XRN7DQGR.js → chunk-NJFQCDGA.js} +3 -3
  32. package/dist/{chunk-XRN7DQGR.js.map → chunk-NJFQCDGA.js.map} +1 -1
  33. package/dist/{chunk-BNEHDLVZ.js → chunk-NSWEJPLV.js} +129 -20
  34. package/dist/chunk-NSWEJPLV.js.map +1 -0
  35. package/dist/{chunk-JLWI2JGA.js → chunk-NUZM7UOR.js} +117 -6
  36. package/dist/chunk-NUZM7UOR.js.map +1 -0
  37. package/dist/{chunk-B3OMGYZZ.js → chunk-PXM3VZYR.js} +4 -4
  38. package/dist/{chunk-B3OMGYZZ.js.map → chunk-PXM3VZYR.js.map} +1 -1
  39. package/dist/chunk-QMME6TB4.js +457 -0
  40. package/dist/chunk-QMME6TB4.js.map +1 -0
  41. package/dist/{chunk-G25STLE7.js → chunk-SJFBXCII.js} +30 -3
  42. package/dist/chunk-SJFBXCII.js.map +1 -0
  43. package/dist/{chunk-A43I2AJ4.js → chunk-TM5XQY3L.js} +3 -3
  44. package/dist/{chunk-A43I2AJ4.js.map → chunk-TM5XQY3L.js.map} +1 -1
  45. package/dist/{chunk-KL65SSR7.js → chunk-TNADGCOX.js} +323 -152
  46. package/dist/chunk-TNADGCOX.js.map +1 -0
  47. package/dist/{chunk-V3X3DBZL.js → chunk-UXR7FBE3.js} +6 -6
  48. package/dist/{chunk-V3X3DBZL.js.map → chunk-UXR7FBE3.js.map} +1 -1
  49. package/dist/{chunk-IPICO2RV.js → chunk-VIWZ4QT7.js} +14 -3
  50. package/dist/chunk-VIWZ4QT7.js.map +1 -0
  51. package/dist/{chunk-IRCYOTRG.js → chunk-WGPS3NZQ.js} +240 -13
  52. package/dist/chunk-WGPS3NZQ.js.map +1 -0
  53. package/dist/{chunk-I6RBAIS3.js → chunk-XK5LKOBF.js} +4 -4
  54. package/dist/{chunk-I6RBAIS3.js.map → chunk-XK5LKOBF.js.map} +1 -1
  55. package/dist/cli.js +796 -359
  56. package/dist/cli.js.map +1 -1
  57. package/dist/ensure-map-TAVYMPEG.js +29 -0
  58. package/dist/{ensure-map-SMWHKOUY.js.map → ensure-map-TAVYMPEG.js.map} +1 -1
  59. package/dist/{graph-backend-I4I72J4W.js → graph-backend-WF4LGBGD.js} +5 -5
  60. package/dist/{graph-backend-I4I72J4W.js.map → graph-backend-WF4LGBGD.js.map} +1 -1
  61. package/dist/index.d.ts +143 -7
  62. package/dist/index.js +17 -16
  63. package/dist/index.js.map +1 -1
  64. package/dist/{interactive-TMQR6TXM.js → interactive-6PN237LX.js} +49 -32
  65. package/dist/interactive-6PN237LX.js.map +1 -0
  66. package/dist/load-T2FOJUPI.js +10 -0
  67. package/dist/{load-E3OTM7BS.js.map → load-T2FOJUPI.js.map} +1 -1
  68. package/dist/model-manager-GJ2YSTSK.js +1 -1
  69. package/dist/{run-outcome-QWLNBASF.js → run-outcome-AMIKAASL.js} +6 -6
  70. package/dist/{run-outcome-QWLNBASF.js.map → run-outcome-AMIKAASL.js.map} +1 -1
  71. package/dist/runtime-session-QAVOPSSH.js +20 -0
  72. package/dist/{runtime-session-UQ7UVAPL.js.map → runtime-session-QAVOPSSH.js.map} +1 -1
  73. package/dist/session-SCHQQTHN.js +15 -0
  74. package/dist/{session-MG6BJVAG.js.map → session-SCHQQTHN.js.map} +1 -1
  75. package/dist/session-store-F7NX7SZN.js +4 -0
  76. package/dist/{session-store-SQECEXUU.js.map → session-store-F7NX7SZN.js.map} +1 -1
  77. package/dist/{stream-json-GM44SP7L.js → stream-json-A6K2MONY.js} +48 -16
  78. package/dist/stream-json-A6K2MONY.js.map +1 -0
  79. package/dist/{vg-mcp-bridge-3WFC7LGE.js → vg-mcp-bridge-3TSFOL4V.js} +13 -11
  80. package/dist/vg-mcp-bridge-3TSFOL4V.js.map +1 -0
  81. package/dist/{vgd-ZUSBEVUL.js → vgd-B67JCNJP.js} +9 -9
  82. package/dist/vgd-B67JCNJP.js.map +1 -0
  83. package/package.json +1 -1
  84. package/dist/agent-4DAECASW.js +0 -22
  85. package/dist/baseline-4BDH4F2W.js +0 -9
  86. package/dist/chunk-76TDXGGF.js.map +0 -1
  87. package/dist/chunk-7G5S5KZN.js.map +0 -1
  88. package/dist/chunk-7PVCHLR2.js.map +0 -1
  89. package/dist/chunk-BNEHDLVZ.js.map +0 -1
  90. package/dist/chunk-G25STLE7.js.map +0 -1
  91. package/dist/chunk-IPICO2RV.js.map +0 -1
  92. package/dist/chunk-IRCYOTRG.js.map +0 -1
  93. package/dist/chunk-JLWI2JGA.js.map +0 -1
  94. package/dist/chunk-KL65SSR7.js.map +0 -1
  95. package/dist/chunk-MPP4S4OE.js.map +0 -1
  96. package/dist/chunk-SDG242R4.js.map +0 -1
  97. package/dist/chunk-TGDHOAXX.js +0 -6
  98. package/dist/chunk-WIDZ5IE7.js.map +0 -1
  99. package/dist/chunk-XEJJGDGX.js.map +0 -1
  100. package/dist/chunk-ZKNB4YH4.js +0 -102
  101. package/dist/chunk-ZKNB4YH4.js.map +0 -1
  102. package/dist/ensure-map-SMWHKOUY.js +0 -28
  103. package/dist/interactive-TMQR6TXM.js.map +0 -1
  104. package/dist/load-E3OTM7BS.js +0 -10
  105. package/dist/runtime-session-UQ7UVAPL.js +0 -20
  106. package/dist/session-MG6BJVAG.js +0 -13
  107. package/dist/session-store-SQECEXUU.js +0 -4
  108. package/dist/stream-json-GM44SP7L.js.map +0 -1
  109. package/dist/vg-mcp-bridge-3WFC7LGE.js.map +0 -1
  110. package/dist/vgd-ZUSBEVUL.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { loadAdvancedScanHook, baselineCommand } from './chunk-FF5ZQ6KI.js';
3
- import { fetchCatalog, resolveProviders } from './chunk-JLWI2JGA.js';
4
- import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-V2QK3IUY.js';
5
- import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-B3OMGYZZ.js';
2
+ import { loadAdvancedScanHook, baselineCommand } from './chunk-6JP7HGIF.js';
3
+ import { fetchCatalog, resolveProviders } from './chunk-NUZM7UOR.js';
4
+ import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-L5PUNO3T.js';
5
+ import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-PXM3VZYR.js';
6
+ import './chunk-7AVYKZEM.js';
6
7
  import { buildModelInstallPlan } from './chunk-WHJMS7XC.js';
7
- import { runCodeSession } from './chunk-WIDZ5IE7.js';
8
- import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-XEJJGDGX.js';
9
- export { runBuild } from './chunk-XEJJGDGX.js';
8
+ import { runCodeSession } from './chunk-M7773OUN.js';
9
+ import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-KYX2YCXT.js';
10
+ export { runBuild } from './chunk-KYX2YCXT.js';
10
11
  import { disableColor, info, c, json, out } from './chunk-CT5BS56U.js';
11
- import './chunk-5I4VSBWQ.js';
12
12
  import './chunk-IS7VTH2Q.js';
13
13
  import { init_resolve_ollama, gatherSystemMemory, resolveOllamaBinary, hasOllamaBinary, resolve_ollama_exports } from './chunk-OWSFZQOP.js';
14
14
  import { readOrchestratorState, writeOrchestratorState, parseMode, setDefaultMode, recommendMode, activePin, resolveMode, providerForBackend, QUALIFIED_PACKS, pinPack, unpinPack, buildOrchestratorStatus } from './chunk-NZELMYT4.js';
@@ -16,54 +16,55 @@ import { fmt, estimateModelBytes } from './chunk-7N4Y3E47.js';
16
16
  import './chunk-IZDH67DX.js';
17
17
  import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-JFE7XCAE.js';
18
18
  import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-3LOWJSAF.js';
19
- import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-IRCYOTRG.js';
19
+ import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-WGPS3NZQ.js';
20
20
  import './chunk-543E6WDJ.js';
21
- import { summarizeDiffs, ScriptedProvider } from './chunk-G25STLE7.js';
21
+ import { summarizeDiffs, ScriptedProvider } from './chunk-SJFBXCII.js';
22
22
  import { ensurePackage, ensureUnavailableMessage } from './chunk-REIGWTTH.js';
23
- import './chunk-A43I2AJ4.js';
23
+ import './chunk-TM5XQY3L.js';
24
24
  import { vgdSocketPath, vgdIsRunning, vgdRequest, vgdPidPath } from './chunk-RBIRXQR6.js';
25
25
  import { buildIdentifierTrieFromGraph } from './chunk-5HYCB55P.js';
26
- import './chunk-7AVYKZEM.js';
27
- import { serveStdio, exportGraph, GraphSource, createServer, formatForExt } from './chunk-BNEHDLVZ.js';
28
- import { refreshIfStale } from './chunk-V3X3DBZL.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-KL65SSR7.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-7PVCHLR2.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-XRN7DQGR.js';
26
+ import { serveStdio, isRelevantChange, exportGraph, GraphSource, createServer, formatForExt } from './chunk-NSWEJPLV.js';
27
+ import { refreshIfStale } from './chunk-UXR7FBE3.js';
28
+ 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-TNADGCOX.js';
29
+ 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-M452MRWI.js';
30
+ 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-NJFQCDGA.js';
32
31
  import { resolveIngestHost, dashHostForIngestHost, availableRegionIds, ingestHostForRegionId } from './chunk-HTLDXEHW.js';
32
+ import { discoverModels } from './chunk-CQDUBAQY.js';
33
+ import { freeBytesOnVolume, weightStoreDir, listCachedWeights, ensureWeightCached, catalogIntegrityReport } from './chunk-OV4KGXPD.js';
34
+ import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-DT4KIVRI.js';
33
35
  import { ensureDir, pathExists, readJsonFile, writeTextFile, writeJsonFile } from './chunk-CRAMOEBE.js';
34
- import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-MPP4S4OE.js';
35
- import './chunk-IPICO2RV.js';
36
- import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-I6RBAIS3.js';
36
+ import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-K6Q6HTFD.js';
37
+ import './chunk-VIWZ4QT7.js';
38
+ import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-XK5LKOBF.js';
37
39
  import { init_cli_invocation, resolveCliInvocation, NPX_INVOCATION } from './chunk-3LSG7Z4I.js';
38
40
  import { resolveOne } from './chunk-J7LKEB2R.js';
39
- import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, countPending, indexFor, impactOf, modelCacheInfo, clearModelCache } from './chunk-SDG242R4.js';
40
- import { discoverModels } from './chunk-CQDUBAQY.js';
41
- import { freeBytesOnVolume, weightStoreDir, listCachedWeights, ensureWeightCached, catalogIntegrityReport } from './chunk-OV4KGXPD.js';
41
+ import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, countPending, indexFor, impactOf, modelCacheInfo, clearModelCache, withTimeout } from './chunk-HC44772H.js';
42
42
  import { resolvedGrammarFiles, grammarSetVersion } from './chunk-UTNNGKKX.js';
43
43
  import './chunk-RXP66R2E.js';
44
- import { loadGraph, SCHEMA_VERSION } from './chunk-T6DRYOMT.js';
45
- import { resolveGraphPath, renderReport, loadGraphFileWithSnapshot, writeArtifacts, vibgrateDir, mapFileExists, ensureVibgrateGitignore } from './chunk-76TDXGGF.js';
46
- import { VERSION } from './chunk-TGDHOAXX.js';
47
- import { cacheDir, serializeGraph, stableStringify } from './chunk-ZKNB4YH4.js';
44
+ import { loadGraph, loadGraphPreferIndex, SCHEMA_VERSION } from './chunk-CPLG4GFB.js';
45
+ import { resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, resetRelevanceProviderCache, loadRelevanceProvider, loadGraphFileWithSnapshot, writeArtifacts, vibgrateDir, mapFileExists, relevanceModuleDir, ensureVibgrateGitignore } from './chunk-3Q3ZXJZP.js';
46
+ import { VERSION } from './chunk-7KNFG44U.js';
47
+ import { cacheDir, serializeGraph, stableStringify, parseGraph } from './chunk-QMME6TB4.js';
48
+ import './chunk-5I4VSBWQ.js';
48
49
  import './chunk-BWPBB45M.js';
49
50
  import { canonicalize, hashString, hashBytes } from './chunk-JFGYT6BI.js';
50
51
  import './chunk-BPF3YX2U.js';
51
- import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-DT4KIVRI.js';
52
52
  import { __toCommonJS } from './chunk-Z6ZWNWWR.js';
53
- import * as fs7 from 'fs';
54
- import fs7__default, { realpathSync } from 'fs';
55
- import * as path37 from 'path';
56
- import path37__default from 'path';
53
+ import * as fs10 from 'fs';
54
+ import fs10__default, { realpathSync } from 'fs';
55
+ import * as path39 from 'path';
56
+ import path39__default from 'path';
57
57
  import { fileURLToPath, pathToFileURL } from 'url';
58
58
  import { Command, CommanderError, Option } from 'commander';
59
59
  import * as semver3 from 'semver';
60
60
  import semver3__default from 'semver';
61
- import { execSync, spawn, spawnSync, execFileSync } from 'child_process';
62
61
  import * as readline from 'readline';
62
+ import * as zlib from 'zlib';
63
63
  import * as crypto3 from 'crypto';
64
- import { randomUUID } from 'crypto';
64
+ import { randomUUID, createHash } from 'crypto';
65
+ import { execSync, spawn, spawnSync, execFileSync } from 'child_process';
65
66
  import chalk7 from 'chalk';
66
- import * as fs21 from 'fs/promises';
67
+ import * as fs24 from 'fs/promises';
67
68
  import * as os from 'os';
68
69
 
69
70
  init_cli_invocation();
@@ -74,10 +75,10 @@ function registerStatus(program) {
74
75
  applyGlobalOptions(cmd);
75
76
  }
76
77
  async function runStatus(global) {
77
- const root2 = path37.resolve(global.cwd ?? ".");
78
+ const root2 = path39.resolve(global.cwd ?? ".");
78
79
  const graphPath = resolveGraphPath(root2, global.graph);
79
80
  const graph = loadGraph(root2, graphPath);
80
- const hasCache = fs7.existsSync(path37.join(cacheDir(root2), "parse-cache.json"));
81
+ const hasCache = fs10.existsSync(path39.join(cacheDir(root2), "parse-cache.json"));
81
82
  let stale = null;
82
83
  let staleExact = false;
83
84
  if (graph) {
@@ -97,8 +98,8 @@ async function runStatus(global) {
97
98
  }
98
99
  if (global.json) {
99
100
  json({
100
- root: path37.relative(process.cwd(), root2) || ".",
101
- graphPath: path37.relative(root2, graphPath),
101
+ root: path39.relative(process.cwd(), root2) || ".",
102
+ graphPath: path39.relative(root2, graphPath),
102
103
  built: graph !== null,
103
104
  generatedAt: graph?.generatedAt ?? null,
104
105
  counts: graph?.meta.counts ?? null,
@@ -113,11 +114,11 @@ async function runStatus(global) {
113
114
  return;
114
115
  }
115
116
  if (!graph) {
116
- info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(path37.relative(root2, graphPath))}`);
117
+ info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(path39.relative(root2, graphPath))}`);
117
118
  info(` run ${c.bold("vg")} to build one`);
118
119
  return;
119
120
  }
120
- info(`${c.cyan("vg")} \xB7 ${path37.relative(root2, graphPath)}`);
121
+ info(`${c.cyan("vg")} \xB7 ${path39.relative(root2, graphPath)}`);
121
122
  info(` generated ${graph.generatedAt}`);
122
123
  info(
123
124
  ` nodes ${c.bold(String(graph.meta.counts.nodes))} edges ${c.bold(
@@ -134,7 +135,7 @@ async function runStatus(global) {
134
135
  if (vibgrateDir(root2)) ;
135
136
  }
136
137
  function rootOf(global) {
137
- return path37.resolve(global.cwd ?? ".");
138
+ return path39.resolve(global.cwd ?? ".");
138
139
  }
139
140
  function requireGraph(global) {
140
141
  const root2 = rootOf(global);
@@ -170,6 +171,8 @@ function registerAsk(program) {
170
171
  let result;
171
172
  let mode = "lexical";
172
173
  let note = "";
174
+ const relevance = await analyzeQuestion(q);
175
+ const topicTags = relevance ? await loadTopicTags(graph, root2, resolveGraphPath(root2, global.graph)) : null;
173
176
  if (wantSemantic) {
174
177
  const firstRun = !embeddingsCached(root2, resolveEmbedModel());
175
178
  if (!global.json && firstRun) {
@@ -181,14 +184,14 @@ function registerAsk(program) {
181
184
  const bar = !global.json && firstRun ? new ProgressBar(c.dim("embedding")) : void 0;
182
185
  const vectors = await getNodeEmbeddings(graph, embedder, root2, bar ? (d, t) => bar.update(d, t) : void 0);
183
186
  bar?.done();
184
- result = await queryGraphSemantic(graph, q, { budget, embedder, nodeVectors: vectors });
187
+ result = await queryGraphSemantic(graph, q, { budget, embedder, nodeVectors: vectors, relevance, topicTags });
185
188
  mode = `semantic (${embedder.id})`;
186
189
  } else {
187
- result = queryGraph(graph, q, { budget });
190
+ result = queryGraph(graph, q, { budget, relevance, topicTags });
188
191
  note = reason ? unavailableMessage(reason) : "semantic unavailable; used lexical";
189
192
  }
190
193
  } else {
191
- result = queryGraph(graph, q, { budget });
194
+ result = queryGraph(graph, q, { budget, relevance, topicTags });
192
195
  if (global.local) note = "semantic skipped under --local; used lexical";
193
196
  }
194
197
  if (global.client) {
@@ -868,12 +871,12 @@ var PUBLISH_INTERVAL_MS = 2e3;
868
871
  var KEEPALIVE_MS = 1e4;
869
872
  var STALE_MS = 6e4;
870
873
  function liveStatsDir(root2) {
871
- return path37.join(cacheDir(root2), "serve-live");
874
+ return path39.join(cacheDir(root2), "serve-live");
872
875
  }
873
876
  function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid, signal) => process.kill(pid, signal), selfPid = process.pid) {
874
877
  let entries;
875
878
  try {
876
- entries = fs7.readdirSync(dir);
879
+ entries = fs10.readdirSync(dir);
877
880
  } catch {
878
881
  return [];
879
882
  }
@@ -882,7 +885,7 @@ function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid
882
885
  if (!/^serve-\d+\.json$/.test(name)) continue;
883
886
  let parsed;
884
887
  try {
885
- parsed = JSON.parse(fs7.readFileSync(path37.join(dir, name), "utf8"));
888
+ parsed = JSON.parse(fs10.readFileSync(path39.join(dir, name), "utf8"));
886
889
  } catch {
887
890
  continue;
888
891
  }
@@ -904,7 +907,7 @@ var LiveStatsBus = class {
904
907
  this.dir = dir;
905
908
  this.stats = stats;
906
909
  this.pid = pid;
907
- this.file = path37.join(dir, `serve-${this.pid}.json`);
910
+ this.file = path39.join(dir, `serve-${this.pid}.json`);
908
911
  }
909
912
  dir;
910
913
  stats;
@@ -936,10 +939,10 @@ var LiveStatsBus = class {
936
939
  this.lastWriteAt = now;
937
940
  const body = { pid: this.pid, updatedAt: now, version: VERSION, snapshot: snap };
938
941
  try {
939
- fs7.mkdirSync(this.dir, { recursive: true });
942
+ fs10.mkdirSync(this.dir, { recursive: true });
940
943
  const tmp = `${this.file}.tmp`;
941
- fs7.writeFileSync(tmp, JSON.stringify(body));
942
- fs7.renameSync(tmp, this.file);
944
+ fs10.writeFileSync(tmp, JSON.stringify(body));
945
+ fs10.renameSync(tmp, this.file);
943
946
  } catch {
944
947
  }
945
948
  }
@@ -950,24 +953,24 @@ var LiveStatsBus = class {
950
953
  siblings(now = Date.now()) {
951
954
  let entries;
952
955
  try {
953
- entries = fs7.readdirSync(this.dir);
956
+ entries = fs10.readdirSync(this.dir);
954
957
  } catch {
955
958
  return [];
956
959
  }
957
960
  const out2 = [];
958
961
  for (const name of entries.sort()) {
959
962
  if (!/^serve-\d+\.json$/.test(name)) continue;
960
- const file = path37.join(this.dir, name);
963
+ const file = path39.join(this.dir, name);
961
964
  let parsed;
962
965
  try {
963
- parsed = JSON.parse(fs7.readFileSync(file, "utf8"));
966
+ parsed = JSON.parse(fs10.readFileSync(file, "utf8"));
964
967
  } catch {
965
968
  continue;
966
969
  }
967
970
  if (typeof parsed?.pid !== "number" || typeof parsed.updatedAt !== "number" || !parsed.snapshot?.totals) continue;
968
971
  if (now - parsed.updatedAt > STALE_MS) {
969
972
  try {
970
- fs7.unlinkSync(file);
973
+ fs10.unlinkSync(file);
971
974
  } catch {
972
975
  }
973
976
  continue;
@@ -979,7 +982,7 @@ var LiveStatsBus = class {
979
982
  }
980
983
  unlinkOwn = () => {
981
984
  try {
982
- fs7.unlinkSync(this.file);
985
+ fs10.unlinkSync(this.file);
983
986
  } catch {
984
987
  }
985
988
  };
@@ -1292,12 +1295,12 @@ var LedgerTail = class {
1292
1295
  if (size === this.offset) return;
1293
1296
  let chunk;
1294
1297
  try {
1295
- const fd = fs7.openSync(this.file, "r");
1298
+ const fd = fs10.openSync(this.file, "r");
1296
1299
  try {
1297
1300
  chunk = Buffer.alloc(size - this.offset);
1298
- fs7.readSync(fd, chunk, 0, chunk.length, this.offset);
1301
+ fs10.readSync(fd, chunk, 0, chunk.length, this.offset);
1299
1302
  } finally {
1300
- fs7.closeSync(fd);
1303
+ fs10.closeSync(fd);
1301
1304
  }
1302
1305
  } catch {
1303
1306
  return;
@@ -1310,7 +1313,7 @@ var LedgerTail = class {
1310
1313
  }
1311
1314
  sizeOf() {
1312
1315
  try {
1313
- return fs7.statSync(this.file).size;
1316
+ return fs10.statSync(this.file).size;
1314
1317
  } catch {
1315
1318
  return 0;
1316
1319
  }
@@ -1342,7 +1345,7 @@ function ingestLedgerLine(stats, line, now) {
1342
1345
  // src/commands/serve.ts
1343
1346
  var SHARE_FLUSH_INTERVAL_MS = 5 * 60 * 1e3;
1344
1347
  function registerServe(program) {
1345
- const cmd = program.command("serve").description("start Vibgrate AI Context \u2014 local-first MCP serving your code map, drift & version-correct docs to your AI").option("--http", "serve over streamable HTTP instead of stdio").option("--port <n>", "port for --http", "7437").option("--host <h>", "host for --http", "127.0.0.1").option("--savings", "record local, counts-only usage savings (opt-in; off by default)").option("--share-stats", "ALSO upload the counts-only usage ledger to Vibgrate to improve the local MCP (opt-in; off by default; implies --savings; disabled under --local)").option("--dedup", "collapse a node's heavy relation lists on repeat reads within a session (opt-in; saves tokens)").option("--no-refresh", "serve the map as built \u2014 skip the auto-rebuild when files change").action(async function(opts) {
1348
+ const cmd = program.command("serve").description("start Vibgrate AI Context \u2014 local-first MCP serving your code map, drift & version-correct docs to your AI").option("--http", "serve over streamable HTTP instead of stdio").option("--port <n>", "port for --http", "7437").option("--host <h>", "host for --http", "127.0.0.1").option("--savings", "record local, counts-only usage savings (opt-in; off by default)").option("--share-stats", "ALSO upload the counts-only usage ledger to Vibgrate to improve the local MCP (opt-in; off by default; implies --savings; disabled under --local)").option("--dedup", "collapse a node's heavy relation lists on repeat reads within a session (opt-in; saves tokens)").option("--no-refresh", "serve the map as built \u2014 skip the auto-rebuild when files change").option("--no-watch", "disable the event-driven file watcher \u2014 freshness falls back to the periodic poll").option("--surface <mode>", 'tool listing surface: "hot" lists only the navigation core (orient/search_symbols/query_graph/get_node); "full" lists all tools. Every tool stays callable either way. Env: VG_MCP_SURFACE').option("--tools <names>", "comma-separated tool names to list (listing only \u2014 all tools remain callable). Env: VG_MCP_TOOLS").action(async function(opts) {
1346
1349
  const global = readGlobal(this);
1347
1350
  const root2 = rootOf(global);
1348
1351
  const graphPath = resolveGraphPath(root2, global.graph);
@@ -1365,8 +1368,15 @@ function registerServe(program) {
1365
1368
  local,
1366
1369
  dedup: opts.dedup === true,
1367
1370
  refresh,
1371
+ watch: opts.watch !== false,
1368
1372
  root: root2,
1369
- stats
1373
+ stats,
1374
+ // Listing surface: flags win over env; unknown values fall back to the
1375
+ // full surface inside listedToolNames (fail-open).
1376
+ toolSurface: {
1377
+ surface: (opts.surface ?? process.env.VG_MCP_SURFACE) === "hot" ? "hot" : "full",
1378
+ tools: (opts.tools ?? process.env.VG_MCP_TOOLS)?.split(",").map((s) => s.trim()).filter(Boolean)
1379
+ }
1370
1380
  };
1371
1381
  await ensureServableGraph(root2, graphPath, global, refresh);
1372
1382
  if (opts.shareStats === true && local) {
@@ -1455,6 +1465,7 @@ async function serveHttp(graphPath, host, port, opts, freshness, onReady) {
1455
1465
  const { createServer: createHttp } = await import('http');
1456
1466
  const { StreamableHTTPServerTransport } = await import('@modelcontextprotocol/sdk/server/streamableHttp.js');
1457
1467
  const source = new GraphSource(graphPath, opts.refresh !== false, { root: opts.root });
1468
+ if (opts.refresh !== false && opts.watch !== false) source.startWatching();
1458
1469
  const httpServer = createHttp(async (req, res) => {
1459
1470
  if (req.url !== "/mcp") {
1460
1471
  res.writeHead(404).end("not found");
@@ -1695,19 +1706,19 @@ function endOfLine(text, line) {
1695
1706
  }
1696
1707
  var CACHE_VERSION = "vg-lsp-scan-cache/2";
1697
1708
  function cachePath(root2) {
1698
- return path37.join(cacheDir(root2), "lsp-scan.json");
1709
+ return path39.join(cacheDir(root2), "lsp-scan.json");
1699
1710
  }
1700
1711
  function manifestHash(root2) {
1701
1712
  const files = [];
1702
1713
  const walk2 = (dir) => {
1703
1714
  let entries;
1704
1715
  try {
1705
- entries = fs7.readdirSync(dir, { withFileTypes: true });
1716
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
1706
1717
  } catch {
1707
1718
  return;
1708
1719
  }
1709
1720
  for (const entry of entries) {
1710
- const abs = path37.join(dir, entry.name);
1721
+ const abs = path39.join(dir, entry.name);
1711
1722
  if (entry.isDirectory()) {
1712
1723
  if (isSkippedDirName(entry.name)) continue;
1713
1724
  walk2(abs);
@@ -1717,8 +1728,8 @@ function manifestHash(root2) {
1717
1728
  const base = entry.name.toLowerCase();
1718
1729
  if (!isManifest(abs) && !SKIP_FILES.has(base)) continue;
1719
1730
  try {
1720
- const rel = path37.relative(root2, abs).split(path37.sep).join("/");
1721
- files.push({ rel, hash: hashBytes(fs7.readFileSync(abs)) });
1731
+ const rel = path39.relative(root2, abs).split(path39.sep).join("/");
1732
+ files.push({ rel, hash: hashBytes(fs10.readFileSync(abs)) });
1722
1733
  } catch {
1723
1734
  }
1724
1735
  }
@@ -1728,16 +1739,16 @@ function manifestHash(root2) {
1728
1739
  return hashString(canonicalize(files));
1729
1740
  }
1730
1741
  function isDependencyFile(root2, filePath) {
1731
- const rel = path37.relative(path37.resolve(root2), path37.resolve(filePath));
1732
- if (rel === "" || rel.startsWith("..") || path37.isAbsolute(rel)) return false;
1733
- const parts = rel.split(path37.sep);
1742
+ const rel = path39.relative(path39.resolve(root2), path39.resolve(filePath));
1743
+ if (rel === "" || rel.startsWith("..") || path39.isAbsolute(rel)) return false;
1744
+ const parts = rel.split(path39.sep);
1734
1745
  if (parts.slice(0, -1).some((dir) => isSkippedDirName(dir))) return false;
1735
1746
  const base = parts[parts.length - 1].toLowerCase();
1736
1747
  return isManifest(filePath) || SKIP_FILES.has(base);
1737
1748
  }
1738
1749
  function loadScanCache(root2, key2) {
1739
1750
  try {
1740
- const raw = JSON.parse(fs7.readFileSync(cachePath(root2), "utf8"));
1751
+ const raw = JSON.parse(fs10.readFileSync(cachePath(root2), "utf8"));
1741
1752
  if (raw.version === CACHE_VERSION && raw.manifestHash === key2.manifestHash && raw.toolVersion === key2.toolVersion && raw.offline === key2.offline && raw.artifact) {
1742
1753
  return { manifestHash: raw.manifestHash, artifact: raw.artifact };
1743
1754
  }
@@ -1747,8 +1758,8 @@ function loadScanCache(root2, key2) {
1747
1758
  }
1748
1759
  function writeScanCache(root2, key2, artifact) {
1749
1760
  try {
1750
- fs7.mkdirSync(cacheDir(root2), { recursive: true });
1751
- fs7.writeFileSync(
1761
+ fs10.mkdirSync(cacheDir(root2), { recursive: true });
1762
+ fs10.writeFileSync(
1752
1763
  cachePath(root2),
1753
1764
  stableStringify(
1754
1765
  { version: CACHE_VERSION, manifestHash: key2.manifestHash, toolVersion: key2.toolVersion, offline: key2.offline, artifact },
@@ -1761,7 +1772,7 @@ function writeScanCache(root2, key2, artifact) {
1761
1772
  var MAX_ENTRIES = 1e3;
1762
1773
  var KEEP_ENTRIES = 500;
1763
1774
  function historyPath(root2) {
1764
- return path37.join(root2, ".vibgrate", "score-history.jsonl");
1775
+ return path39.join(root2, ".vibgrate", "score-history.jsonl");
1765
1776
  }
1766
1777
  function parseLine(line) {
1767
1778
  try {
@@ -1775,7 +1786,7 @@ function parseLine(line) {
1775
1786
  }
1776
1787
  function readHistory(root2) {
1777
1788
  try {
1778
- return fs7.readFileSync(historyPath(root2), "utf8").split("\n").filter((l) => l.trim()).map(parseLine).filter((e) => e !== null);
1789
+ return fs10.readFileSync(historyPath(root2), "utf8").split("\n").filter((l) => l.trim()).map(parseLine).filter((e) => e !== null);
1779
1790
  } catch {
1780
1791
  return [];
1781
1792
  }
@@ -1802,14 +1813,14 @@ function recordScore(root2, entry) {
1802
1813
  }
1803
1814
  }
1804
1815
  const file = historyPath(root2);
1805
- fs7.mkdirSync(path37.dirname(file), { recursive: true });
1816
+ fs10.mkdirSync(path39.dirname(file), { recursive: true });
1806
1817
  ensureVibgrateGitignore(root2);
1807
- fs7.appendFileSync(file, `${JSON.stringify(entry)}
1818
+ fs10.appendFileSync(file, `${JSON.stringify(entry)}
1808
1819
  `);
1809
1820
  const all = readHistory(root2);
1810
1821
  if (all.length > MAX_ENTRIES) {
1811
1822
  const kept = all.slice(-KEEP_ENTRIES);
1812
- fs7.writeFileSync(file, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
1823
+ fs10.writeFileSync(file, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
1813
1824
  }
1814
1825
  } catch {
1815
1826
  }
@@ -1821,6 +1832,10 @@ function deltaFrom(prev, current) {
1821
1832
  }
1822
1833
 
1823
1834
  // src/lsp/graph-query.ts
1835
+ function semanticBudgetMs() {
1836
+ const n = Number(process.env.VG_SEMANTIC_BUDGET_MS);
1837
+ return Number.isFinite(n) && n > 0 ? n : 2e4;
1838
+ }
1824
1839
  async function runGraphQuery(graph, params, ctx) {
1825
1840
  switch (params.mode) {
1826
1841
  case "ask":
@@ -1846,25 +1861,52 @@ async function runAsk(graph, params, ctx) {
1846
1861
  if (!question) return { ok: false, mode: "ask", error: "bad-request", message: "question is required" };
1847
1862
  const budget = params.budget ?? 2e3;
1848
1863
  const wantSemantic = !!params.semantic && !ctx.offline && ctx.semantic !== false;
1849
- let result;
1864
+ const log = ctx.log ?? (() => {
1865
+ });
1866
+ let result = null;
1850
1867
  let mode = "lexical";
1851
1868
  let note;
1852
1869
  if (wantSemantic) {
1870
+ const budgetMs = semanticBudgetMs();
1871
+ log(`ask: trying the semantic path (budget ${Math.round(budgetMs / 1e3)}s)`);
1853
1872
  let reason;
1854
- const embedder = await loadEmbedder({ onUnavailable: (r) => reason = r });
1855
- if (embedder) {
1856
- const vectors = await getNodeEmbeddings(graph, embedder, ctx.root);
1857
- result = await queryGraphSemantic(graph, question, { budget, embedder, nodeVectors: vectors });
1858
- mode = `semantic (${embedder.id})`;
1859
- } else {
1860
- result = queryGraph(graph, question, { budget });
1861
- note = reason ? unavailableMessage(reason) : "semantic unavailable; used lexical";
1873
+ const started = Date.now();
1874
+ try {
1875
+ result = await withTimeout(
1876
+ (async () => {
1877
+ const embedder = await loadEmbedder({ onUnavailable: (r2) => reason = r2 });
1878
+ if (!embedder) return null;
1879
+ log(`ask: embedder "${embedder.id}" loaded in ${Date.now() - started}ms; embedding nodes\u2026`);
1880
+ const vectors = await getNodeEmbeddings(graph, embedder, ctx.root);
1881
+ log(`ask: ${vectors.size} node vectors ready in ${Date.now() - started}ms; ranking\u2026`);
1882
+ const r = await queryGraphSemantic(graph, question, { budget, embedder, nodeVectors: vectors });
1883
+ mode = `semantic (${embedder.id})`;
1884
+ return r;
1885
+ })(),
1886
+ budgetMs,
1887
+ "semantic search went over its time budget"
1888
+ );
1889
+ if (!result) {
1890
+ note = reason ? unavailableMessage(reason) : "semantic unavailable; used lexical";
1891
+ log(`ask: semantic unavailable (${reason ?? "no backend"}) \u2014 falling back to lexical`);
1892
+ }
1893
+ } catch (err) {
1894
+ mode = "lexical";
1895
+ result = null;
1896
+ note = "semantic search did not finish in time \u2014 answered with fast lexical search. It keeps warming in the background, so the next Ask should be semantic.";
1897
+ log(
1898
+ `ask: semantic path abandoned after ${Date.now() - started}ms (${err instanceof Error ? err.message : String(err)}) \u2014 falling back to lexical`
1899
+ );
1862
1900
  }
1863
- } else {
1901
+ } else if (params.semantic && ctx.semantic === false) {
1902
+ note = "semantic search is turned off \u2014 used lexical";
1903
+ } else if (params.semantic && ctx.offline) {
1904
+ note = "semantic skipped \u2014 Vibgrate is running offline";
1905
+ }
1906
+ if (!result) {
1864
1907
  result = queryGraph(graph, question, { budget });
1865
- if (params.semantic && ctx.semantic === false) note = "semantic search is turned off \u2014 used lexical";
1866
- else if (params.semantic && ctx.offline) note = "semantic skipped \u2014 Vibgrate is running offline";
1867
1908
  }
1909
+ log(`ask: answered with ${mode} \u2014 ${result.matches.length} match(es)`);
1868
1910
  return {
1869
1911
  ok: true,
1870
1912
  mode: "ask",
@@ -2629,14 +2671,26 @@ var VibgrateLanguageServer = class {
2629
2671
  }
2630
2672
  async onGraphQuery(params) {
2631
2673
  const p = params;
2674
+ const trace = (message) => this.conn.notify("window/logMessage", { type: 3, message: `Vibgrate graph: ${message}` });
2632
2675
  if (!this.opts.graph) {
2676
+ trace(`${p.mode} refused \u2014 the local Vibgrate Graph is turned off (--no-graph)`);
2633
2677
  return { ok: false, mode: p.mode, error: "disabled", message: "the local Vibgrate Graph is turned off" };
2634
2678
  }
2679
+ const started = Date.now();
2635
2680
  const graph = await this.graphForQuery();
2636
2681
  if (!graph) {
2682
+ trace(`${p.mode} has no code map yet \u2014 it is still building`);
2637
2683
  return { ok: false, mode: p.mode, error: "not-found", message: "no code map yet \u2014 it is still building" };
2638
2684
  }
2639
- return runGraphQuery(graph, p, { root: this.opts.root, offline: this.opts.offline, semantic: this.opts.semantic });
2685
+ trace(
2686
+ `${p.mode} over ${graph.nodes.length} nodes / ${graph.edges.length} edges (map ready in ${Date.now() - started}ms)`
2687
+ );
2688
+ return runGraphQuery(graph, p, {
2689
+ root: this.opts.root,
2690
+ offline: this.opts.offline,
2691
+ semantic: this.opts.semantic,
2692
+ log: trace
2693
+ });
2640
2694
  }
2641
2695
  /**
2642
2696
  * `vibgrate/enrich` — lazy vulnerability enrichment for one expanded package,
@@ -2682,10 +2736,10 @@ var VibgrateLanguageServer = class {
2682
2736
  const ecosystem = osvEcosystem(proj.type);
2683
2737
  if (!ecosystem) continue;
2684
2738
  const relManifest = manifestRelativePath(proj);
2685
- const absManifest = path37.resolve(this.opts.root, relManifest);
2739
+ const absManifest = path39.resolve(this.opts.root, relManifest);
2686
2740
  let text = null;
2687
2741
  try {
2688
- if (fs7.existsSync(absManifest)) text = fs7.readFileSync(absManifest, "utf8");
2742
+ if (fs10.existsSync(absManifest)) text = fs10.readFileSync(absManifest, "utf8");
2689
2743
  } catch {
2690
2744
  text = null;
2691
2745
  }
@@ -2815,9 +2869,9 @@ function pruneArtifactProjects(a) {
2815
2869
  return { ...a, projects, findings };
2816
2870
  }
2817
2871
  function projectByPath(a, projectPath) {
2818
- const want = path37.normalize(projectPath === "" ? "." : projectPath);
2872
+ const want = path39.normalize(projectPath === "" ? "." : projectPath);
2819
2873
  for (const proj of a.projects ?? []) {
2820
- const got = path37.normalize(proj.path === "" ? "." : proj.path);
2874
+ const got = path39.normalize(proj.path === "" ? "." : proj.path);
2821
2875
  if (got === want) return proj;
2822
2876
  }
2823
2877
  return void 0;
@@ -2854,12 +2908,12 @@ function buildProjectRefs(rootDir, projects) {
2854
2908
  return refs.length > 0 ? refs : void 0;
2855
2909
  }
2856
2910
  function projectForFile(root2, a, filePath) {
2857
- const dir = path37.dirname(path37.resolve(filePath));
2911
+ const dir = path39.dirname(path39.resolve(filePath));
2858
2912
  let best;
2859
2913
  let bestLen = -1;
2860
2914
  for (const proj of a.projects ?? []) {
2861
- const projDir = path37.resolve(root2, proj.path);
2862
- if ((dir === projDir || dir.startsWith(projDir + path37.sep)) && projDir.length > bestLen) {
2915
+ const projDir = path39.resolve(root2, proj.path);
2916
+ if ((dir === projDir || dir.startsWith(projDir + path39.sep)) && projDir.length > bestLen) {
2863
2917
  best = proj;
2864
2918
  bestLen = projDir.length;
2865
2919
  }
@@ -2867,7 +2921,7 @@ function projectForFile(root2, a, filePath) {
2867
2921
  return best;
2868
2922
  }
2869
2923
  function sameProject(location, projectPath) {
2870
- return path37.normalize(location) === path37.normalize(projectPath);
2924
+ return path39.normalize(location) === path39.normalize(projectPath);
2871
2925
  }
2872
2926
  function hasReleaseDates(a) {
2873
2927
  for (const proj of a.projects ?? []) {
@@ -2937,10 +2991,10 @@ function buildBreakdown(rootDir, projects) {
2937
2991
  const relManifest = manifestRelativePath(p);
2938
2992
  if (isPrunedWorkspacePath(p.path) || isPrunedWorkspacePath(relManifest)) continue;
2939
2993
  const ecosystem = osvEcosystem(p.type);
2940
- const absManifest = path37.resolve(rootDir, relManifest);
2994
+ const absManifest = path39.resolve(rootDir, relManifest);
2941
2995
  let text = null;
2942
2996
  try {
2943
- if (fs7.existsSync(absManifest)) text = fs7.readFileSync(absManifest, "utf8");
2997
+ if (fs10.existsSync(absManifest)) text = fs10.readFileSync(absManifest, "utf8");
2944
2998
  } catch {
2945
2999
  text = null;
2946
3000
  }
@@ -3005,34 +3059,34 @@ function buildBreakdown(rootDir, projects) {
3005
3059
  }
3006
3060
  function manifestRelativePath(proj) {
3007
3061
  const base = proj.path === "." || proj.path === "" ? "" : proj.path;
3008
- const join27 = (name) => base ? path37.join(base, name) : name;
3062
+ const join29 = (name) => base ? path39.join(base, name) : name;
3009
3063
  switch (proj.type) {
3010
3064
  case "node":
3011
3065
  case "typescript":
3012
- return join27("package.json");
3066
+ return join29("package.json");
3013
3067
  case "python":
3014
- return join27("pyproject.toml");
3068
+ return join29("pyproject.toml");
3015
3069
  case "go":
3016
- return join27("go.mod");
3070
+ return join29("go.mod");
3017
3071
  case "rust":
3018
- return join27("Cargo.toml");
3072
+ return join29("Cargo.toml");
3019
3073
  case "ruby":
3020
- return join27("Gemfile");
3074
+ return join29("Gemfile");
3021
3075
  case "php":
3022
- return join27("composer.json");
3076
+ return join29("composer.json");
3023
3077
  case "java":
3024
3078
  case "kotlin":
3025
3079
  case "scala":
3026
3080
  case "groovy":
3027
- return join27("pom.xml");
3081
+ return join29("pom.xml");
3028
3082
  case "dotnet":
3029
- return join27(proj.name ? `${proj.name}.csproj` : "Directory.Build.props");
3083
+ return join29(proj.name ? `${proj.name}.csproj` : "Directory.Build.props");
3030
3084
  case "dart":
3031
- return join27("pubspec.yaml");
3085
+ return join29("pubspec.yaml");
3032
3086
  case "elixir":
3033
- return join27("mix.exs");
3087
+ return join29("mix.exs");
3034
3088
  default:
3035
- return join27("package.json");
3089
+ return join29("package.json");
3036
3090
  }
3037
3091
  }
3038
3092
  function lockfileRelativePath(rootDir, proj) {
@@ -3063,9 +3117,9 @@ function lockfileRelativePath(rootDir, proj) {
3063
3117
  const dirsToTry = base ? [base, ""] : [""];
3064
3118
  for (const dir of dirsToTry) {
3065
3119
  for (const name of candidateNames) {
3066
- const rel = dir ? path37.join(dir, name) : name;
3120
+ const rel = dir ? path39.join(dir, name) : name;
3067
3121
  try {
3068
- if (fs7.existsSync(path37.join(rootDir, rel))) return rel;
3122
+ if (fs10.existsSync(path39.join(rootDir, rel))) return rel;
3069
3123
  } catch {
3070
3124
  }
3071
3125
  }
@@ -3136,10 +3190,10 @@ function lookupImportFiles(map, pkg) {
3136
3190
  }
3137
3191
  function firstPackageMentionLine(root2, relFile, pkg) {
3138
3192
  try {
3139
- const abs = path37.resolve(root2, relFile);
3140
- const stat2 = fs7.statSync(abs);
3193
+ const abs = path39.resolve(root2, relFile);
3194
+ const stat2 = fs10.statSync(abs);
3141
3195
  if (!stat2.isFile() || stat2.size > 256 * 1024) return null;
3142
- const text = fs7.readFileSync(abs, "utf8");
3196
+ const text = fs10.readFileSync(abs, "utf8");
3143
3197
  const tokens = [pkg];
3144
3198
  if (pkg.startsWith("@")) {
3145
3199
  const parts = pkg.split("/");
@@ -3291,7 +3345,7 @@ function hoverMarkdown(dep, contribution) {
3291
3345
  return lines.join("\n");
3292
3346
  }
3293
3347
  function startLanguageServer(opts) {
3294
- if (!fs7.existsSync(opts.root)) {
3348
+ if (!fs10.existsSync(opts.root)) {
3295
3349
  process.stderr.write(`vg lsp: root does not exist: ${opts.root}
3296
3350
  `);
3297
3351
  process.exit(1);
@@ -3333,10 +3387,90 @@ function registerLsp(program) {
3333
3387
  });
3334
3388
  applyGlobalOptions(cmd);
3335
3389
  }
3390
+ var HOOK_NEEDLE = "vg hook pre-tool-use";
3391
+ var MATCHER = "Grep|Glob";
3392
+ var HOOK_TIMEOUT_S = 10;
3393
+ function hookCommand(vgBin) {
3394
+ return `${vgBin} hook pre-tool-use`;
3395
+ }
3396
+ function installClaudeHooks(root2, vgBin = "vg") {
3397
+ const file = path39.join(root2, ".claude", "settings.json");
3398
+ const rel = path39.join(".claude", "settings.json");
3399
+ let settings = {};
3400
+ if (fs10.existsSync(file)) {
3401
+ try {
3402
+ const parsed = JSON.parse(fs10.readFileSync(file, "utf8"));
3403
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3404
+ return { file: rel, status: "skipped", note: "settings.json is not a JSON object \u2014 left untouched" };
3405
+ }
3406
+ settings = parsed;
3407
+ } catch {
3408
+ return { file: rel, status: "skipped", note: "settings.json is not parseable JSON \u2014 left untouched (fix it and rerun)" };
3409
+ }
3410
+ }
3411
+ const hooks = settings.hooks ??= {};
3412
+ if (typeof hooks !== "object" || Array.isArray(hooks)) {
3413
+ return { file: rel, status: "skipped", note: '"hooks" is not an object \u2014 left untouched' };
3414
+ }
3415
+ const pre = hooks.PreToolUse ??= [];
3416
+ if (!Array.isArray(pre)) {
3417
+ return { file: rel, status: "skipped", note: '"hooks.PreToolUse" is not an array \u2014 left untouched' };
3418
+ }
3419
+ const desired = { type: "command", command: hookCommand(vgBin), timeout: HOOK_TIMEOUT_S };
3420
+ for (const group of pre) {
3421
+ for (const entry of group.hooks ?? []) {
3422
+ if (typeof entry.command === "string" && entry.command.includes(HOOK_NEEDLE)) {
3423
+ if (entry.command === desired.command && entry.timeout === desired.timeout && group.matcher === MATCHER) {
3424
+ return { file: rel, status: "unchanged" };
3425
+ }
3426
+ entry.command = desired.command;
3427
+ entry.timeout = desired.timeout;
3428
+ group.matcher = MATCHER;
3429
+ writeSettings(file, settings);
3430
+ return { file: rel, status: "written", note: "updated existing vg hook entry" };
3431
+ }
3432
+ }
3433
+ }
3434
+ pre.push({ matcher: MATCHER, hooks: [desired] });
3435
+ writeSettings(file, settings);
3436
+ return { file: rel, status: "written" };
3437
+ }
3438
+ function uninstallClaudeHooks(root2) {
3439
+ const file = path39.join(root2, ".claude", "settings.json");
3440
+ const rel = path39.join(".claude", "settings.json");
3441
+ if (!fs10.existsSync(file)) return { file: rel, status: "unchanged" };
3442
+ let settings;
3443
+ try {
3444
+ settings = JSON.parse(fs10.readFileSync(file, "utf8"));
3445
+ } catch {
3446
+ return { file: rel, status: "skipped", note: "settings.json is not parseable JSON \u2014 left untouched" };
3447
+ }
3448
+ const hooks = settings.hooks;
3449
+ const pre = hooks?.PreToolUse;
3450
+ if (!Array.isArray(pre)) return { file: rel, status: "unchanged" };
3451
+ let removed = false;
3452
+ for (const group of pre) {
3453
+ const before = group.hooks?.length ?? 0;
3454
+ group.hooks = (group.hooks ?? []).filter((e) => !(typeof e.command === "string" && e.command.includes(HOOK_NEEDLE)));
3455
+ if (group.hooks.length !== before) removed = true;
3456
+ }
3457
+ const kept = pre.filter((g) => (g.hooks?.length ?? 0) > 0);
3458
+ if (!removed) return { file: rel, status: "unchanged" };
3459
+ if (kept.length) hooks.PreToolUse = kept;
3460
+ else delete hooks.PreToolUse;
3461
+ if (hooks && Object.keys(hooks).length === 0) delete settings.hooks;
3462
+ writeSettings(file, settings);
3463
+ return { file: rel, status: "written" };
3464
+ }
3465
+ function writeSettings(file, settings) {
3466
+ fs10.mkdirSync(path39.dirname(file), { recursive: true });
3467
+ fs10.writeFileSync(file, `${JSON.stringify(settings, null, 2)}
3468
+ `);
3469
+ }
3336
3470
 
3337
3471
  // src/commands/install.ts
3338
3472
  function registerInstall(program) {
3339
- const install = program.command("install").description("add vg to your AI assistant(s): skill + MCP + advisory nudge").argument("[tools...]", `assistant ids: ${ASSISTANTS.map((a) => a.id).join(", ")}`).option("--all", "install for every supported assistant").option("--detect", "detect assistants in use (repo footprint, home config, PATH) and install for those; with --list, only report what was detected").option("--list", "show the support matrix and exit").option("--no-hook", "skip the advisory nudge").action(function(tools, opts) {
3473
+ const install = program.command("install").description("add vg to your AI assistant(s): skill + MCP + advisory nudge").argument("[tools...]", `assistant ids: ${ASSISTANTS.map((a) => a.id).join(", ")}`).option("--all", "install for every supported assistant").option("--detect", "detect assistants in use (repo footprint, home config, PATH) and install for those; with --list, only report what was detected").option("--list", "show the support matrix and exit").option("--no-hook", "skip the advisory nudge").option("--hooks", "also wire the PreToolUse enrichment hook (Claude Code): Grep/Glob calls get graph context via `vg hook pre-tool-use` (project .claude/settings.json; opt-in)").action(function(tools, opts) {
3340
3474
  const global = readGlobal(this);
3341
3475
  const root2 = rootOf(global);
3342
3476
  const detected = opts.detect ? detectAssistants(root2) : [];
@@ -3400,6 +3534,12 @@ function registerInstall(program) {
3400
3534
  for (const r of results) {
3401
3535
  info(`${c.green("\u2714")} ${c.bold(r.id)} \u2014 wrote ${r.wrote.join(", ")}${r.skipped.length ? c.dim(` (skipped ${r.skipped.join(", ")})`) : ""}`);
3402
3536
  }
3537
+ if (opts.hooks && targets.some((a) => a.id === "claude")) {
3538
+ const vgBin = launch.command === "npx" ? null : launch.command;
3539
+ const hooksResult = vgBin ? installClaudeHooks(root2, vgBin) : { file: ".claude/settings.json", status: "skipped", note: "vg is not installed on PATH \u2014 hooks need a fast binary (npm i -g @vibgrate/cli), rerun with --hooks after" };
3540
+ if (hooksResult.status === "written") info(`${c.green("\u2714")} ${c.bold("hooks")} \u2014 wrote PreToolUse enrichment into ${hooksResult.file}`);
3541
+ else if (hooksResult.note) info(`${c.yellow("!")} hooks \u2014 ${hooksResult.note}`);
3542
+ }
3403
3543
  if (launch.note && results.some((r) => r.note)) info(`${c.yellow("!")} ${launch.note}`);
3404
3544
  if (smallRepo) info(c.dim(` note: small repo (${fileCount} files) \u2014 nudge says searching is fine; vg is still used for impact/tests`));
3405
3545
  info(c.dim(` wrote ${navConfig} \u2014 deferred-loading config for Claude-API agents (lower per-step token cost)`));
@@ -3410,6 +3550,10 @@ function registerInstall(program) {
3410
3550
  const global = readGlobal(this);
3411
3551
  const root2 = rootOf(global);
3412
3552
  const results = tools.map(resolve5).map((a) => ({ id: a.id, removed: uninstallAssistant(a, root2, !!opts.purge) }));
3553
+ if (tools.map(resolve5).some((a) => a.id === "claude")) {
3554
+ const hooksResult = uninstallClaudeHooks(root2);
3555
+ if (hooksResult.status === "written") results.find((r) => r.id === "claude")?.removed.push(`${hooksResult.file} (vg hook entries)`);
3556
+ }
3413
3557
  if (global.json) {
3414
3558
  json({ root: root2, results });
3415
3559
  return;
@@ -3434,14 +3578,289 @@ function resolve5(id) {
3434
3578
  }
3435
3579
  return a;
3436
3580
  }
3581
+ var RELEVANCE_MODULE_NAME = "@vibgrate/relevance";
3582
+ var DEFAULT_REGISTRY = "https://registry.npmjs.org";
3583
+ function registryBase(opts) {
3584
+ return (process.env.VIBGRATE_MODULE_REGISTRY || opts.registry || DEFAULT_REGISTRY).replace(/\/+$/, "");
3585
+ }
3586
+ function stateFile() {
3587
+ return path39.join(path39.dirname(relevanceModuleDir()), "consent.json");
3588
+ }
3589
+ function readConsent() {
3590
+ try {
3591
+ return JSON.parse(fs10.readFileSync(stateFile(), "utf8"));
3592
+ } catch {
3593
+ return {};
3594
+ }
3595
+ }
3596
+ function writeConsent(state) {
3597
+ try {
3598
+ fs10.mkdirSync(path39.dirname(stateFile()), { recursive: true });
3599
+ fs10.writeFileSync(stateFile(), JSON.stringify(state));
3600
+ } catch {
3601
+ }
3602
+ }
3603
+ function kernelDisabled() {
3604
+ const v = process.env.VIBGRATE_NO_KERNEL;
3605
+ return v === "1" || v === "true";
3606
+ }
3607
+ function moduleInstalled() {
3608
+ try {
3609
+ const meta = JSON.parse(fs10.readFileSync(path39.join(relevanceModuleDir(), ".module.json"), "utf8"));
3610
+ if (fs10.existsSync(path39.join(relevanceModuleDir(), "index.js"))) {
3611
+ return { installed: true, version: meta.version };
3612
+ }
3613
+ } catch {
3614
+ }
3615
+ return { installed: false };
3616
+ }
3617
+ 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.";
3618
+ function verifyIntegrity(buf, integrity, shasum) {
3619
+ if (integrity) {
3620
+ const [algo, expected] = integrity.split("-", 2);
3621
+ if (!algo || !expected) throw new Error("malformed integrity metadata");
3622
+ const actual = createHash(algo).update(buf).digest("base64");
3623
+ if (actual !== expected) throw new Error(`integrity mismatch (${algo})`);
3624
+ return;
3625
+ }
3626
+ if (shasum) {
3627
+ const actual = createHash("sha1").update(buf).digest("hex");
3628
+ if (actual !== shasum) throw new Error("integrity mismatch (shasum)");
3629
+ return;
3630
+ }
3631
+ throw new Error("registry provided no integrity metadata");
3632
+ }
3633
+ function untar(data) {
3634
+ const out2 = [];
3635
+ let offset = 0;
3636
+ let pendingName = null;
3637
+ while (offset + 512 <= data.length) {
3638
+ const block = data.subarray(offset, offset + 512);
3639
+ offset += 512;
3640
+ if (block.every((b) => b === 0)) continue;
3641
+ const rawName = block.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
3642
+ const size = parseInt(block.subarray(124, 136).toString("utf8").replace(/\0.*$/, "").trim() || "0", 8);
3643
+ const type = String.fromCharCode(block[156]);
3644
+ const prefix = block.subarray(345, 500).toString("utf8").replace(/\0.*$/, "");
3645
+ const body = data.subarray(offset, offset + size);
3646
+ offset += Math.ceil(size / 512) * 512;
3647
+ if (type === "L") {
3648
+ pendingName = body.toString("utf8").replace(/\0.*$/, "");
3649
+ continue;
3650
+ }
3651
+ if (type === "x" || type === "g") {
3652
+ const m = /(?:^|\n)\d+ path=([^\n]+)\n/.exec(body.toString("utf8"));
3653
+ if (m) pendingName = m[1];
3654
+ continue;
3655
+ }
3656
+ if (type !== "0" && type !== "\0") continue;
3657
+ const name = pendingName ?? (prefix ? `${prefix}/${rawName}` : rawName);
3658
+ pendingName = null;
3659
+ if (name.split("/").includes("..") || path39.isAbsolute(name)) {
3660
+ throw new Error(`unsafe path in tarball: ${name}`);
3661
+ }
3662
+ out2.push({ name, body: Buffer.from(body) });
3663
+ }
3664
+ return out2;
3665
+ }
3666
+ async function installRelevanceModule(opts = {}) {
3667
+ if (kernelDisabled()) return { status: "disabled", detail: "VIBGRATE_NO_KERNEL is set" };
3668
+ const existing = moduleInstalled();
3669
+ if (existing.installed && !opts.force) return { status: "already-installed", version: existing.version };
3670
+ const doFetch = opts.fetchImpl ?? fetch;
3671
+ const base = registryBase(opts);
3672
+ try {
3673
+ const metaRes = await doFetch(`${base}/${RELEVANCE_MODULE_NAME.replace("/", "%2f")}`);
3674
+ if (!metaRes.ok) return { status: "unavailable", detail: `registry ${metaRes.status}` };
3675
+ const meta = await metaRes.json();
3676
+ const version = meta["dist-tags"]?.latest;
3677
+ const dist = version ? meta.versions?.[version]?.dist : void 0;
3678
+ if (!version || !dist?.tarball) return { status: "unavailable", detail: "no published version" };
3679
+ const tarRes = await doFetch(dist.tarball);
3680
+ if (!tarRes.ok) return { status: "unavailable", detail: `tarball ${tarRes.status}` };
3681
+ const gz = Buffer.from(await tarRes.arrayBuffer());
3682
+ verifyIntegrity(gz, dist.integrity, dist.shasum);
3683
+ const entries = untar(zlib.gunzipSync(gz));
3684
+ const dir = relevanceModuleDir();
3685
+ fs10.rmSync(dir, { recursive: true, force: true });
3686
+ fs10.mkdirSync(dir, { recursive: true });
3687
+ let wrote = 0;
3688
+ for (const e of entries) {
3689
+ let rel = null;
3690
+ if (e.name.startsWith("package/dist/")) rel = e.name.slice("package/dist/".length);
3691
+ else if (e.name === "package/LICENSE" || e.name === "package/README.md") rel = e.name.slice("package/".length);
3692
+ if (!rel) continue;
3693
+ const target = path39.join(dir, rel);
3694
+ if (!target.startsWith(dir + path39.sep) && target !== dir) throw new Error(`unsafe extract path: ${rel}`);
3695
+ fs10.mkdirSync(path39.dirname(target), { recursive: true });
3696
+ fs10.writeFileSync(target, e.body);
3697
+ wrote += 1;
3698
+ }
3699
+ if (!wrote || !fs10.existsSync(path39.join(dir, "index.js"))) {
3700
+ fs10.rmSync(dir, { recursive: true, force: true });
3701
+ return { status: "unavailable", detail: "package layout not recognized (no dist/index.js)" };
3702
+ }
3703
+ fs10.writeFileSync(path39.join(dir, ".module.json"), JSON.stringify({ name: RELEVANCE_MODULE_NAME, version }));
3704
+ resetRelevanceProviderCache();
3705
+ return { status: "installed", version };
3706
+ } catch (e) {
3707
+ return { status: "unavailable", detail: String(e.message ?? e).slice(0, 200) };
3708
+ }
3709
+ }
3710
+ function removeRelevanceModule() {
3711
+ fs10.rmSync(relevanceModuleDir(), { recursive: true, force: true });
3712
+ resetRelevanceProviderCache();
3713
+ }
3714
+ async function ensureRelevanceModule(io = {}) {
3715
+ try {
3716
+ if (kernelDisabled()) return { status: "disabled" };
3717
+ const existing = moduleInstalled();
3718
+ if (existing.installed) return { status: "already-installed", version: existing.version };
3719
+ if (readConsent().relevance === "denied") return { status: "declined" };
3720
+ return await installRelevanceModule({ fetchImpl: io.fetchImpl });
3721
+ } catch {
3722
+ return { status: "unavailable", detail: "auto-install failed" };
3723
+ }
3724
+ }
3725
+
3726
+ // src/commands/module.ts
3727
+ function registerModule(program) {
3728
+ const cmd = program.command("module").description("manage optional local modules (relevance)");
3729
+ 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) {
3730
+ const global = readGlobal(this);
3731
+ requireRelevance(name);
3732
+ if (kernelDisabled()) {
3733
+ throw new CliError("VIBGRATE_NO_KERNEL is set \u2014 unset it to install the relevance module", ExitCode.USAGE_ERROR);
3734
+ }
3735
+ if (!opts.yes && process.stdin.isTTY && process.stdout.isTTY) {
3736
+ const ok = await confirm(`${DISCLOSURE}
3737
+ Install now? [Y/n] `);
3738
+ if (!ok) {
3739
+ writeConsent({ ...readConsent(), relevance: "denied" });
3740
+ info("not installed");
3741
+ return;
3742
+ }
3743
+ }
3744
+ writeConsent({ ...readConsent(), relevance: "granted" });
3745
+ const result = await installRelevanceModule({ force: opts.force });
3746
+ if (global.json) {
3747
+ json(result);
3748
+ if (result.status === "unavailable") process.exitCode = ExitCode.ERROR;
3749
+ return;
3750
+ }
3751
+ if (result.status === "installed") out(`installed ${RELEVANCE_MODULE_NAME}@${result.version}`);
3752
+ else if (result.status === "already-installed") out(`already installed (${result.version ?? "unknown"}) \u2014 use --force to reinstall`);
3753
+ else throw new CliError(`install failed: ${result.detail ?? result.status} \u2014 check network access to the registry, or retry later`, ExitCode.ERROR);
3754
+ });
3755
+ cmd.command("remove").description("remove an installed module").argument("<name>", "module name (supported: relevance)").action(async function(name) {
3756
+ requireRelevance(name);
3757
+ removeRelevanceModule();
3758
+ out("removed");
3759
+ });
3760
+ cmd.command("status").description("show installed modules and whether they load").action(async function() {
3761
+ const global = readGlobal(this);
3762
+ const installed = moduleInstalled();
3763
+ resetRelevanceProviderCache();
3764
+ const provider = installed.installed ? await loadRelevanceProvider() : null;
3765
+ const status = {
3766
+ relevance: {
3767
+ installed: installed.installed,
3768
+ version: installed.version ?? null,
3769
+ loadable: !!provider,
3770
+ providerVersion: provider ? provider.version() : null,
3771
+ disabled: kernelDisabled(),
3772
+ consent: readConsent().relevance ?? "unset"
3773
+ }
3774
+ };
3775
+ if (global.json) {
3776
+ json(status);
3777
+ return;
3778
+ }
3779
+ const r = status.relevance;
3780
+ out(`relevance: ${r.installed ? `installed ${r.version}` : "not installed"}${r.disabled ? " (disabled via VIBGRATE_NO_KERNEL)" : ""}`);
3781
+ if (r.installed) out(` loads: ${r.loadable ? `yes (${r.providerVersion})` : "no"}`);
3782
+ info(c.dim(` consent: ${r.consent}`));
3783
+ });
3784
+ applyGlobalOptions(cmd);
3785
+ }
3786
+ function requireRelevance(name) {
3787
+ if (name !== "relevance") {
3788
+ throw usageError(`unknown module '${name}' \u2014 supported modules: relevance`);
3789
+ }
3790
+ }
3791
+ function confirm(question) {
3792
+ return new Promise((resolve21) => {
3793
+ const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
3794
+ rl.question(question, (answer) => {
3795
+ rl.close();
3796
+ resolve21(answer.trim() === "" || /^y(es)?$/i.test(answer.trim()));
3797
+ });
3798
+ });
3799
+ }
3800
+ var MAX_HOOK_MATCHES = 5;
3801
+ var MIN_PATTERN_CHARS = 3;
3802
+ function patternToQuery(pattern) {
3803
+ return pattern.replace(/\\[dwsbDWSB]/g, " ").replace(/[\\^$.*+?()[\]{}|]/g, " ").replace(/\s+/g, " ").trim();
3804
+ }
3805
+ function hookContext(payloadText, root2, graphOverride) {
3806
+ let payload;
3807
+ try {
3808
+ payload = JSON.parse(payloadText);
3809
+ } catch {
3810
+ return null;
3811
+ }
3812
+ if (payload.tool_name !== "Grep" && payload.tool_name !== "Glob") return null;
3813
+ const raw = payload.tool_input?.pattern ?? payload.tool_input?.query ?? "";
3814
+ const query = patternToQuery(String(raw));
3815
+ if (query.length < MIN_PATTERN_CHARS) return null;
3816
+ const graphPath = resolveGraphPath(root2, graphOverride);
3817
+ let graph;
3818
+ try {
3819
+ const preferred = loadGraphPreferIndex(root2, graphPath);
3820
+ graph = preferred ? preferred.graph : parseGraph(fs10.readFileSync(graphPath, "utf8"));
3821
+ } catch {
3822
+ return null;
3823
+ }
3824
+ const result = queryGraph(graph, query, {});
3825
+ const matches = result.matches.slice(0, MAX_HOOK_MATCHES);
3826
+ if (!matches.length) return null;
3827
+ const lines = matches.map(
3828
+ (m) => `- \`${m.node.qualifiedName}\` (${m.node.kind}) \u2014 ${m.node.file}:${m.node.span.start}${m.node.isHub ? " [hub \u2014 check impact_of before changing]" : ""}`
3829
+ );
3830
+ return [
3831
+ `vg code map \u2014 symbols matching "${query}":`,
3832
+ ...lines,
3833
+ "These locations come from the deterministic code graph; prefer them over scanning the raw grep output."
3834
+ ].join("\n");
3835
+ }
3836
+ function registerHook(program) {
3837
+ const cmd = program.command("hook", { hidden: true }).description("assistant-host hook endpoints (wired by `vg install --hooks`)");
3838
+ const pre = cmd.command("pre-tool-use").description("PreToolUse enrichment: annotate Grep/Glob calls with graph context (stdin: host hook payload)").action(async function() {
3839
+ const global = readGlobal(this);
3840
+ const root2 = rootOf(global);
3841
+ try {
3842
+ const stdin = fs10.readFileSync(0, "utf8");
3843
+ const context = hookContext(stdin, root2, global.graph);
3844
+ if (context) {
3845
+ process.stdout.write(
3846
+ `${JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: context } })}
3847
+ `
3848
+ );
3849
+ }
3850
+ } catch {
3851
+ }
3852
+ });
3853
+ applyGlobalOptions(pre);
3854
+ applyGlobalOptions(cmd);
3855
+ }
3437
3856
  var HOOK_BEGIN = "# vg:begin";
3438
3857
  var HOOK_END = "# vg:end";
3439
3858
  function registerShare(program) {
3440
3859
  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) {
3441
3860
  const global = readGlobal(this);
3442
3861
  const root2 = rootOf(global);
3443
- const gitDir = path37.join(root2, ".git");
3444
- if (!fs7.existsSync(gitDir)) {
3862
+ const gitDir = path39.join(root2, ".git");
3863
+ if (!fs10.existsSync(gitDir)) {
3445
3864
  throw new CliError("not a git repository \u2014 run `vg share` inside a git repo", ExitCode.USAGE_ERROR);
3446
3865
  }
3447
3866
  if (opts.undo) {
@@ -3462,23 +3881,23 @@ function registerShare(program) {
3462
3881
  applyGlobalOptions(cmd);
3463
3882
  }
3464
3883
  function writeVibgrateGitignore(root2, reports) {
3465
- const dir = path37.join(root2, ".vibgrate");
3466
- fs7.mkdirSync(dir, { recursive: true });
3884
+ const dir = path39.join(root2, ".vibgrate");
3885
+ fs10.mkdirSync(dir, { recursive: true });
3467
3886
  const lines = ["# Managed by `vg share` \u2014 keep graph.json committed, ignore the rest", "cache/", "facts.jsonl", "graph.snap"];
3468
3887
  if (!reports) lines.push("graph.html", "GRAPH_REPORT.md");
3469
- fs7.writeFileSync(path37.join(dir, ".gitignore"), `${lines.join("\n")}
3888
+ fs10.writeFileSync(path39.join(dir, ".gitignore"), `${lines.join("\n")}
3470
3889
  `);
3471
3890
  }
3472
3891
  function writeGitAttributes(root2) {
3473
- const file = path37.join(root2, ".gitattributes");
3892
+ const file = path39.join(root2, ".gitattributes");
3474
3893
  const line = ".vibgrate/graph.json merge=vg";
3475
- let content = fs7.existsSync(file) ? fs7.readFileSync(file, "utf8") : "";
3894
+ let content = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "";
3476
3895
  if (!content.split("\n").some((l) => l.trim() === line)) {
3477
3896
  content = content.length ? `${content.replace(/\s*$/, "")}
3478
3897
  ${line}
3479
3898
  ` : `${line}
3480
3899
  `;
3481
- fs7.writeFileSync(file, content);
3900
+ fs10.writeFileSync(file, content);
3482
3901
  }
3483
3902
  }
3484
3903
  function configureMergeDriver(root2) {
@@ -3487,8 +3906,8 @@ function configureMergeDriver(root2) {
3487
3906
  }
3488
3907
  function installPreCommitHook(root2) {
3489
3908
  const hooksDir = hookDir(root2);
3490
- fs7.mkdirSync(hooksDir, { recursive: true });
3491
- const file = path37.join(hooksDir, "pre-commit");
3909
+ fs10.mkdirSync(hooksDir, { recursive: true });
3910
+ const file = path39.join(hooksDir, "pre-commit");
3492
3911
  const block = [
3493
3912
  HOOK_BEGIN,
3494
3913
  "if command -v vg >/dev/null 2>&1; then",
@@ -3497,7 +3916,7 @@ function installPreCommitHook(root2) {
3497
3916
  "fi",
3498
3917
  HOOK_END
3499
3918
  ].join("\n");
3500
- let content = fs7.existsSync(file) ? fs7.readFileSync(file, "utf8") : "#!/bin/sh\n";
3919
+ let content = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "#!/bin/sh\n";
3501
3920
  const re = new RegExp(`${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}`);
3502
3921
  if (re.test(content)) content = content.replace(re, block);
3503
3922
  else content = `${content.replace(/\s*$/, "")}
@@ -3506,21 +3925,21 @@ ${block}
3506
3925
  `;
3507
3926
  if (!content.startsWith("#!")) content = `#!/bin/sh
3508
3927
  ${content}`;
3509
- fs7.writeFileSync(file, content);
3510
- fs7.chmodSync(file, 493);
3928
+ fs10.writeFileSync(file, content);
3929
+ fs10.chmodSync(file, 493);
3511
3930
  }
3512
3931
  function undo(root2) {
3513
- const hookFile = path37.join(hookDir(root2), "pre-commit");
3514
- if (fs7.existsSync(hookFile)) {
3932
+ const hookFile = path39.join(hookDir(root2), "pre-commit");
3933
+ if (fs10.existsSync(hookFile)) {
3515
3934
  const re = new RegExp(`\\n*${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}\\n*`);
3516
- const next2 = fs7.readFileSync(hookFile, "utf8").replace(re, "\n");
3517
- if (next2.trim() === "#!/bin/sh") fs7.rmSync(hookFile);
3518
- else fs7.writeFileSync(hookFile, next2);
3935
+ const next2 = fs10.readFileSync(hookFile, "utf8").replace(re, "\n");
3936
+ if (next2.trim() === "#!/bin/sh") fs10.rmSync(hookFile);
3937
+ else fs10.writeFileSync(hookFile, next2);
3519
3938
  }
3520
- const attr = path37.join(root2, ".gitattributes");
3521
- if (fs7.existsSync(attr)) {
3522
- const next2 = fs7.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
3523
- fs7.writeFileSync(attr, next2);
3939
+ const attr = path39.join(root2, ".gitattributes");
3940
+ if (fs10.existsSync(attr)) {
3941
+ const next2 = fs10.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
3942
+ fs10.writeFileSync(attr, next2);
3524
3943
  }
3525
3944
  try {
3526
3945
  git(root2, ["config", "--remove-section", "merge.vg"]);
@@ -3530,10 +3949,10 @@ function undo(root2) {
3530
3949
  function hookDir(root2) {
3531
3950
  try {
3532
3951
  const configured = git(root2, ["config", "--get", "core.hooksPath"]).trim();
3533
- if (configured) return path37.resolve(root2, configured);
3952
+ if (configured) return path39.resolve(root2, configured);
3534
3953
  } catch {
3535
3954
  }
3536
- return path37.join(root2, ".git", "hooks");
3955
+ return path39.join(root2, ".git", "hooks");
3537
3956
  }
3538
3957
  function git(root2, args) {
3539
3958
  return execFileSync("git", args, { cwd: root2, encoding: "utf8" });
@@ -3542,28 +3961,14 @@ function escapeRe(s) {
3542
3961
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3543
3962
  }
3544
3963
  var DEFAULT_DEBOUNCE_MS = 400;
3545
- var SKIP_NAME = /* @__PURE__ */ new Set([
3546
- ".git",
3547
- "node_modules",
3548
- ".vibgrate",
3549
- "dist",
3550
- "build",
3551
- "out",
3552
- "coverage",
3553
- ".next",
3554
- "target",
3555
- "__pycache__",
3556
- ".venv",
3557
- "venv"
3558
- ]);
3559
3964
  function registerWatch(program) {
3560
3965
  const cmd = program.command("watch").description("rebuild the code map when files change (debounced)").argument("[paths...]", "folders to watch (default: current folder)").option("--debounce <ms>", "settle time after a change before rebuild", String(DEFAULT_DEBOUNCE_MS)).option("--no-html", "do not write graph.html on each rebuild").option("--no-report", "do not write GRAPH_REPORT.md on each rebuild").option("--fast", "skip precise tsc resolve on rebuilds (heuristic only)").action(async function(paths, opts) {
3561
3966
  const global = readGlobal(this);
3562
3967
  const root2 = rootOf(global);
3563
3968
  const debounceMs = Math.max(50, Number(opts.debounce) || DEFAULT_DEBOUNCE_MS);
3564
- const watchRoots = (paths.length ? paths : ["."]).map((p) => path37.resolve(root2, p));
3969
+ const watchRoots = (paths.length ? paths : ["."]).map((p) => path39.resolve(root2, p));
3565
3970
  for (const w of watchRoots) {
3566
- if (!fs7.existsSync(w)) {
3971
+ if (!fs10.existsSync(w)) {
3567
3972
  throw new CliError(`watch path not found: ${w}`, ExitCode.USAGE_ERROR);
3568
3973
  }
3569
3974
  }
@@ -3616,16 +4021,12 @@ function registerWatch(program) {
3616
4021
  const watchers = [];
3617
4022
  for (const w of watchRoots) {
3618
4023
  try {
3619
- const watcher = fs7.watch(w, { recursive: true }, (_event, filename) => {
4024
+ const watcher = fs10.watch(w, { recursive: true }, (_event, filename) => {
3620
4025
  if (!filename) {
3621
4026
  schedule("change");
3622
4027
  return;
3623
4028
  }
3624
- const parts = filename.split(path37.sep);
3625
- if (parts.some((p) => SKIP_NAME.has(p))) return;
3626
- if (filename.includes(`${path37.sep}.vibgrate${path37.sep}`) || filename.startsWith(".vibgrate")) {
3627
- return;
3628
- }
4029
+ if (!isRelevantChange(filename)) return;
3629
4030
  schedule(filename);
3630
4031
  });
3631
4032
  watchers.push(watcher);
@@ -3633,7 +4034,7 @@ function registerWatch(program) {
3633
4034
  throw new CliError(`cannot watch ${w}: ${err.message}`, ExitCode.ERROR);
3634
4035
  }
3635
4036
  }
3636
- info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path37.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
4037
+ info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path39.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
3637
4038
  await new Promise((resolve21) => {
3638
4039
  const stop = () => {
3639
4040
  for (const w of watchers) w.close();
@@ -3966,10 +4367,10 @@ function normalizeStandards(raw) {
3966
4367
  }
3967
4368
  function loadStandards(root2) {
3968
4369
  for (const rel of STANDARDS_FILES) {
3969
- const p = path37__default.join(root2, rel);
4370
+ const p = path39__default.join(root2, rel);
3970
4371
  let text;
3971
4372
  try {
3972
- text = fs7__default.readFileSync(p, "utf8");
4373
+ text = fs10__default.readFileSync(p, "utf8");
3973
4374
  } catch {
3974
4375
  continue;
3975
4376
  }
@@ -4687,8 +5088,8 @@ async function runHostBench(options = {}) {
4687
5088
  }
4688
5089
  async function runArmSimulate(input) {
4689
5090
  const { arm, lib, modelPath, turns, trie, env, live } = input;
4690
- const path39 = `${modelPath}#${arm.id}`;
4691
- const session = await acquireHostSession(lib, path39);
5091
+ const path41 = `${modelPath}#${arm.id}`;
5092
+ const session = await acquireHostSession(lib, path41);
4692
5093
  const system = "You are a coding agent with a Task Capsule.";
4693
5094
  const capsule = "function readConfig(): Config { return load(); }";
4694
5095
  let last = null;
@@ -5900,7 +6301,7 @@ function registerModels(program) {
5900
6301
  );
5901
6302
  }
5902
6303
  } else {
5903
- if (!target.path || !fs7.existsSync(target.path)) {
6304
+ if (!target.path || !fs10.existsSync(target.path)) {
5904
6305
  throw new CliError(
5905
6306
  `model file not found at ${target.path || "(unknown path)"} \u2014 it may already be removed.`,
5906
6307
  ExitCode.NOT_FOUND
@@ -5914,7 +6315,7 @@ function registerModels(program) {
5914
6315
  }
5915
6316
  if (!global.json) info(c.dim(` $ rm ${target.path}`));
5916
6317
  try {
5917
- fs7.unlinkSync(target.path);
6318
+ fs10.unlinkSync(target.path);
5918
6319
  } catch (e) {
5919
6320
  const msg = e instanceof Error ? e.message : String(e);
5920
6321
  throw new CliError(`could not delete ${target.path}: ${msg}`, ExitCode.ERROR);
@@ -6052,9 +6453,9 @@ function registerModels(program) {
6052
6453
  }
6053
6454
  });
6054
6455
  if (opts.out) {
6055
- const outPath = path37.resolve(opts.out);
6056
- fs7.mkdirSync(path37.dirname(outPath), { recursive: true });
6057
- fs7.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
6456
+ const outPath = path39.resolve(opts.out);
6457
+ fs10.mkdirSync(path39.dirname(outPath), { recursive: true });
6458
+ fs10.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
6058
6459
  `);
6059
6460
  if (!global.json) info(c.dim(` wrote ${outPath}`));
6060
6461
  }
@@ -6203,14 +6604,14 @@ function resolveUninstallTarget(name, runtimeOpt) {
6203
6604
  }
6204
6605
  return exact[0];
6205
6606
  }
6206
- const base = path37.basename(wantLc);
6607
+ const base = path39.basename(wantLc);
6207
6608
  const soft = fleet.filter((m) => {
6208
6609
  const n = m.name.toLowerCase();
6209
- return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) || path37.basename(n) === base;
6610
+ return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) || path39.basename(n) === base;
6210
6611
  });
6211
6612
  if (soft.length === 1) return soft[0];
6212
6613
  if (soft.length > 1) {
6213
- const baseHits = soft.filter((m) => path37.basename(m.name).toLowerCase() === base);
6614
+ const baseHits = soft.filter((m) => path39.basename(m.name).toLowerCase() === base);
6214
6615
  const pool = baseHits.length ? baseHits : soft;
6215
6616
  const order = ["ollama", "gguf", "lm-studio"];
6216
6617
  for (const rt of order) {
@@ -6248,11 +6649,11 @@ function printBackends(backends) {
6248
6649
  }
6249
6650
  }
6250
6651
  function codeConfigPath(root2) {
6251
- return path37.join(root2, ".vibgrate", "code.json");
6652
+ return path39.join(root2, ".vibgrate", "code.json");
6252
6653
  }
6253
6654
  function loadCodeConfig(root2) {
6254
6655
  try {
6255
- const raw = JSON.parse(fs7.readFileSync(codeConfigPath(root2), "utf8"));
6656
+ const raw = JSON.parse(fs10.readFileSync(codeConfigPath(root2), "utf8"));
6256
6657
  return sanitize(raw);
6257
6658
  } catch {
6258
6659
  return {};
@@ -6319,7 +6720,7 @@ function contextBudgetFor(config, modelContextWindow) {
6319
6720
  var MCP_CONFIG_FILES = [".cursor/mcp.json", ".vscode/mcp.json", ".mcp.json"];
6320
6721
  function readMcpServersFile(file) {
6321
6722
  try {
6322
- const raw = JSON.parse(fs7.readFileSync(file, "utf8"));
6723
+ const raw = JSON.parse(fs10.readFileSync(file, "utf8"));
6323
6724
  const map = raw.mcpServers ?? raw.servers;
6324
6725
  return map && typeof map === "object" ? parseMcpServers(map) : {};
6325
6726
  } catch {
@@ -6330,7 +6731,7 @@ function discoverMcpServers(root2, ownServers) {
6330
6731
  const servers = {};
6331
6732
  const sources = [];
6332
6733
  for (const rel of MCP_CONFIG_FILES) {
6333
- const found = readMcpServersFile(path37.join(root2, rel));
6734
+ const found = readMcpServersFile(path39.join(root2, rel));
6334
6735
  const names = Object.keys(found);
6335
6736
  if (names.length) {
6336
6737
  sources.push(rel);
@@ -6349,6 +6750,9 @@ function registerCode(program) {
6349
6750
  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) {
6350
6751
  const global = readGlobal(this);
6351
6752
  const instruction = (instructionParts ?? []).join(" ").trim();
6753
+ if (!global.local) {
6754
+ await ensureRelevanceModule();
6755
+ }
6352
6756
  const config = loadCodeConfig(rootOf(global));
6353
6757
  let provider = opts.provider ?? config.provider;
6354
6758
  let model = opts.model ?? config.model;
@@ -6359,7 +6763,7 @@ function registerCode(program) {
6359
6763
  try {
6360
6764
  const { parseMode: parseMode2, resolveMode: resolveMode2, readOrchestratorState: readOrchestratorState2, activePin: activePin2 } = await import('./model-orchestrator-LHYPJBFH.js');
6361
6765
  const { gatherSystemMemory: gatherSystemMemory2 } = await import('./local-runtime-2ED33KK6.js');
6362
- const { loadGraph: loadGraph2 } = await import('./load-E3OTM7BS.js');
6766
+ const { loadGraph: loadGraph2 } = await import('./load-T2FOJUPI.js');
6363
6767
  const state = readOrchestratorState2();
6364
6768
  const mode = parseMode2(modeFlag) ?? state.defaultMode ?? void 0;
6365
6769
  const pin = mode ? activePin2(mode, state) : null;
@@ -6439,11 +6843,12 @@ function registerCode(program) {
6439
6843
  const verifyCommand = opts.verify === true ? config.testCommand : typeof opts.verify === "string" ? opts.verify : void 0;
6440
6844
  const verify3 = verifyCommand ? { command: verifyCommand } : void 0;
6441
6845
  const mcp = discoverMcpServers(rootOf(global), config.mcpServers);
6442
- if (!instruction && !opts.mock) {
6846
+ const stdinFirstTurn = !instruction && !!opts.streamJson && !!opts.session;
6847
+ if (!instruction && !opts.mock && !stdinFirstTurn) {
6443
6848
  if (!(process.stdin.isTTY && process.stdout.isTTY)) {
6444
6849
  throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"` (guided mode needs an interactive terminal)');
6445
6850
  }
6446
- const { runInteractive } = await import('./interactive-TMQR6TXM.js');
6851
+ const { runInteractive } = await import('./interactive-6PN237LX.js');
6447
6852
  await runInteractive(
6448
6853
  rootOf(global),
6449
6854
  global,
@@ -6471,9 +6876,9 @@ function registerCode(program) {
6471
6876
  );
6472
6877
  return;
6473
6878
  }
6474
- if (!instruction) throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"`');
6879
+ if (!instruction && !stdinFirstTurn) throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"`');
6475
6880
  {
6476
- const { ensureCodeMap } = await import('./ensure-map-SMWHKOUY.js');
6881
+ const { ensureCodeMap } = await import('./ensure-map-TAVYMPEG.js');
6477
6882
  const mapRoot = rootOf(global);
6478
6883
  try {
6479
6884
  await ensureCodeMap(mapRoot, global, {
@@ -6510,7 +6915,7 @@ function registerCode(program) {
6510
6915
  let mockReply;
6511
6916
  if (opts.mock) {
6512
6917
  try {
6513
- mockReply = fs7.readFileSync(opts.mock, "utf8");
6918
+ mockReply = fs10.readFileSync(opts.mock, "utf8");
6514
6919
  } catch {
6515
6920
  throw new CliError(`couldn't read the --mock file: ${opts.mock}`, ExitCode.USAGE_ERROR);
6516
6921
  }
@@ -6558,20 +6963,20 @@ function registerCode(program) {
6558
6963
  process.stdout.write(JSON.stringify(line) + "\n");
6559
6964
  };
6560
6965
  try {
6561
- const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-QWLNBASF.js');
6966
+ const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-AMIKAASL.js');
6562
6967
  const primarySlug = route.providers[0]?.model.includes("/") ? route.providers[0].model.split("/")[0] : route.providers[0]?.id;
6563
- const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-GM44SP7L.js');
6564
- const { nodeCodeFs } = await import('./session-MG6BJVAG.js');
6565
- const readline5 = await import('readline');
6968
+ const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-A6K2MONY.js');
6969
+ const { nodeCodeFs } = await import('./session-SCHQQTHN.js');
6970
+ const readline6 = await import('readline');
6566
6971
  const child = await import('child_process');
6567
6972
  const { loadOrDiscoverFederation } = await import('./federation-MDQPO3PW.js');
6568
6973
  const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
6569
6974
  const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
6570
- const { startCodeRuntimeSession } = await import('./runtime-session-UQ7UVAPL.js');
6571
- const { resolveGraphBackend } = await import('./graph-backend-I4I72J4W.js');
6975
+ const { startCodeRuntimeSession } = await import('./runtime-session-QAVOPSSH.js');
6976
+ const { resolveGraphBackend } = await import('./graph-backend-WF4LGBGD.js');
6572
6977
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
6573
6978
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
6574
- const { vgdRequest: vgdRequest2 } = await import('./vgd-ZUSBEVUL.js');
6979
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-B67JCNJP.js');
6575
6980
  const federation = loadOrDiscoverFederation(root2);
6576
6981
  const modelProfile = mergeModelExecutionProfile(
6577
6982
  resolveModelExecutionProfile({
@@ -6629,7 +7034,7 @@ ${res.stderr}` : ""),
6629
7034
  exitCode: res.status ?? 1
6630
7035
  };
6631
7036
  };
6632
- const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-3WFC7LGE.js');
7037
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-3TSFOL4V.js');
6633
7038
  const vgBuiltin = createVgBuiltinMcpTools({
6634
7039
  getGraph: () => graph,
6635
7040
  root: root2,
@@ -6653,7 +7058,7 @@ ${res.stderr}` : ""),
6653
7058
  const os4 = await import('os');
6654
7059
  const pathMod = await import('path');
6655
7060
  const checkpointIndex = pathMod.join(
6656
- fs7.mkdtempSync(pathMod.join(os4.tmpdir(), "vg-code-cp-")),
7061
+ fs10.mkdtempSync(pathMod.join(os4.tmpdir(), "vg-code-cp-")),
6657
7062
  "index"
6658
7063
  );
6659
7064
  const gitRunner = (gitArgs, gitEnv) => {
@@ -6703,6 +7108,8 @@ ${res.stderr}` : ""),
6703
7108
  capsule,
6704
7109
  files: opts.file.length ? opts.file : void 0,
6705
7110
  worktreeOverlay: true,
7111
+ // Real-model host: compaction writes a model checkpoint summary.
7112
+ llmCompaction: true,
6706
7113
  // Full coding agent: free discovery by default. Capsule is context only.
6707
7114
  advancedMode: true,
6708
7115
  externalTools,
@@ -6717,15 +7124,16 @@ ${res.stderr}` : ""),
6717
7124
  };
6718
7125
  try {
6719
7126
  if (opts.session) {
6720
- const { runCodeStreamJsonSession } = await import('./stream-json-GM44SP7L.js');
6721
- const { runAgent: runAgent2 } = await import('./agent-4DAECASW.js');
7127
+ const { runCodeStreamJsonSession } = await import('./stream-json-A6K2MONY.js');
7128
+ const { runAgent: runAgent2 } = await import('./agent-JTA4YWMQ.js');
6722
7129
  const {
7130
+ condenseSession,
6723
7131
  loadLatestSession,
6724
7132
  newSession,
6725
7133
  recordTask,
6726
7134
  saveSession,
6727
7135
  summarizeSession
6728
- } = await import('./session-store-SQECEXUU.js');
7136
+ } = await import('./session-store-F7NX7SZN.js');
6729
7137
  const resumedRecord = opts.continue ? loadLatestSession(root2) : void 0;
6730
7138
  let record = resumedRecord ?? newSession(
6731
7139
  `s${Date.now().toString(36)}`,
@@ -6736,13 +7144,13 @@ ${res.stderr}` : ""),
6736
7144
  const pendingTurns = [];
6737
7145
  let wakeTurn;
6738
7146
  let ended = false;
6739
- const pushTurn = (instruction2) => {
7147
+ const pushTurn = (turn) => {
6740
7148
  if (wakeTurn) {
6741
7149
  const wake = wakeTurn;
6742
7150
  wakeTurn = void 0;
6743
- wake(instruction2);
6744
- } else if (instruction2 !== null) {
6745
- pendingTurns.push(instruction2);
7151
+ wake(turn);
7152
+ } else if (turn !== null) {
7153
+ pendingTurns.push(turn);
6746
7154
  }
6747
7155
  };
6748
7156
  const nextTurn = () => {
@@ -6763,7 +7171,7 @@ ${res.stderr}` : ""),
6763
7171
  nextTurn,
6764
7172
  bindDecisions: (session) => {
6765
7173
  streamApprove = (action) => session.approve(action);
6766
- const rl = readline5.createInterface({ input: process.stdin });
7174
+ const rl = readline6.createInterface({ input: process.stdin });
6767
7175
  rl.on("line", (raw) => {
6768
7176
  const msg = parseHostMessage(raw);
6769
7177
  if (!msg) return;
@@ -6771,7 +7179,8 @@ ${res.stderr}` : ""),
6771
7179
  session.submitDecision(msg.id, msg.approve);
6772
7180
  runOutcome.noteDecision(msg.id, msg.approve);
6773
7181
  } else if (msg.kind === "answer") session.submitAnswer(msg.id, msg.answer);
6774
- else if (msg.kind === "submit") pushTurn(msg.instruction);
7182
+ else if (msg.kind === "submit")
7183
+ pushTurn({ instruction: msg.instruction, agentMode: msg.agentMode, images: msg.images });
6775
7184
  else if (msg.kind === "restore") {
6776
7185
  void import('./checkpoint-4WFZMKEO.js').then(({ restoreCheckpoint }) => {
6777
7186
  const outcome = restoreCheckpoint(gitRunner, {
@@ -6780,6 +7189,14 @@ ${res.stderr}` : ""),
6780
7189
  });
6781
7190
  emitStream({ event: "checkpoint-restored", commit: msg.commit, ...outcome });
6782
7191
  });
7192
+ } else if (msg.kind === "compact") {
7193
+ record = condenseSession(record, Date.now());
7194
+ saveSession(root2, record);
7195
+ emitStream({
7196
+ event: "event",
7197
+ type: "notice",
7198
+ text: "Conversation compacted \u2014 earlier turns condensed into a checkpoint."
7199
+ });
6783
7200
  } else if (msg.kind === "cancel") {
6784
7201
  session.cancelTurn();
6785
7202
  runOutcome.cancelPending();
@@ -6795,14 +7212,24 @@ ${res.stderr}` : ""),
6795
7212
  pushTurn(null);
6796
7213
  });
6797
7214
  },
6798
- runTurn: ({ instruction: turnInstruction, priorSummary, signal, session }) => {
7215
+ runTurn: ({ instruction: turnInstruction, signal, session, agentMode, auto: turnAuto, images }) => {
7216
+ const priorSummary = summarizeSession(record) || void 0;
6799
7217
  turnIndex++;
6800
7218
  runOutcome.beginRun(turnRunId(record.id, turnIndex), turnInstruction);
7219
+ const plan = agentMode === "plan";
7220
+ streamApprove = plan ? async () => false : (action) => session.approve(action);
6801
7221
  return runAgent2({
6802
7222
  ...baseAgentOptions,
6803
7223
  instruction: turnInstruction,
6804
7224
  priorSummary,
7225
+ // Carry-over for capsule seed ranking: the previous
7226
+ // turn's instruction (the current turn is recorded only
7227
+ // in onTurnEnd, so .at(-1) is the prior ask).
7228
+ priorInstruction: record.tasks.at(-1)?.instruction,
6805
7229
  signal,
7230
+ auto: turnAuto,
7231
+ plan,
7232
+ images,
6806
7233
  approve: session.approve,
6807
7234
  askUser: session.askUser,
6808
7235
  onEvent: session.onEvent
@@ -6831,7 +7258,7 @@ ${res.stderr}` : ""),
6831
7258
  emit: emitAndRecord,
6832
7259
  bindDecisions: (session) => {
6833
7260
  streamApprove = (action) => session.approve(action);
6834
- const rl = readline5.createInterface({ input: process.stdin });
7261
+ const rl = readline6.createInterface({ input: process.stdin });
6835
7262
  rl.on("line", (raw) => {
6836
7263
  const msg = parseHostMessage(raw);
6837
7264
  if (!msg) return;
@@ -6866,17 +7293,21 @@ ${res.stderr}` : ""),
6866
7293
  if (!autonomous && !tty) {
6867
7294
  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).");
6868
7295
  }
6869
- const { agentTask } = await import('./interactive-TMQR6TXM.js');
6870
- const { nodeCodeFs } = await import('./session-MG6BJVAG.js');
7296
+ const { agentTask } = await import('./interactive-6PN237LX.js');
7297
+ const { nodeCodeFs } = await import('./session-SCHQQTHN.js');
6871
7298
  const { TtyPrompter } = await import('./ui-K7D3BCHD.js');
6872
7299
  let priorSummary;
7300
+ let priorInstruction;
6873
7301
  if (opts.continue) {
6874
- const { loadLatestSession, summarizeSession } = await import('./session-store-SQECEXUU.js');
7302
+ const { loadLatestSession, summarizeSession } = await import('./session-store-F7NX7SZN.js');
6875
7303
  const prev = loadLatestSession(root2);
6876
- if (prev) priorSummary = summarizeSession(prev);
7304
+ if (prev) {
7305
+ priorSummary = summarizeSession(prev);
7306
+ priorInstruction = prev.tasks.at(-1)?.instruction;
7307
+ }
6877
7308
  }
6878
7309
  const prompter = tty ? new TtyPrompter() : void 0;
6879
- const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-3WFC7LGE.js');
7310
+ const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-3TSFOL4V.js');
6880
7311
  const vgBuiltin = createVgBuiltinMcpTools({
6881
7312
  getGraph: () => graph,
6882
7313
  root: root2,
@@ -6900,11 +7331,11 @@ ${res.stderr}` : ""),
6900
7331
  const { loadFederation } = await import('./federation-MDQPO3PW.js');
6901
7332
  const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
6902
7333
  const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
6903
- const { startCodeRuntimeSession } = await import('./runtime-session-UQ7UVAPL.js');
6904
- const { resolveGraphBackend } = await import('./graph-backend-I4I72J4W.js');
7334
+ const { startCodeRuntimeSession } = await import('./runtime-session-QAVOPSSH.js');
7335
+ const { resolveGraphBackend } = await import('./graph-backend-WF4LGBGD.js');
6905
7336
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
6906
7337
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
6907
- const { vgdRequest: vgdRequest2 } = await import('./vgd-ZUSBEVUL.js');
7338
+ const { vgdRequest: vgdRequest2 } = await import('./vgd-B67JCNJP.js');
6908
7339
  const federation = loadFederation(root2);
6909
7340
  const modelProfile = mergeModelExecutionProfile(
6910
7341
  resolveModelExecutionProfile({
@@ -6954,13 +7385,15 @@ ${res.stderr}` : ""),
6954
7385
  stream: opts.stream,
6955
7386
  verify: verify3 ? { command: verify3.command, maxRounds: modelProfile.maxRepairRounds } : void 0,
6956
7387
  priorSummary,
7388
+ priorInstruction,
6957
7389
  externalTools: mcpTools,
6958
7390
  prompter,
6959
7391
  capsule,
6960
7392
  files: opts.file.length ? opts.file : void 0,
6961
7393
  executionEnv,
6962
7394
  graphBackend,
6963
- modelProfile
7395
+ modelProfile,
7396
+ llmCompaction: true
6964
7397
  });
6965
7398
  if (global.json) json(agentResult);
6966
7399
  if (agentResult.stopped === "error") process.exitCode = ExitCode.ERROR;
@@ -6974,7 +7407,7 @@ ${res.stderr}` : ""),
6974
7407
  }
6975
7408
  let consent = !!opts.yes;
6976
7409
  if (opts.apply && !consent && process.stdin.isTTY && process.stdout.isTTY) {
6977
- consent = await confirm(`Apply the proposed change to ${root2}?`);
7410
+ consent = await confirm2(`Apply the proposed change to ${root2}?`);
6978
7411
  }
6979
7412
  const onPhase = (phase, detail) => {
6980
7413
  if (!global.json && !global.quiet) info(c.dim(` ${phase}: ${detail}`));
@@ -6996,7 +7429,7 @@ ${res.stderr}` : ""),
6996
7429
  attribution: { client: "vg-code", provider: providerSlug, model: primary?.model }
6997
7430
  });
6998
7431
  if (opts.out) {
6999
- fs7.writeFileSync(opts.out, JSON.stringify(result, null, 2) + "\n");
7432
+ fs10.writeFileSync(opts.out, JSON.stringify(result, null, 2) + "\n");
7000
7433
  }
7001
7434
  if (global.json) {
7002
7435
  json(result);
@@ -7047,7 +7480,7 @@ function resolveSecurityTierFlag(flag, fromConfig, auto) {
7047
7480
  if (fromConfig) return fromConfig;
7048
7481
  return auto ? "L1" : "L0";
7049
7482
  }
7050
- function confirm(question) {
7483
+ function confirm2(question) {
7051
7484
  return new Promise((resolve21) => {
7052
7485
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
7053
7486
  rl.question(`${question} [y/N] `, (answer) => {
@@ -7209,7 +7642,7 @@ async function addCmd(root2, rest, opts, asJson) {
7209
7642
  }
7210
7643
  function readPackageVersion(root2) {
7211
7644
  try {
7212
- const pkg = JSON.parse(fs7__default.readFileSync(path37__default.join(root2, "package.json"), "utf8"));
7645
+ const pkg = JSON.parse(fs10__default.readFileSync(path39__default.join(root2, "package.json"), "utf8"));
7213
7646
  return typeof pkg.version === "string" ? pkg.version : void 0;
7214
7647
  } catch {
7215
7648
  return void 0;
@@ -7217,7 +7650,7 @@ function readPackageVersion(root2) {
7217
7650
  }
7218
7651
  function readOptionalFile(p) {
7219
7652
  try {
7220
- const t = fs7__default.readFileSync(p, "utf8");
7653
+ const t = fs10__default.readFileSync(p, "utf8");
7221
7654
  return t.trim() ? t : void 0;
7222
7655
  } catch {
7223
7656
  return void 0;
@@ -7232,8 +7665,8 @@ async function publishCmd(root2, rest, opts, global, asJson) {
7232
7665
  if (!parsed) throw new CliError("publishing a private library requires a DSN \u2014 run `vibgrate login` or set VIBGRATE_DSN", ExitCode.USAGE_ERROR);
7233
7666
  const version = (opts.version || readPackageVersion(root2) || "").trim();
7234
7667
  if (!version) throw usageError("a --version is required (or run from a package whose package.json has a version)");
7235
- const readme = readOptionalFile(opts.readme ? path37__default.resolve(opts.readme) : path37__default.join(root2, "README.md"));
7236
- const dts = opts.dts ? readOptionalFile(path37__default.resolve(opts.dts)) : void 0;
7668
+ const readme = readOptionalFile(opts.readme ? path39__default.resolve(opts.readme) : path39__default.join(root2, "README.md"));
7669
+ const dts = opts.dts ? readOptionalFile(path39__default.resolve(opts.dts)) : void 0;
7237
7670
  if (!readme && !dts) throw usageError("nothing to publish \u2014 no README.md found and no --dts given");
7238
7671
  const result = await publishPrivateLibrary(
7239
7672
  { name, version, readme, dts, language: opts.language },
@@ -7365,8 +7798,8 @@ function registerExport(program) {
7365
7798
  out(content.trimEnd());
7366
7799
  return;
7367
7800
  }
7368
- fs7.mkdirSync(path37.dirname(path37.resolve(file)), { recursive: true });
7369
- fs7.writeFileSync(file, content);
7801
+ fs10.mkdirSync(path39.dirname(path39.resolve(file)), { recursive: true });
7802
+ fs10.writeFileSync(file, content);
7370
7803
  info(`${c.green("\u2714")} wrote ${file} ${c.dim(`(${format})`)}`);
7371
7804
  });
7372
7805
  applyGlobalOptions(cmd);
@@ -7376,43 +7809,43 @@ function detectFormat(file) {
7376
7809
  if (lower.endsWith(".cdx.json")) return "cyclonedx";
7377
7810
  if (lower.endsWith(".spdx.json")) return "spdx";
7378
7811
  if (file === "-") return "json";
7379
- return formatForExt(path37.extname(file));
7812
+ return formatForExt(path39.extname(file));
7380
7813
  }
7381
7814
  function registerBundle(program) {
7382
7815
  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) {
7383
7816
  const global = readGlobal(this);
7384
7817
  const root2 = rootOf(global);
7385
- const outDir = path37.resolve(root2, opts.out ?? "vg-bundle");
7818
+ const outDir = path39.resolve(root2, opts.out ?? "vg-bundle");
7386
7819
  let grammarFiles;
7387
7820
  try {
7388
7821
  grammarFiles = resolvedGrammarFiles();
7389
7822
  } catch {
7390
7823
  throw new CliError("no grammars found to bundle (run a build first)", ExitCode.ERROR);
7391
7824
  }
7392
- fs7.mkdirSync(path37.join(outDir, "grammars"), { recursive: true });
7825
+ fs10.mkdirSync(path39.join(outDir, "grammars"), { recursive: true });
7393
7826
  let grammarCount = 0;
7394
7827
  for (const { fileName, absPath } of grammarFiles) {
7395
- fs7.copyFileSync(absPath, path37.join(outDir, "grammars", fileName));
7828
+ fs10.copyFileSync(absPath, path39.join(outDir, "grammars", fileName));
7396
7829
  grammarCount++;
7397
7830
  }
7398
7831
  const included = [`grammars/ (${grammarCount} .wasm)`];
7399
7832
  const graphSrc = resolveGraphPath(root2, global.graph);
7400
- if (fs7.existsSync(graphSrc)) {
7401
- fs7.copyFileSync(graphSrc, path37.join(outDir, "graph.json"));
7833
+ if (fs10.existsSync(graphSrc)) {
7834
+ fs10.copyFileSync(graphSrc, path39.join(outDir, "graph.json"));
7402
7835
  included.push("graph.json");
7403
7836
  } else {
7404
7837
  const graph = loadGraphFileWithSnapshot(graphSrc);
7405
7838
  if (graph) {
7406
- fs7.writeFileSync(path37.join(outDir, "graph.json"), serializeGraph(graph));
7839
+ fs10.writeFileSync(path39.join(outDir, "graph.json"), serializeGraph(graph));
7407
7840
  included.push("graph.json");
7408
7841
  }
7409
7842
  }
7410
7843
  const cat = catalogPath(root2);
7411
- if (fs7.existsSync(cat)) {
7412
- fs7.copyFileSync(cat, path37.join(outDir, "vibgrate.lib.json"));
7844
+ if (fs10.existsSync(cat)) {
7845
+ fs10.copyFileSync(cat, path39.join(outDir, "vibgrate.lib.json"));
7413
7846
  included.push("vibgrate.lib.json");
7414
- if (fs7.existsSync(libDir(root2))) {
7415
- fs7.cpSync(libDir(root2), path37.join(outDir, "lib"), { recursive: true });
7847
+ if (fs10.existsSync(libDir(root2))) {
7848
+ fs10.cpSync(libDir(root2), path39.join(outDir, "lib"), { recursive: true });
7416
7849
  included.push("lib/");
7417
7850
  }
7418
7851
  }
@@ -7424,15 +7857,15 @@ function registerBundle(program) {
7424
7857
  included,
7425
7858
  usage: "Run `vg build --grammars <this dir>/grammars` to build fully offline."
7426
7859
  };
7427
- fs7.writeFileSync(path37.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
7860
+ fs10.writeFileSync(path39.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
7428
7861
  `);
7429
7862
  if (global.json) {
7430
- json({ out: path37.relative(root2, outDir), ...manifest });
7863
+ json({ out: path39.relative(root2, outDir), ...manifest });
7431
7864
  return;
7432
7865
  }
7433
- info(`${c.cyan("vg bundle")} \xB7 wrote ${path37.relative(root2, outDir)}/`);
7866
+ info(`${c.cyan("vg bundle")} \xB7 wrote ${path39.relative(root2, outDir)}/`);
7434
7867
  for (const i of included) info(` ${c.green("\u2714")} ${i}`);
7435
- info(c.dim(` offline: vg build --grammars "${path37.relative(root2, outDir)}/grammars"`));
7868
+ info(c.dim(` offline: vg build --grammars "${path39.relative(root2, outDir)}/grammars"`));
7436
7869
  });
7437
7870
  applyGlobalOptions(cmd);
7438
7871
  }
@@ -7450,7 +7883,7 @@ async function runDoctor(global) {
7450
7883
  const root2 = rootOf(global);
7451
7884
  const local = global.local === true;
7452
7885
  const graphPath = resolveGraphPath(root2, global.graph);
7453
- const configFile = CONFIG_BASENAMES.find((f) => fs7.existsSync(path37.join(root2, f))) ?? null;
7886
+ const configFile = CONFIG_BASENAMES.find((f) => fs10.existsSync(path39.join(root2, f))) ?? null;
7454
7887
  const graph = loadGraph(root2, graphPath);
7455
7888
  let staleFiles = null;
7456
7889
  if (graph) {
@@ -7476,14 +7909,14 @@ async function runDoctor(global) {
7476
7909
  root: root2,
7477
7910
  configFile,
7478
7911
  map: {
7479
- path: path37.relative(root2, graphPath),
7912
+ path: path39.relative(root2, graphPath),
7480
7913
  built: graph !== null,
7481
7914
  generatedAt: graph?.generatedAt ?? null,
7482
7915
  staleFiles
7483
7916
  },
7484
7917
  libCatalog: {
7485
- path: path37.relative(root2, catalogPath(root2)),
7486
- present: fs7.existsSync(catalogPath(root2)),
7918
+ path: path39.relative(root2, catalogPath(root2)),
7919
+ present: fs10.existsSync(catalogPath(root2)),
7487
7920
  libraries: libCount
7488
7921
  },
7489
7922
  credentials: creds,
@@ -7540,7 +7973,7 @@ async function runDoctor(global) {
7540
7973
  );
7541
7974
  info(
7542
7975
  ` host pool ${li.hostPool.size} warm session(s)` + (li.hostPool.sessions[0] ? c.dim(
7543
- ` \xB7 last ${path37.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
7976
+ ` \xB7 last ${path39.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
7544
7977
  ) : c.dim(" \xB7 none (load via vg code / vgd host-load)"))
7545
7978
  );
7546
7979
  if (li.dynamicOnToken || li.dynamicCustomSampler) {
@@ -7716,7 +8149,7 @@ function registerDaemon(program) {
7716
8149
  const register = cmd.command("register").description("register the current repository with a running vgd").argument("[root]", "repository root (default: cwd)").action(async function(rootArg) {
7717
8150
  const global = readGlobal(this);
7718
8151
  const socketPath = socketOf(this);
7719
- const root2 = path37.resolve(rootArg ?? rootOf(global));
8152
+ const root2 = path39.resolve(rootArg ?? rootOf(global));
7720
8153
  if (!await vgdIsRunning({ socketPath })) {
7721
8154
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
7722
8155
  }
@@ -7752,7 +8185,7 @@ function registerDaemon(program) {
7752
8185
  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) {
7753
8186
  const global = readGlobal(this);
7754
8187
  const socketPath = socketOf(this);
7755
- const primary = path37.resolve(rootArg ?? rootOf(global));
8188
+ const primary = path39.resolve(rootArg ?? rootOf(global));
7756
8189
  if (!await vgdIsRunning({ socketPath })) {
7757
8190
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
7758
8191
  }
@@ -7780,7 +8213,7 @@ function registerDaemon(program) {
7780
8213
  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) {
7781
8214
  const global = readGlobal(this);
7782
8215
  const socketPath = socketOf(this);
7783
- const root2 = path37.resolve(rootArg ?? rootOf(global));
8216
+ const root2 = path39.resolve(rootArg ?? rootOf(global));
7784
8217
  if (!await vgdIsRunning({ socketPath })) {
7785
8218
  throw new CliError(`vgd is not running \u2014 start it with \`vg daemon ensure\` (${socketPath})`, ExitCode.NOT_FOUND);
7786
8219
  }
@@ -7794,7 +8227,7 @@ function registerDaemon(program) {
7794
8227
  throw new CliError(loaded.error, ExitCode.NOT_FOUND);
7795
8228
  }
7796
8229
  if (!loaded.ok) {
7797
- const { loadGraph: loadGraph2 } = await import('./load-E3OTM7BS.js');
8230
+ const { loadGraph: loadGraph2 } = await import('./load-T2FOJUPI.js');
7798
8231
  const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
7799
8232
  const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
7800
8233
  const graph = loadGraph2(root2, global.graph);
@@ -7910,7 +8343,7 @@ function socketOf(cmd) {
7910
8343
  let c2 = cmd;
7911
8344
  while (c2) {
7912
8345
  const opts = c2.opts();
7913
- if (opts.socket) return path37.resolve(opts.socket);
8346
+ if (opts.socket) return path39.resolve(opts.socket);
7914
8347
  c2 = c2.parent;
7915
8348
  }
7916
8349
  return vgdSocketPath();
@@ -7982,7 +8415,7 @@ async function restartVgdIfRunning(socketPath = vgdSocketPath()) {
7982
8415
  }
7983
8416
  function readVgdPid() {
7984
8417
  try {
7985
- const raw = fs7.readFileSync(vgdPidPath(), "utf8").trim();
8418
+ const raw = fs10.readFileSync(vgdPidPath(), "utf8").trim();
7986
8419
  const pid = Number.parseInt(raw, 10);
7987
8420
  return Number.isInteger(pid) && pid > 0 ? pid : null;
7988
8421
  } catch {
@@ -8067,7 +8500,7 @@ function registerPolicy(program) {
8067
8500
  const global = readGlobal(this);
8068
8501
  let raw;
8069
8502
  try {
8070
- raw = fs7.readFileSync(file, "utf8");
8503
+ raw = fs10.readFileSync(file, "utf8");
8071
8504
  } catch {
8072
8505
  throw new CliError(`cannot read ${file}`, ExitCode.NOT_FOUND);
8073
8506
  }
@@ -8187,11 +8620,11 @@ function registerLlmHost(program) {
8187
8620
  applyGlobalOptions(cmd);
8188
8621
  }
8189
8622
  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) => {
8190
- const rootDir = path37.resolve(targetPath);
8191
- const vibgrateDir2 = path37.join(rootDir, ".vibgrate");
8623
+ const rootDir = path39.resolve(targetPath);
8624
+ const vibgrateDir2 = path39.join(rootDir, ".vibgrate");
8192
8625
  await ensureDir(vibgrateDir2);
8193
8626
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold(".vibgrate/")} directory`);
8194
- const configPath = path37.join(rootDir, "vibgrate.config.ts");
8627
+ const configPath = path39.join(rootDir, "vibgrate.config.ts");
8195
8628
  if (await pathExists(configPath)) {
8196
8629
  console.log(chalk7.dim(" vibgrate.config.ts already exists, skipping"));
8197
8630
  } else {
@@ -8199,7 +8632,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
8199
8632
  console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold("vibgrate.config.ts")}`);
8200
8633
  }
8201
8634
  if (opts.baseline) {
8202
- const { runBaseline } = await import('./baseline-4BDH4F2W.js');
8635
+ const { runBaseline } = await import('./baseline-2V7PKA7Q.js');
8203
8636
  await runBaseline(rootDir);
8204
8637
  }
8205
8638
  console.log("");
@@ -8302,7 +8735,7 @@ function collectPackageImports(graph, ecosystem, pkg) {
8302
8735
  };
8303
8736
  }
8304
8737
  async function firstReferenceLine(rootDir, relFile, identifier, readFile3) {
8305
- const content = await readFile3(path37.join(rootDir, relFile));
8738
+ const content = await readFile3(path39.join(rootDir, relFile));
8306
8739
  if (!content) return null;
8307
8740
  const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8308
8741
  const re = new RegExp(`\\b${escaped}\\b`);
@@ -8340,9 +8773,9 @@ function sitesFromImportFiles(files, limit = 10) {
8340
8773
  }
8341
8774
  async function defaultReadFile(absPath) {
8342
8775
  try {
8343
- const stat2 = await fs21.stat(absPath);
8776
+ const stat2 = await fs24.stat(absPath);
8344
8777
  if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
8345
- return await fs21.readFile(absPath, "utf8");
8778
+ return await fs24.readFile(absPath, "utf8");
8346
8779
  } catch {
8347
8780
  return null;
8348
8781
  }
@@ -8538,7 +8971,7 @@ var AI_ASSISTANT_DETECTORS = [
8538
8971
  async function detectAiAssistant(rootDir) {
8539
8972
  for (const detector of AI_ASSISTANT_DETECTORS) {
8540
8973
  for (const file of detector.files) {
8541
- if (await pathExists$1(path37.join(rootDir, file))) {
8974
+ if (await pathExists$1(path39.join(rootDir, file))) {
8542
8975
  return detector.name;
8543
8976
  }
8544
8977
  }
@@ -8732,7 +9165,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
8732
9165
  collectExcludes,
8733
9166
  []
8734
9167
  ).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) => {
8735
- const rootDir = path37.resolve(targetPath);
9168
+ const rootDir = path39.resolve(targetPath);
8736
9169
  if (!await pathExists$1(rootDir)) {
8737
9170
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
8738
9171
  process.exit(1);
@@ -8740,7 +9173,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
8740
9173
  const hasDsn = !!resolveDsn(opts.dsn);
8741
9174
  const willPush = !opts.offline && (opts.push || hasDsn);
8742
9175
  const noLocalArtifacts = opts.localArtifacts === false;
8743
- const isFirstRun = !await pathExists$1(path37.join(rootDir, ".vibgrate", "scan_result.json"));
9176
+ const isFirstRun = !await pathExists$1(path39.join(rootDir, ".vibgrate", "scan_result.json"));
8744
9177
  let pinnedRegion;
8745
9178
  let planTier;
8746
9179
  let upgradeUrl;
@@ -8999,7 +9432,7 @@ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
8999
9432
  function scanStaleness(rootDir, artifactPath) {
9000
9433
  let ref;
9001
9434
  try {
9002
- ref = fs7.statSync(artifactPath).mtimeMs;
9435
+ ref = fs10.statSync(artifactPath).mtimeMs;
9003
9436
  } catch {
9004
9437
  return { stale: false };
9005
9438
  }
@@ -9011,7 +9444,7 @@ function scanStaleness(rootDir, artifactPath) {
9011
9444
  if (depth > 8 || scanned > MAX_ENTRIES2) return;
9012
9445
  let entries;
9013
9446
  try {
9014
- entries = fs7.readdirSync(dir, { withFileTypes: true });
9447
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
9015
9448
  } catch {
9016
9449
  return;
9017
9450
  }
@@ -9019,20 +9452,20 @@ function scanStaleness(rootDir, artifactPath) {
9019
9452
  scanned++;
9020
9453
  if (scanned > MAX_ENTRIES2) break;
9021
9454
  if (e.isDirectory()) {
9022
- if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path37.join(dir, e.name), depth + 1);
9455
+ if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path39.join(dir, e.name), depth + 1);
9023
9456
  continue;
9024
9457
  }
9025
9458
  if (!WATCHED_FILES.has(e.name) && !WATCHED_EXT.test(e.name)) continue;
9026
- const abs = path37.join(dir, e.name);
9459
+ const abs = path39.join(dir, e.name);
9027
9460
  let mtimeMs;
9028
9461
  try {
9029
- mtimeMs = fs7.statSync(abs).mtimeMs;
9462
+ mtimeMs = fs10.statSync(abs).mtimeMs;
9030
9463
  } catch {
9031
9464
  continue;
9032
9465
  }
9033
9466
  if (mtimeMs > newest) {
9034
9467
  newest = mtimeMs;
9035
- newestChanged = path37.relative(rootDir, abs) || e.name;
9468
+ newestChanged = path39.relative(rootDir, abs) || e.name;
9036
9469
  }
9037
9470
  }
9038
9471
  };
@@ -9163,7 +9596,7 @@ function analyzeTree(root2, packages) {
9163
9596
  if (depth > MAX_DEPTH || filesSeen >= MAX_FILES) return;
9164
9597
  let entries;
9165
9598
  try {
9166
- entries = fs7.readdirSync(dir, { withFileTypes: true });
9599
+ entries = fs10.readdirSync(dir, { withFileTypes: true });
9167
9600
  } catch {
9168
9601
  return;
9169
9602
  }
@@ -9172,17 +9605,17 @@ function analyzeTree(root2, packages) {
9172
9605
  if (filesSeen >= MAX_FILES) return;
9173
9606
  if (entry.isDirectory()) {
9174
9607
  if (SKIP_DIRS3.has(entry.name) || entry.name.startsWith(".")) continue;
9175
- walk2(path37.join(dir, entry.name), depth + 1);
9608
+ walk2(path39.join(dir, entry.name), depth + 1);
9176
9609
  continue;
9177
9610
  }
9178
- const fileEco = EXT_ECOSYSTEM[path37.extname(entry.name)];
9611
+ const fileEco = EXT_ECOSYSTEM[path39.extname(entry.name)];
9179
9612
  if (!fileEco || fileEco === "unknown") continue;
9180
9613
  filesSeen++;
9181
- const full = path37.join(dir, entry.name);
9614
+ const full = path39.join(dir, entry.name);
9182
9615
  let content;
9183
9616
  try {
9184
- if (fs7.statSync(full).size > MAX_FILE_BYTES2) continue;
9185
- content = fs7.readFileSync(full, "utf8");
9617
+ if (fs10.statSync(full).size > MAX_FILE_BYTES2) continue;
9618
+ content = fs10.readFileSync(full, "utf8");
9186
9619
  } catch {
9187
9620
  continue;
9188
9621
  }
@@ -9493,7 +9926,7 @@ function applyPlan(rootDir, upgrades, opts = {}) {
9493
9926
  }
9494
9927
  const outcomes = effective.map((t) => {
9495
9928
  const c2 = pmCommandFor(u.ecosystem, u.package, u.to, opts.packageManager, { workspaceRoot: t.isWorkspaceRoot });
9496
- return { t, res: run(c2, path37.join(rootDir, t.dir)) };
9929
+ return { t, res: run(c2, path39.join(rootDir, t.dir)) };
9497
9930
  });
9498
9931
  const failures = outcomes.filter((o) => !o.res.ok);
9499
9932
  if (failures.length === 0) {
@@ -9522,8 +9955,8 @@ function applyPlan(rootDir, upgrades, opts = {}) {
9522
9955
  return results;
9523
9956
  }
9524
9957
  var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
9525
- var CACHE_DIR = path37.join(os.homedir(), ".vibgrate");
9526
- var CACHE_FILE = path37.join(CACHE_DIR, "update-check.json");
9958
+ var CACHE_DIR = path39.join(os.homedir(), ".vibgrate");
9959
+ var CACHE_FILE = path39.join(CACHE_DIR, "update-check.json");
9527
9960
  async function fetchLatestVersion() {
9528
9961
  try {
9529
9962
  const controller = new AbortController();
@@ -9550,8 +9983,8 @@ async function fetchLatestVersion() {
9550
9983
  }
9551
9984
  async function writeCache(data) {
9552
9985
  try {
9553
- await fs21.mkdir(CACHE_DIR, { recursive: true });
9554
- await fs21.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
9986
+ await fs24.mkdir(CACHE_DIR, { recursive: true });
9987
+ await fs24.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
9555
9988
  } catch {
9556
9989
  }
9557
9990
  }
@@ -9562,7 +9995,7 @@ function detectGlobalInstall(execPath = process.argv[1] || "", cwd = process.cwd
9562
9995
  if (!execPath) return null;
9563
9996
  let resolved = execPath;
9564
9997
  try {
9565
- resolved = fs7.realpathSync(execPath);
9998
+ resolved = fs10.realpathSync(execPath);
9566
9999
  } catch {
9567
10000
  }
9568
10001
  const p = resolved.replace(/\\/g, "/");
@@ -9592,14 +10025,14 @@ async function findGlobalInstall(pkg = PACKAGE_NAME, run = defaultRunner) {
9592
10025
  pm: "yarn",
9593
10026
  root: () => {
9594
10027
  const dir = tryRun("yarn global dir");
9595
- return dir ? path37.join(dir, "node_modules") : null;
10028
+ return dir ? path39.join(dir, "node_modules") : null;
9596
10029
  }
9597
10030
  },
9598
- { pm: "bun", root: () => path37.join(os.homedir(), ".bun", "install", "global", "node_modules") }
10031
+ { pm: "bun", root: () => path39.join(os.homedir(), ".bun", "install", "global", "node_modules") }
9599
10032
  ];
9600
10033
  for (const probe of probes) {
9601
10034
  const root2 = probe.root();
9602
- if (root2 && await pathExists(path37.join(root2, pkg))) return probe.pm;
10035
+ if (root2 && await pathExists(path39.join(root2, pkg))) return probe.pm;
9603
10036
  }
9604
10037
  return null;
9605
10038
  }
@@ -9618,15 +10051,15 @@ function getGlobalUpdateCommand(pm, pkg, version) {
9618
10051
  }
9619
10052
  }
9620
10053
  async function detectPackageManager(cwd) {
9621
- if (await pathExists(path37.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
9622
- if (await pathExists(path37.join(cwd, "bun.lockb"))) return "bun";
9623
- if (await pathExists(path37.join(cwd, "yarn.lock"))) return "yarn";
10054
+ if (await pathExists(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10055
+ if (await pathExists(path39.join(cwd, "bun.lockb"))) return "bun";
10056
+ if (await pathExists(path39.join(cwd, "yarn.lock"))) return "yarn";
9624
10057
  return "npm";
9625
10058
  }
9626
10059
  async function detectWorkspaceRoot(cwd) {
9627
- if (await pathExists(path37.join(cwd, "pnpm-workspace.yaml"))) return true;
10060
+ if (await pathExists(path39.join(cwd, "pnpm-workspace.yaml"))) return true;
9628
10061
  try {
9629
- const pkgPath = path37.join(cwd, "package.json");
10062
+ const pkgPath = path39.join(cwd, "package.json");
9630
10063
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
9631
10064
  const pkg = JSON.parse(raw);
9632
10065
  return pkg.workspaces != null;
@@ -9651,7 +10084,7 @@ function getInstallCommand(pm, pkg, version, isDev, opts = {}) {
9651
10084
  }
9652
10085
  async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
9653
10086
  try {
9654
- const pkgPath = path37.join(cwd, "package.json");
10087
+ const pkgPath = path39.join(cwd, "package.json");
9655
10088
  const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
9656
10089
  const parsed = JSON.parse(raw);
9657
10090
  if (parsed.devDependencies?.[pkg]) return "dev";
@@ -9820,13 +10253,13 @@ function collectCandidates(artifact) {
9820
10253
  return out2;
9821
10254
  }
9822
10255
  var defaultFixScanner = async (rootDir) => {
9823
- const scratch = path37.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
10256
+ const scratch = path39.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
9824
10257
  const scanOpts = { vibgrateVersion: VERSION, format: "json", out: scratch, quiet: true, concurrency: 8 };
9825
10258
  const advanced = await loadAdvancedScanHook();
9826
10259
  return runCoreScan(rootDir, scanOpts, advanced);
9827
10260
  };
9828
10261
  async function loadArtifact(rootDir, inFile, scan = defaultFixScanner) {
9829
- const artifactPath = path37.isAbsolute(inFile) ? inFile : path37.join(rootDir, inFile);
10262
+ const artifactPath = path39.isAbsolute(inFile) ? inFile : path39.join(rootDir, inFile);
9830
10263
  if (await pathExists(artifactPath)) {
9831
10264
  const staleness = scanStaleness(rootDir, artifactPath);
9832
10265
  if (!staleness.stale) {
@@ -9853,7 +10286,7 @@ async function repositoryIdentity(rootDir, override) {
9853
10286
  }
9854
10287
  }
9855
10288
  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) => {
9856
- const rootDir = path37.resolve(targetPath);
10289
+ const rootDir = path39.resolve(targetPath);
9857
10290
  if (!await pathExists(rootDir)) {
9858
10291
  console.error(chalk7.red(`Path does not exist: ${rootDir}`));
9859
10292
  process.exit(1);
@@ -10014,7 +10447,7 @@ function emit(report, format) {
10014
10447
  }
10015
10448
  }
10016
10449
  function relProjectDir(rootDir, projectPath) {
10017
- const rel = path37.isAbsolute(projectPath) ? path37.relative(rootDir, projectPath) : projectPath;
10450
+ const rel = path39.isAbsolute(projectPath) ? path39.relative(rootDir, projectPath) : projectPath;
10018
10451
  return rel === "" ? "." : rel;
10019
10452
  }
10020
10453
  async function buildTargetResolver(rootDir, artifact) {
@@ -10849,7 +11282,7 @@ function formatMarkdown(artifact) {
10849
11282
 
10850
11283
  // src/reporting/commands/report.ts
10851
11284
  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) => {
10852
- const artifactPath = path37.resolve(opts.in);
11285
+ const artifactPath = path39.resolve(opts.in);
10853
11286
  if (!await pathExists(artifactPath)) {
10854
11287
  console.error(chalk7.red(`Artifact not found: ${artifactPath}`));
10855
11288
  console.error(chalk7.dim('Run "vibgrate scan" first to generate a scan artifact.'));
@@ -10898,8 +11331,8 @@ function openUrl(url) {
10898
11331
  // src/reporting/commands/login.ts
10899
11332
  var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
10900
11333
  function isInside(dir, file) {
10901
- const rel = path37.relative(dir, file);
10902
- return !!rel && !rel.startsWith("..") && !path37.isAbsolute(rel);
11334
+ const rel = path39.relative(dir, file);
11335
+ return !!rel && !rel.startsWith("..") && !path39.isAbsolute(rel);
10903
11336
  }
10904
11337
  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(
10905
11338
  "--local",
@@ -11154,7 +11587,7 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
11154
11587
  try {
11155
11588
  const statements = [];
11156
11589
  if (opts.from) {
11157
- const fromPath = path37.resolve(opts.from);
11590
+ const fromPath = path39.resolve(opts.from);
11158
11591
  if (!await pathExists(fromPath)) {
11159
11592
  process.stderr.write(chalk7.red(`Statements file not found: ${fromPath}
11160
11593
  `));
@@ -11172,9 +11605,9 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
11172
11605
  });
11173
11606
  const json2 = JSON.stringify(doc, null, 2);
11174
11607
  if (opts.out) {
11175
- await writeTextFile(path37.resolve(opts.out), json2 + "\n");
11608
+ await writeTextFile(path39.resolve(opts.out), json2 + "\n");
11176
11609
  process.stderr.write(
11177
- chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path37.resolve(opts.out)}
11610
+ chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path39.resolve(opts.out)}
11178
11611
  `
11179
11612
  );
11180
11613
  } else {
@@ -11357,7 +11790,7 @@ function formatDeltaText(base, current) {
11357
11790
  return lines.join("\n");
11358
11791
  }
11359
11792
  async function readArtifactOrExit(filePath) {
11360
- const absolutePath = path37.resolve(filePath);
11793
+ const absolutePath = path39.resolve(filePath);
11361
11794
  if (!await pathExists(absolutePath)) {
11362
11795
  console.error(chalk7.red(`Artifact not found: ${absolutePath}`));
11363
11796
  process.exit(1);
@@ -11374,7 +11807,7 @@ var exportCommand = new Command("export").description("Export scan artifact as S
11374
11807
  const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
11375
11808
  const body = JSON.stringify(sbom, null, 2);
11376
11809
  if (opts.out) {
11377
- await writeTextFile(path37.resolve(opts.out), body);
11810
+ await writeTextFile(path39.resolve(opts.out), body);
11378
11811
  console.log(chalk7.green("\u2714") + ` SBOM written to ${opts.out}`);
11379
11812
  } else {
11380
11813
  console.log(body);
@@ -11385,7 +11818,7 @@ var deltaCommand = new Command("delta").description("Show SBOM delta between two
11385
11818
  const current = await readArtifactOrExit(opts.to);
11386
11819
  const report = formatDeltaText(base, current);
11387
11820
  if (opts.out) {
11388
- await writeTextFile(path37.resolve(opts.out), report);
11821
+ await writeTextFile(path39.resolve(opts.out), report);
11389
11822
  console.log(chalk7.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
11390
11823
  } else {
11391
11824
  console.log(report);
@@ -11516,20 +11949,20 @@ function resolveRegime(id) {
11516
11949
  return regime;
11517
11950
  }
11518
11951
  function evidenceDir(root2) {
11519
- return path37.join(root2, ".vibgrate", "evidence");
11952
+ return path39.join(root2, ".vibgrate", "evidence");
11520
11953
  }
11521
11954
  function orgPath(root2) {
11522
- return path37.join(evidenceDir(root2), "org.json");
11955
+ return path39.join(evidenceDir(root2), "org.json");
11523
11956
  }
11524
11957
  function productsPath(root2) {
11525
- return path37.join(evidenceDir(root2), "products.json");
11958
+ return path39.join(evidenceDir(root2), "products.json");
11526
11959
  }
11527
11960
  function releasesDir(root2) {
11528
- return path37.join(evidenceDir(root2), "releases");
11961
+ return path39.join(evidenceDir(root2), "releases");
11529
11962
  }
11530
11963
  function releasePath(root2, productId, version) {
11531
11964
  const safe = `${productId}@${version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
11532
- return path37.join(releasesDir(root2), `${safe}.json`);
11965
+ return path39.join(releasesDir(root2), `${safe}.json`);
11533
11966
  }
11534
11967
  var DEFAULT_ORG = {
11535
11968
  responsiblePersons: [],
@@ -11560,7 +11993,7 @@ async function freezeRelease(root2, release) {
11560
11993
  const p = releasePath(root2, release.productId, release.version);
11561
11994
  if (await pathExists(p)) {
11562
11995
  throw new CliError(
11563
- `release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${path37.relative(root2, p)} only if it was frozen in error`,
11996
+ `release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${path39.relative(root2, p)} only if it was frozen in error`,
11564
11997
  ExitCode.USAGE_ERROR
11565
11998
  );
11566
11999
  }
@@ -11574,7 +12007,7 @@ async function loadReleases(root2, productId) {
11574
12007
  const files = (await readdir(dir)).filter((f) => f.endsWith(".json")).sort();
11575
12008
  const releases = [];
11576
12009
  for (const f of files) {
11577
- const rel = await readJsonFile(path37.join(dir, f));
12010
+ const rel = await readJsonFile(path39.join(dir, f));
11578
12011
  if (!productId || rel.productId === productId) releases.push(rel);
11579
12012
  }
11580
12013
  return releases;
@@ -12269,19 +12702,19 @@ function verifyEvidenceEnvelope(env, opts = {}) {
12269
12702
  var DEFAULT_KEY = "attest-key.pem";
12270
12703
  function resolveSigningKey(root2, explicit) {
12271
12704
  const chosen = process.env.VG_ATTEST_KEY;
12272
- const keyPath = chosen ? path37.resolve(chosen) : path37.join(root2, ".vibgrate", DEFAULT_KEY);
12705
+ const keyPath = chosen ? path39.resolve(chosen) : path39.join(root2, ".vibgrate", DEFAULT_KEY);
12273
12706
  let minted = false;
12274
- if (!fs7.existsSync(keyPath)) {
12707
+ if (!fs10.existsSync(keyPath)) {
12275
12708
  if (chosen) throw new CliError(`signing key not found: ${chosen}`, ExitCode.USAGE_ERROR);
12276
12709
  const kp = generateKeypair();
12277
- fs7.mkdirSync(path37.dirname(keyPath), { recursive: true });
12278
- fs7.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
12279
- fs7.writeFileSync(`${keyPath}.pub`, kp.publicPem);
12710
+ fs10.mkdirSync(path39.dirname(keyPath), { recursive: true });
12711
+ fs10.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
12712
+ fs10.writeFileSync(`${keyPath}.pub`, kp.publicPem);
12280
12713
  minted = true;
12281
12714
  }
12282
12715
  let key2;
12283
12716
  try {
12284
- key2 = crypto3.createPrivateKey(fs7.readFileSync(keyPath, "utf8"));
12717
+ key2 = crypto3.createPrivateKey(fs10.readFileSync(keyPath, "utf8"));
12285
12718
  } catch {
12286
12719
  throw new CliError(`could not read an Ed25519 private key from ${keyPath}`, ExitCode.USAGE_ERROR);
12287
12720
  }
@@ -12292,16 +12725,16 @@ function resolveSigningKey(root2, explicit) {
12292
12725
  }
12293
12726
  function writeBundle(input) {
12294
12727
  const dir = input.outDir;
12295
- fs7.mkdirSync(path37.join(dir, "inputs", "releases"), { recursive: true });
12296
- const write = (rel, data) => fs7.writeFileSync(path37.join(dir, rel), `${JSON.stringify(data, null, 2)}
12728
+ fs10.mkdirSync(path39.join(dir, "inputs", "releases"), { recursive: true });
12729
+ const write = (rel, data) => fs10.writeFileSync(path39.join(dir, rel), `${JSON.stringify(data, null, 2)}
12297
12730
  `);
12298
12731
  write("result.json", input.result);
12299
- write(path37.join("inputs", "advisory.json"), input.advisory);
12732
+ write(path39.join("inputs", "advisory.json"), input.advisory);
12300
12733
  for (const rel of input.releases) {
12301
12734
  const safe = `${rel.productId}@${rel.version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
12302
- write(path37.join("inputs", "releases", `${safe}.json`), rel);
12735
+ write(path39.join("inputs", "releases", `${safe}.json`), rel);
12303
12736
  }
12304
- write(path37.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
12737
+ write(path39.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
12305
12738
  write("provenance.json", {
12306
12739
  method: "deterministic",
12307
12740
  modelDrafted: [],
@@ -12317,13 +12750,13 @@ function writeBundle(input) {
12317
12750
  disclaimer: input.regime.disclaimer
12318
12751
  });
12319
12752
  if (input.envelope) {
12320
- fs7.writeFileSync(path37.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
12753
+ fs10.writeFileSync(path39.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
12321
12754
  `);
12322
12755
  }
12323
12756
  if (input.timestampToken) {
12324
- fs7.writeFileSync(path37.join(dir, "timestamp.tsr"), input.timestampToken);
12757
+ fs10.writeFileSync(path39.join(dir, "timestamp.tsr"), input.timestampToken);
12325
12758
  }
12326
- fs7.writeFileSync(path37.join(dir, "VERIFY.md"), verifyDoc(input));
12759
+ fs10.writeFileSync(path39.join(dir, "VERIFY.md"), verifyDoc(input));
12327
12760
  return dir;
12328
12761
  }
12329
12762
  function verifyDoc(input) {
@@ -12384,13 +12817,13 @@ function undeterminedFields(result, regime) {
12384
12817
  return gaps.filter((g) => regime.submission.requires.some((r) => g.startsWith(r)) || g.startsWith("exposure") || g.startsWith("member"));
12385
12818
  }
12386
12819
  async function recordDrill(root2, record) {
12387
- const dir = path37.join(evidenceDir(root2), "drills");
12388
- const p = path37.join(dir, `${record.drillId}.json`);
12820
+ const dir = path39.join(evidenceDir(root2), "drills");
12821
+ const p = path39.join(dir, `${record.drillId}.json`);
12389
12822
  await writeJsonFile(p, record);
12390
12823
  return p;
12391
12824
  }
12392
12825
  async function hasRecentDrill(root2, asOf) {
12393
- const dir = path37.join(evidenceDir(root2), "drills");
12826
+ const dir = path39.join(evidenceDir(root2), "drills");
12394
12827
  if (!await pathExists(dir)) return void 0;
12395
12828
  const { readdir } = await import('fs/promises');
12396
12829
  const { readJsonFile: readJsonFile2 } = await import('./fs-4G5A65KS.js');
@@ -12398,7 +12831,7 @@ async function hasRecentDrill(root2, asOf) {
12398
12831
  if (files.length === 0) return void 0;
12399
12832
  const cutoff = new Date(new Date(asOf).getTime() - 90 * 24 * 3600 * 1e3).toISOString();
12400
12833
  for (const f of files) {
12401
- const rec = await readJsonFile2(path37.join(dir, f));
12834
+ const rec = await readJsonFile2(path39.join(dir, f));
12402
12835
  if (rec.ranAt >= cutoff) return true;
12403
12836
  }
12404
12837
  return false;
@@ -12478,7 +12911,7 @@ function formatRegimeList() {
12478
12911
 
12479
12912
  // src/reporting/commands/evidence/index.ts
12480
12913
  function root(opts) {
12481
- return path37.resolve(opts.cwd ?? process.cwd());
12914
+ return path39.resolve(opts.cwd ?? process.cwd());
12482
12915
  }
12483
12916
  function slug(name) {
12484
12917
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "product";
@@ -12566,7 +12999,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
12566
12999
  const release = await buildRelease({
12567
13000
  productId: product.id,
12568
13001
  version,
12569
- from: path37.resolve(rootDir, opts.from),
13002
+ from: path39.resolve(rootDir, opts.from),
12570
13003
  shipDate: opts.shipDate,
12571
13004
  buildId: opts.buildId,
12572
13005
  artefactDigest: opts.digest,
@@ -12574,7 +13007,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
12574
13007
  frozenAt: nowIso()
12575
13008
  });
12576
13009
  const p = await freezeRelease(rootDir, release);
12577
- console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path37.relative(rootDir, p)}`);
13010
+ console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path39.relative(rootDir, p)}`);
12578
13011
  });
12579
13012
  async function runExposure(rootDir, vuln, opts) {
12580
13013
  const org = await loadOrg(rootDir);
@@ -12626,7 +13059,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
12626
13059
  console.log("\n" + buildPack(result, regime, org, stage));
12627
13060
  }
12628
13061
  if (opts.bundle) {
12629
- const dir = path37.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
13062
+ const dir = path39.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
12630
13063
  let envelope;
12631
13064
  if (opts.sign !== false) {
12632
13065
  const { key: key2, minted } = resolveSigningKey(rootDir);
@@ -12634,7 +13067,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
12634
13067
  envelope = signEvidenceStatement(buildEvidenceStatement(result, VERSION), key2);
12635
13068
  }
12636
13069
  writeBundle({ outDir: dir, result, advisory, releases, regime, envelope, timestampToken, cliVersion: VERSION });
12637
- console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path37.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
13070
+ console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path39.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
12638
13071
  }
12639
13072
  process.exitCode = exposureExit(result.overallStatus);
12640
13073
  });
@@ -12666,7 +13099,7 @@ var packCmd = new Command("pack").description("Build the submission pack a human
12666
13099
  const stage = opts.stage ?? regime.clocks[0]?.stage ?? "early-warning";
12667
13100
  const md = buildPack(result, regime, org, stage);
12668
13101
  if (opts.out) {
12669
- fs7.writeFileSync(path37.resolve(rootDir, opts.out), md);
13102
+ fs10.writeFileSync(path39.resolve(rootDir, opts.out), md);
12670
13103
  console.error(chalk7.green("\u2714") + ` pack written to ${opts.out}`);
12671
13104
  } else {
12672
13105
  console.log(md);
@@ -12708,20 +13141,20 @@ var drillCmd = new Command("drill").description("Timed dry-run of the determinat
12708
13141
  }
12709
13142
  });
12710
13143
  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) => {
12711
- const abs = path37.resolve(bundlePath);
12712
- const envPath = fs7.statSync(abs).isDirectory() ? path37.join(abs, "evidence.intoto.jsonl") : abs;
12713
- if (!fs7.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
12714
- const envelope = JSON.parse(fs7.readFileSync(envPath, "utf8").trim().split("\n")[0]);
12715
- const resultPath = path37.join(path37.dirname(envPath), "result.json");
12716
- const result = fs7.existsSync(resultPath) ? JSON.parse(fs7.readFileSync(resultPath, "utf8")) : void 0;
12717
- const publicKeyPem = opts.pub ? fs7.readFileSync(path37.resolve(opts.pub), "utf8") : void 0;
13144
+ const abs = path39.resolve(bundlePath);
13145
+ const envPath = fs10.statSync(abs).isDirectory() ? path39.join(abs, "evidence.intoto.jsonl") : abs;
13146
+ if (!fs10.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
13147
+ const envelope = JSON.parse(fs10.readFileSync(envPath, "utf8").trim().split("\n")[0]);
13148
+ const resultPath = path39.join(path39.dirname(envPath), "result.json");
13149
+ const result = fs10.existsSync(resultPath) ? JSON.parse(fs10.readFileSync(resultPath, "utf8")) : void 0;
13150
+ const publicKeyPem = opts.pub ? fs10.readFileSync(path39.resolve(opts.pub), "utf8") : void 0;
12718
13151
  const v = verifyEvidenceEnvelope(envelope, { publicKeyPem, result });
12719
13152
  const color = v.status === "verified" ? chalk7.green : v.status === "failed" ? chalk7.red : chalk7.yellow;
12720
13153
  console.log(" " + color(v.status.toUpperCase()) + ` ${v.reason}`);
12721
13154
  if (v.evidenceId) console.log(" " + chalk7.dim(`evidence ${v.evidenceId} \xB7 regime ${v.regime} \xB7 advisory ${v.advisoryId} \xB7 ${v.overallStatus}`));
12722
- const tsrPath = path37.join(path37.dirname(envPath), "timestamp.tsr");
12723
- if (fs7.existsSync(tsrPath) && result) {
12724
- const t = verifyTimestamp(fs7.readFileSync(tsrPath), exposureSubjectDigest(result));
13155
+ const tsrPath = path39.join(path39.dirname(envPath), "timestamp.tsr");
13156
+ if (fs10.existsSync(tsrPath) && result) {
13157
+ const t = verifyTimestamp(fs10.readFileSync(tsrPath), exposureSubjectDigest(result));
12725
13158
  const tcolor = t.imprintMatches ? chalk7.green : chalk7.red;
12726
13159
  console.log(" " + tcolor("TIMESTAMP") + ` ${t.reason}`);
12727
13160
  }
@@ -12788,12 +13221,12 @@ var exportCmd = new Command("export").description("Air-gap bundle of all evidenc
12788
13221
  const releases = [];
12789
13222
  for (const list of releasesByProduct.values()) releases.push(...list);
12790
13223
  const report = computeReadiness({ regime, org, products, releasesByProduct, recentDrill: await hasRecentDrill(rootDir, today()) });
12791
- const dir = path37.resolve(rootDir, opts.out);
12792
- await writeJsonFile(path37.join(dir, "org.json"), org);
12793
- await writeJsonFile(path37.join(dir, "products.json"), products);
12794
- for (const r of releases) await writeJsonFile(path37.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
12795
- await writeJsonFile(path37.join(dir, "readiness.json"), report);
12796
- console.error(chalk7.green("\u2714") + ` exported evidence state to ${path37.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
13224
+ const dir = path39.resolve(rootDir, opts.out);
13225
+ await writeJsonFile(path39.join(dir, "org.json"), org);
13226
+ await writeJsonFile(path39.join(dir, "products.json"), products);
13227
+ for (const r of releases) await writeJsonFile(path39.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
13228
+ await writeJsonFile(path39.join(dir, "readiness.json"), report);
13229
+ console.error(chalk7.green("\u2714") + ` exported evidence state to ${path39.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
12797
13230
  });
12798
13231
  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) => {
12799
13232
  const rootDir = root(opts);
@@ -12819,10 +13252,10 @@ var pushCmd = new Command("push").description("Push the product registry (and an
12819
13252
  }));
12820
13253
  let exposure;
12821
13254
  if (opts.result) {
12822
- const raw = path37.resolve(rootDir, opts.result);
12823
- const resultPath = fs7.existsSync(raw) && fs7.statSync(raw).isDirectory() ? path37.join(raw, "result.json") : raw;
12824
- if (!fs7.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
12825
- exposure = JSON.parse(fs7.readFileSync(resultPath, "utf8"));
13255
+ const raw = path39.resolve(rootDir, opts.result);
13256
+ const resultPath = fs10.existsSync(raw) && fs10.statSync(raw).isDirectory() ? path39.join(raw, "result.json") : raw;
13257
+ if (!fs10.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
13258
+ exposure = JSON.parse(fs10.readFileSync(resultPath, "utf8"));
12826
13259
  }
12827
13260
  const payload = { schemaVersion: "evidence-push-1", regime: regime.id, generatedAt: nowIso(), signed: Boolean(opts.signed), products: productPayload, exposure };
12828
13261
  const body = JSON.stringify(payload);
@@ -12880,6 +13313,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
12880
13313
  "serve",
12881
13314
  "lsp",
12882
13315
  "doctor",
13316
+ "module",
12883
13317
  "daemon",
12884
13318
  "policy",
12885
13319
  "llm-host",
@@ -12887,6 +13321,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
12887
13321
  "uninstall",
12888
13322
  "share",
12889
13323
  "watch",
13324
+ "hook",
12890
13325
  "help",
12891
13326
  // Drift-reporting verbs (merged from the Vibgrate CLI).
12892
13327
  "init",
@@ -12926,6 +13361,8 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
12926
13361
  registerServe(program);
12927
13362
  registerLsp(program);
12928
13363
  registerInstall(program);
13364
+ registerModule(program);
13365
+ registerHook(program);
12929
13366
  registerShare(program);
12930
13367
  registerWatch(program);
12931
13368
  registerTests(program);
@@ -13012,7 +13449,7 @@ function dispatch(argv, cwd) {
13012
13449
  }
13013
13450
  const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
13014
13451
  if (looksLikeQuestion) return ["ask", ...args];
13015
- if (fs7.existsSync(path37.resolve(cwd, first))) {
13452
+ if (fs10.existsSync(path39.resolve(cwd, first))) {
13016
13453
  return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
13017
13454
  }
13018
13455
  const moved = MOVED_COMMANDS[first];
@@ -13057,9 +13494,9 @@ async function main(argv = process.argv) {
13057
13494
  }
13058
13495
  function readCwd(raw) {
13059
13496
  const i = raw.findIndex((a) => a === "-C" || a === "--cwd");
13060
- if (i >= 0 && raw[i + 1]) return path37.resolve(raw[i + 1]);
13497
+ if (i >= 0 && raw[i + 1]) return path39.resolve(raw[i + 1]);
13061
13498
  const eq = raw.find((a) => a.startsWith("--cwd="));
13062
- if (eq) return path37.resolve(eq.slice("--cwd=".length));
13499
+ if (eq) return path39.resolve(eq.slice("--cwd=".length));
13063
13500
  return process.cwd();
13064
13501
  }
13065
13502
  function handleError(err) {