@vibgrate/cli 2026.731.3 → 2026.803.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-HNV2VUCO.js +24 -0
- package/dist/{agent-6XOI7RVW.js.map → agent-HNV2VUCO.js.map} +1 -1
- package/dist/baseline-6WTULHM5.js +9 -0
- package/dist/{baseline-PY6TETA5.js.map → baseline-6WTULHM5.js.map} +1 -1
- package/dist/{chunk-B6S2DSBS.js → chunk-2TLQDF6C.js} +129 -20
- package/dist/chunk-2TLQDF6C.js.map +1 -0
- package/dist/{chunk-X634FZVG.js → chunk-3LOWJSAF.js} +11 -16
- package/dist/{chunk-X634FZVG.js.map → chunk-3LOWJSAF.js.map} +1 -1
- package/dist/{chunk-BMUTNUB7.js → chunk-4HFSUIIN.js} +117 -6
- package/dist/chunk-4HFSUIIN.js.map +1 -0
- package/dist/{chunk-3VSU7G75.js → chunk-536J6HUR.js} +235 -13
- package/dist/chunk-536J6HUR.js.map +1 -0
- package/dist/{chunk-EETK7S43.js → chunk-5VH3Y4QC.js} +111 -33
- package/dist/chunk-5VH3Y4QC.js.map +1 -0
- package/dist/{chunk-PHGAUWWF.js → chunk-6I4TXAI6.js} +3 -3
- package/dist/{chunk-PHGAUWWF.js.map → chunk-6I4TXAI6.js.map} +1 -1
- package/dist/{chunk-FF5ZQ6KI.js → chunk-6JP7HGIF.js} +4 -4
- package/dist/{chunk-FF5ZQ6KI.js.map → chunk-6JP7HGIF.js.map} +1 -1
- package/dist/chunk-AJ2KE3NT.js +446 -0
- package/dist/chunk-AJ2KE3NT.js.map +1 -0
- package/dist/{chunk-WK52LWRX.js → chunk-B2KLJPFY.js} +5 -5
- package/dist/{chunk-WK52LWRX.js.map → chunk-B2KLJPFY.js.map} +1 -1
- package/dist/{chunk-Z7VH4RPO.js → chunk-BBFQZ7CA.js} +4 -4
- package/dist/{chunk-Z7VH4RPO.js.map → chunk-BBFQZ7CA.js.map} +1 -1
- package/dist/{chunk-FHJBGPJZ.js → chunk-BWMMR5XA.js} +4 -4
- package/dist/{chunk-FHJBGPJZ.js.map → chunk-BWMMR5XA.js.map} +1 -1
- package/dist/{chunk-KLO2XBUX.js → chunk-CC6F75GI.js} +14 -7
- package/dist/chunk-CC6F75GI.js.map +1 -0
- package/dist/{chunk-SCTLOFNH.js → chunk-CE45STY5.js} +4 -4
- package/dist/{chunk-SCTLOFNH.js.map → chunk-CE45STY5.js.map} +1 -1
- package/dist/{chunk-MOLBANFB.js → chunk-DIU3MXB3.js} +4 -4
- package/dist/{chunk-MOLBANFB.js.map → chunk-DIU3MXB3.js.map} +1 -1
- package/dist/{chunk-5IA2TA57.js → chunk-FKFRASAB.js} +323 -152
- package/dist/chunk-FKFRASAB.js.map +1 -0
- package/dist/{chunk-EVLS2M5G.js → chunk-JFE7XCAE.js} +3 -3
- package/dist/{chunk-EVLS2M5G.js.map → chunk-JFE7XCAE.js.map} +1 -1
- package/dist/{chunk-RGEVBSLK.js → chunk-JUSXLCSE.js} +3 -3
- package/dist/{chunk-RGEVBSLK.js.map → chunk-JUSXLCSE.js.map} +1 -1
- package/dist/{chunk-7G5S5KZN.js → chunk-KUZLILN3.js} +16 -3
- package/dist/chunk-KUZLILN3.js.map +1 -0
- package/dist/{chunk-AVCBKQKA.js → chunk-N4IDP2M2.js} +218 -51
- package/dist/chunk-N4IDP2M2.js.map +1 -0
- package/dist/{chunk-XRN7DQGR.js → chunk-NJFQCDGA.js} +3 -3
- package/dist/{chunk-XRN7DQGR.js.map → chunk-NJFQCDGA.js.map} +1 -1
- package/dist/{chunk-LTTVCI5C.js → chunk-O7MTBC52.js} +134 -9
- package/dist/chunk-O7MTBC52.js.map +1 -0
- package/dist/chunk-QT2PMGN3.js +6 -0
- package/dist/{chunk-DEKGSQHL.js.map → chunk-QT2PMGN3.js.map} +1 -1
- package/dist/{chunk-5XIEVZLW.js → chunk-S4NSF5AZ.js} +6 -6
- package/dist/{chunk-5XIEVZLW.js.map → chunk-S4NSF5AZ.js.map} +1 -1
- package/dist/{chunk-TRKRRX2S.js → chunk-SJFBXCII.js} +35 -6
- package/dist/chunk-SJFBXCII.js.map +1 -0
- package/dist/{chunk-RIWLXMMT.js → chunk-SNKTD23L.js} +109 -10
- package/dist/chunk-SNKTD23L.js.map +1 -0
- package/dist/{chunk-IPICO2RV.js → chunk-VIWZ4QT7.js} +14 -3
- package/dist/chunk-VIWZ4QT7.js.map +1 -0
- package/dist/{chunk-US2DAKCM.js → chunk-Y7YKUZ3T.js} +8 -7
- package/dist/chunk-Y7YKUZ3T.js.map +1 -0
- package/dist/cli.js +732 -347
- package/dist/cli.js.map +1 -1
- package/dist/ensure-map-5YEI7R7V.js +29 -0
- package/dist/{ensure-map-UQL7SM34.js.map → ensure-map-5YEI7R7V.js.map} +1 -1
- package/dist/{graph-backend-G5Y6QQV4.js → graph-backend-CPHLUKUC.js} +5 -5
- package/dist/{graph-backend-G5Y6QQV4.js.map → graph-backend-CPHLUKUC.js.map} +1 -1
- package/dist/index.d.ts +127 -9
- package/dist/index.js +17 -16
- package/dist/index.js.map +1 -1
- package/dist/{interactive-QWT7ERXJ.js → interactive-TNRE4OEK.js} +46 -33
- package/dist/interactive-TNRE4OEK.js.map +1 -0
- package/dist/{llm-host-DZBD5D36.js → llm-host-XFYFOAAX.js} +4 -4
- package/dist/{llm-host-DZBD5D36.js.map → llm-host-XFYFOAAX.js.map} +1 -1
- package/dist/load-MWG6WZTK.js +10 -0
- package/dist/{load-WA53B3GW.js.map → load-MWG6WZTK.js.map} +1 -1
- package/dist/model-manager-GJ2YSTSK.js +1 -1
- package/dist/{run-outcome-J2IDIVYI.js → run-outcome-375HMSQG.js} +6 -6
- package/dist/{run-outcome-J2IDIVYI.js.map → run-outcome-375HMSQG.js.map} +1 -1
- package/dist/runtime-session-3MPWXNRL.js +20 -0
- package/dist/{runtime-session-52P2Y5LX.js.map → runtime-session-3MPWXNRL.js.map} +1 -1
- package/dist/session-2NGJLI5Y.js +15 -0
- package/dist/{session-L7SJNE55.js.map → session-2NGJLI5Y.js.map} +1 -1
- package/dist/session-store-F7NX7SZN.js +4 -0
- package/dist/{session-store-SQECEXUU.js.map → session-store-F7NX7SZN.js.map} +1 -1
- package/dist/{stream-json-TSGYC2MQ.js → stream-json-AUMU3NLV.js} +48 -16
- package/dist/stream-json-AUMU3NLV.js.map +1 -0
- package/dist/{vg-mcp-bridge-IFAXEQMZ.js → vg-mcp-bridge-D463EHQI.js} +13 -11
- package/dist/vg-mcp-bridge-D463EHQI.js.map +1 -0
- package/dist/{vgd-PNR7UKLL.js → vgd-Z23PXSP4.js} +10 -10
- package/dist/vgd-Z23PXSP4.js.map +1 -0
- package/package.json +4 -2
- package/dist/agent-6XOI7RVW.js +0 -22
- package/dist/baseline-PY6TETA5.js +0 -9
- package/dist/chunk-3VSU7G75.js.map +0 -1
- package/dist/chunk-5IA2TA57.js.map +0 -1
- package/dist/chunk-7G5S5KZN.js.map +0 -1
- package/dist/chunk-AVCBKQKA.js.map +0 -1
- package/dist/chunk-B6S2DSBS.js.map +0 -1
- package/dist/chunk-BMUTNUB7.js.map +0 -1
- package/dist/chunk-DEKGSQHL.js +0 -6
- package/dist/chunk-EETK7S43.js.map +0 -1
- package/dist/chunk-IPICO2RV.js.map +0 -1
- package/dist/chunk-KLO2XBUX.js.map +0 -1
- package/dist/chunk-LTTVCI5C.js.map +0 -1
- package/dist/chunk-RIWLXMMT.js.map +0 -1
- package/dist/chunk-TRKRRX2S.js.map +0 -1
- package/dist/chunk-US2DAKCM.js.map +0 -1
- package/dist/chunk-ZKNB4YH4.js +0 -102
- package/dist/chunk-ZKNB4YH4.js.map +0 -1
- package/dist/ensure-map-UQL7SM34.js +0 -28
- package/dist/interactive-QWT7ERXJ.js.map +0 -1
- package/dist/load-WA53B3GW.js +0 -10
- package/dist/runtime-session-52P2Y5LX.js +0 -20
- package/dist/session-L7SJNE55.js +0 -13
- package/dist/session-store-SQECEXUU.js +0 -4
- package/dist/stream-json-TSGYC2MQ.js.map +0 -1
- package/dist/vg-mcp-bridge-IFAXEQMZ.js.map +0 -1
- package/dist/vgd-PNR7UKLL.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,69 +1,70 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { loadAdvancedScanHook, baselineCommand } from './chunk-
|
|
3
|
-
import { fetchCatalog, resolveProviders } from './chunk-
|
|
4
|
-
import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-
|
|
5
|
-
import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-
|
|
2
|
+
import { loadAdvancedScanHook, baselineCommand } from './chunk-6JP7HGIF.js';
|
|
3
|
+
import { fetchCatalog, resolveProviders } from './chunk-4HFSUIIN.js';
|
|
4
|
+
import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-B2KLJPFY.js';
|
|
5
|
+
import { telemetryOptOut, StatsSharer, statsEndpoint, isCI } from './chunk-BBFQZ7CA.js';
|
|
6
|
+
import './chunk-7AVYKZEM.js';
|
|
6
7
|
import { buildModelInstallPlan } from './chunk-WHJMS7XC.js';
|
|
7
|
-
import { runCodeSession } from './chunk-
|
|
8
|
-
import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-
|
|
9
|
-
export { runBuild } from './chunk-
|
|
8
|
+
import { runCodeSession } from './chunk-CC6F75GI.js';
|
|
9
|
+
import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, runBuild } from './chunk-O7MTBC52.js';
|
|
10
|
+
export { runBuild } from './chunk-O7MTBC52.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';
|
|
15
15
|
import { fmt, estimateModelBytes } from './chunk-7N4Y3E47.js';
|
|
16
16
|
import './chunk-IZDH67DX.js';
|
|
17
|
-
import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-
|
|
18
|
-
import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-
|
|
19
|
-
import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-
|
|
17
|
+
import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-JFE7XCAE.js';
|
|
18
|
+
import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-3LOWJSAF.js';
|
|
19
|
+
import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-536J6HUR.js';
|
|
20
20
|
import './chunk-543E6WDJ.js';
|
|
21
|
-
import { summarizeDiffs, ScriptedProvider } from './chunk-
|
|
21
|
+
import { summarizeDiffs, ScriptedProvider } from './chunk-SJFBXCII.js';
|
|
22
22
|
import { ensurePackage, ensureUnavailableMessage } from './chunk-REIGWTTH.js';
|
|
23
|
-
import './chunk-
|
|
23
|
+
import './chunk-JUSXLCSE.js';
|
|
24
24
|
import { vgdSocketPath, vgdIsRunning, vgdRequest, vgdPidPath } from './chunk-RBIRXQR6.js';
|
|
25
25
|
import { buildIdentifierTrieFromGraph } from './chunk-5HYCB55P.js';
|
|
26
|
-
import './chunk-
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
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-2TLQDF6C.js';
|
|
27
|
+
import { refreshIfStale } from './chunk-S4NSF5AZ.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-FKFRASAB.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-SNKTD23L.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-
|
|
35
|
-
import './chunk-
|
|
36
|
-
import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-
|
|
36
|
+
import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-Y7YKUZ3T.js';
|
|
37
|
+
import './chunk-VIWZ4QT7.js';
|
|
38
|
+
import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-BWMMR5XA.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-
|
|
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 } from './chunk-5VH3Y4QC.js';
|
|
42
42
|
import { resolvedGrammarFiles, grammarSetVersion } from './chunk-UTNNGKKX.js';
|
|
43
43
|
import './chunk-RXP66R2E.js';
|
|
44
|
-
import { loadGraph, SCHEMA_VERSION } from './chunk-
|
|
45
|
-
import { resolveGraphPath, renderReport, loadGraphFileWithSnapshot, writeArtifacts, vibgrateDir, mapFileExists, ensureVibgrateGitignore } from './chunk-
|
|
46
|
-
import { VERSION } from './chunk-
|
|
47
|
-
import { cacheDir, serializeGraph, stableStringify } from './chunk-
|
|
44
|
+
import { loadGraph, loadGraphPreferIndex, SCHEMA_VERSION } from './chunk-DIU3MXB3.js';
|
|
45
|
+
import { resolveGraphPath, analyzeQuestion, loadTopicTags, renderReport, resetRelevanceProviderCache, loadRelevanceProvider, loadGraphFileWithSnapshot, writeArtifacts, vibgrateDir, mapFileExists, relevanceModuleDir, ensureVibgrateGitignore } from './chunk-N4IDP2M2.js';
|
|
46
|
+
import { VERSION } from './chunk-QT2PMGN3.js';
|
|
47
|
+
import { cacheDir, serializeGraph, stableStringify, parseGraph } from './chunk-AJ2KE3NT.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
|
|
54
|
-
import
|
|
55
|
-
import * as
|
|
56
|
-
import
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
101
|
-
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(
|
|
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 ${
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
942
|
+
fs10.mkdirSync(this.dir, { recursive: true });
|
|
940
943
|
const tmp = `${this.file}.tmp`;
|
|
941
|
-
|
|
942
|
-
|
|
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 =
|
|
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 =
|
|
963
|
+
const file = path39.join(this.dir, name);
|
|
961
964
|
let parsed;
|
|
962
965
|
try {
|
|
963
|
-
parsed = JSON.parse(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
1298
|
+
const fd = fs10.openSync(this.file, "r");
|
|
1296
1299
|
try {
|
|
1297
1300
|
chunk = Buffer.alloc(size - this.offset);
|
|
1298
|
-
|
|
1301
|
+
fs10.readSync(fd, chunk, 0, chunk.length, this.offset);
|
|
1299
1302
|
} finally {
|
|
1300
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1721
|
-
files.push({ rel, hash: hashBytes(
|
|
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 =
|
|
1732
|
-
if (rel === "" || rel.startsWith("..") ||
|
|
1733
|
-
const parts = rel.split(
|
|
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(
|
|
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
|
-
|
|
1751
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1816
|
+
fs10.mkdirSync(path39.dirname(file), { recursive: true });
|
|
1806
1817
|
ensureVibgrateGitignore(root2);
|
|
1807
|
-
|
|
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
|
-
|
|
1823
|
+
fs10.writeFileSync(file, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
|
|
1813
1824
|
}
|
|
1814
1825
|
} catch {
|
|
1815
1826
|
}
|
|
@@ -2682,10 +2693,10 @@ var VibgrateLanguageServer = class {
|
|
|
2682
2693
|
const ecosystem = osvEcosystem(proj.type);
|
|
2683
2694
|
if (!ecosystem) continue;
|
|
2684
2695
|
const relManifest = manifestRelativePath(proj);
|
|
2685
|
-
const absManifest =
|
|
2696
|
+
const absManifest = path39.resolve(this.opts.root, relManifest);
|
|
2686
2697
|
let text = null;
|
|
2687
2698
|
try {
|
|
2688
|
-
if (
|
|
2699
|
+
if (fs10.existsSync(absManifest)) text = fs10.readFileSync(absManifest, "utf8");
|
|
2689
2700
|
} catch {
|
|
2690
2701
|
text = null;
|
|
2691
2702
|
}
|
|
@@ -2815,9 +2826,9 @@ function pruneArtifactProjects(a) {
|
|
|
2815
2826
|
return { ...a, projects, findings };
|
|
2816
2827
|
}
|
|
2817
2828
|
function projectByPath(a, projectPath) {
|
|
2818
|
-
const want =
|
|
2829
|
+
const want = path39.normalize(projectPath === "" ? "." : projectPath);
|
|
2819
2830
|
for (const proj of a.projects ?? []) {
|
|
2820
|
-
const got =
|
|
2831
|
+
const got = path39.normalize(proj.path === "" ? "." : proj.path);
|
|
2821
2832
|
if (got === want) return proj;
|
|
2822
2833
|
}
|
|
2823
2834
|
return void 0;
|
|
@@ -2854,12 +2865,12 @@ function buildProjectRefs(rootDir, projects) {
|
|
|
2854
2865
|
return refs.length > 0 ? refs : void 0;
|
|
2855
2866
|
}
|
|
2856
2867
|
function projectForFile(root2, a, filePath) {
|
|
2857
|
-
const dir =
|
|
2868
|
+
const dir = path39.dirname(path39.resolve(filePath));
|
|
2858
2869
|
let best;
|
|
2859
2870
|
let bestLen = -1;
|
|
2860
2871
|
for (const proj of a.projects ?? []) {
|
|
2861
|
-
const projDir =
|
|
2862
|
-
if ((dir === projDir || dir.startsWith(projDir +
|
|
2872
|
+
const projDir = path39.resolve(root2, proj.path);
|
|
2873
|
+
if ((dir === projDir || dir.startsWith(projDir + path39.sep)) && projDir.length > bestLen) {
|
|
2863
2874
|
best = proj;
|
|
2864
2875
|
bestLen = projDir.length;
|
|
2865
2876
|
}
|
|
@@ -2867,7 +2878,7 @@ function projectForFile(root2, a, filePath) {
|
|
|
2867
2878
|
return best;
|
|
2868
2879
|
}
|
|
2869
2880
|
function sameProject(location, projectPath) {
|
|
2870
|
-
return
|
|
2881
|
+
return path39.normalize(location) === path39.normalize(projectPath);
|
|
2871
2882
|
}
|
|
2872
2883
|
function hasReleaseDates(a) {
|
|
2873
2884
|
for (const proj of a.projects ?? []) {
|
|
@@ -2937,10 +2948,10 @@ function buildBreakdown(rootDir, projects) {
|
|
|
2937
2948
|
const relManifest = manifestRelativePath(p);
|
|
2938
2949
|
if (isPrunedWorkspacePath(p.path) || isPrunedWorkspacePath(relManifest)) continue;
|
|
2939
2950
|
const ecosystem = osvEcosystem(p.type);
|
|
2940
|
-
const absManifest =
|
|
2951
|
+
const absManifest = path39.resolve(rootDir, relManifest);
|
|
2941
2952
|
let text = null;
|
|
2942
2953
|
try {
|
|
2943
|
-
if (
|
|
2954
|
+
if (fs10.existsSync(absManifest)) text = fs10.readFileSync(absManifest, "utf8");
|
|
2944
2955
|
} catch {
|
|
2945
2956
|
text = null;
|
|
2946
2957
|
}
|
|
@@ -3005,34 +3016,34 @@ function buildBreakdown(rootDir, projects) {
|
|
|
3005
3016
|
}
|
|
3006
3017
|
function manifestRelativePath(proj) {
|
|
3007
3018
|
const base = proj.path === "." || proj.path === "" ? "" : proj.path;
|
|
3008
|
-
const
|
|
3019
|
+
const join29 = (name) => base ? path39.join(base, name) : name;
|
|
3009
3020
|
switch (proj.type) {
|
|
3010
3021
|
case "node":
|
|
3011
3022
|
case "typescript":
|
|
3012
|
-
return
|
|
3023
|
+
return join29("package.json");
|
|
3013
3024
|
case "python":
|
|
3014
|
-
return
|
|
3025
|
+
return join29("pyproject.toml");
|
|
3015
3026
|
case "go":
|
|
3016
|
-
return
|
|
3027
|
+
return join29("go.mod");
|
|
3017
3028
|
case "rust":
|
|
3018
|
-
return
|
|
3029
|
+
return join29("Cargo.toml");
|
|
3019
3030
|
case "ruby":
|
|
3020
|
-
return
|
|
3031
|
+
return join29("Gemfile");
|
|
3021
3032
|
case "php":
|
|
3022
|
-
return
|
|
3033
|
+
return join29("composer.json");
|
|
3023
3034
|
case "java":
|
|
3024
3035
|
case "kotlin":
|
|
3025
3036
|
case "scala":
|
|
3026
3037
|
case "groovy":
|
|
3027
|
-
return
|
|
3038
|
+
return join29("pom.xml");
|
|
3028
3039
|
case "dotnet":
|
|
3029
|
-
return
|
|
3040
|
+
return join29(proj.name ? `${proj.name}.csproj` : "Directory.Build.props");
|
|
3030
3041
|
case "dart":
|
|
3031
|
-
return
|
|
3042
|
+
return join29("pubspec.yaml");
|
|
3032
3043
|
case "elixir":
|
|
3033
|
-
return
|
|
3044
|
+
return join29("mix.exs");
|
|
3034
3045
|
default:
|
|
3035
|
-
return
|
|
3046
|
+
return join29("package.json");
|
|
3036
3047
|
}
|
|
3037
3048
|
}
|
|
3038
3049
|
function lockfileRelativePath(rootDir, proj) {
|
|
@@ -3063,9 +3074,9 @@ function lockfileRelativePath(rootDir, proj) {
|
|
|
3063
3074
|
const dirsToTry = base ? [base, ""] : [""];
|
|
3064
3075
|
for (const dir of dirsToTry) {
|
|
3065
3076
|
for (const name of candidateNames) {
|
|
3066
|
-
const rel = dir ?
|
|
3077
|
+
const rel = dir ? path39.join(dir, name) : name;
|
|
3067
3078
|
try {
|
|
3068
|
-
if (
|
|
3079
|
+
if (fs10.existsSync(path39.join(rootDir, rel))) return rel;
|
|
3069
3080
|
} catch {
|
|
3070
3081
|
}
|
|
3071
3082
|
}
|
|
@@ -3136,10 +3147,10 @@ function lookupImportFiles(map, pkg) {
|
|
|
3136
3147
|
}
|
|
3137
3148
|
function firstPackageMentionLine(root2, relFile, pkg) {
|
|
3138
3149
|
try {
|
|
3139
|
-
const abs =
|
|
3140
|
-
const stat2 =
|
|
3150
|
+
const abs = path39.resolve(root2, relFile);
|
|
3151
|
+
const stat2 = fs10.statSync(abs);
|
|
3141
3152
|
if (!stat2.isFile() || stat2.size > 256 * 1024) return null;
|
|
3142
|
-
const text =
|
|
3153
|
+
const text = fs10.readFileSync(abs, "utf8");
|
|
3143
3154
|
const tokens = [pkg];
|
|
3144
3155
|
if (pkg.startsWith("@")) {
|
|
3145
3156
|
const parts = pkg.split("/");
|
|
@@ -3291,7 +3302,7 @@ function hoverMarkdown(dep, contribution) {
|
|
|
3291
3302
|
return lines.join("\n");
|
|
3292
3303
|
}
|
|
3293
3304
|
function startLanguageServer(opts) {
|
|
3294
|
-
if (!
|
|
3305
|
+
if (!fs10.existsSync(opts.root)) {
|
|
3295
3306
|
process.stderr.write(`vg lsp: root does not exist: ${opts.root}
|
|
3296
3307
|
`);
|
|
3297
3308
|
process.exit(1);
|
|
@@ -3333,10 +3344,90 @@ function registerLsp(program) {
|
|
|
3333
3344
|
});
|
|
3334
3345
|
applyGlobalOptions(cmd);
|
|
3335
3346
|
}
|
|
3347
|
+
var HOOK_NEEDLE = "vg hook pre-tool-use";
|
|
3348
|
+
var MATCHER = "Grep|Glob";
|
|
3349
|
+
var HOOK_TIMEOUT_S = 10;
|
|
3350
|
+
function hookCommand(vgBin) {
|
|
3351
|
+
return `${vgBin} hook pre-tool-use`;
|
|
3352
|
+
}
|
|
3353
|
+
function installClaudeHooks(root2, vgBin = "vg") {
|
|
3354
|
+
const file = path39.join(root2, ".claude", "settings.json");
|
|
3355
|
+
const rel = path39.join(".claude", "settings.json");
|
|
3356
|
+
let settings = {};
|
|
3357
|
+
if (fs10.existsSync(file)) {
|
|
3358
|
+
try {
|
|
3359
|
+
const parsed = JSON.parse(fs10.readFileSync(file, "utf8"));
|
|
3360
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
3361
|
+
return { file: rel, status: "skipped", note: "settings.json is not a JSON object \u2014 left untouched" };
|
|
3362
|
+
}
|
|
3363
|
+
settings = parsed;
|
|
3364
|
+
} catch {
|
|
3365
|
+
return { file: rel, status: "skipped", note: "settings.json is not parseable JSON \u2014 left untouched (fix it and rerun)" };
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
const hooks = settings.hooks ??= {};
|
|
3369
|
+
if (typeof hooks !== "object" || Array.isArray(hooks)) {
|
|
3370
|
+
return { file: rel, status: "skipped", note: '"hooks" is not an object \u2014 left untouched' };
|
|
3371
|
+
}
|
|
3372
|
+
const pre = hooks.PreToolUse ??= [];
|
|
3373
|
+
if (!Array.isArray(pre)) {
|
|
3374
|
+
return { file: rel, status: "skipped", note: '"hooks.PreToolUse" is not an array \u2014 left untouched' };
|
|
3375
|
+
}
|
|
3376
|
+
const desired = { type: "command", command: hookCommand(vgBin), timeout: HOOK_TIMEOUT_S };
|
|
3377
|
+
for (const group of pre) {
|
|
3378
|
+
for (const entry of group.hooks ?? []) {
|
|
3379
|
+
if (typeof entry.command === "string" && entry.command.includes(HOOK_NEEDLE)) {
|
|
3380
|
+
if (entry.command === desired.command && entry.timeout === desired.timeout && group.matcher === MATCHER) {
|
|
3381
|
+
return { file: rel, status: "unchanged" };
|
|
3382
|
+
}
|
|
3383
|
+
entry.command = desired.command;
|
|
3384
|
+
entry.timeout = desired.timeout;
|
|
3385
|
+
group.matcher = MATCHER;
|
|
3386
|
+
writeSettings(file, settings);
|
|
3387
|
+
return { file: rel, status: "written", note: "updated existing vg hook entry" };
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
pre.push({ matcher: MATCHER, hooks: [desired] });
|
|
3392
|
+
writeSettings(file, settings);
|
|
3393
|
+
return { file: rel, status: "written" };
|
|
3394
|
+
}
|
|
3395
|
+
function uninstallClaudeHooks(root2) {
|
|
3396
|
+
const file = path39.join(root2, ".claude", "settings.json");
|
|
3397
|
+
const rel = path39.join(".claude", "settings.json");
|
|
3398
|
+
if (!fs10.existsSync(file)) return { file: rel, status: "unchanged" };
|
|
3399
|
+
let settings;
|
|
3400
|
+
try {
|
|
3401
|
+
settings = JSON.parse(fs10.readFileSync(file, "utf8"));
|
|
3402
|
+
} catch {
|
|
3403
|
+
return { file: rel, status: "skipped", note: "settings.json is not parseable JSON \u2014 left untouched" };
|
|
3404
|
+
}
|
|
3405
|
+
const hooks = settings.hooks;
|
|
3406
|
+
const pre = hooks?.PreToolUse;
|
|
3407
|
+
if (!Array.isArray(pre)) return { file: rel, status: "unchanged" };
|
|
3408
|
+
let removed = false;
|
|
3409
|
+
for (const group of pre) {
|
|
3410
|
+
const before = group.hooks?.length ?? 0;
|
|
3411
|
+
group.hooks = (group.hooks ?? []).filter((e) => !(typeof e.command === "string" && e.command.includes(HOOK_NEEDLE)));
|
|
3412
|
+
if (group.hooks.length !== before) removed = true;
|
|
3413
|
+
}
|
|
3414
|
+
const kept = pre.filter((g) => (g.hooks?.length ?? 0) > 0);
|
|
3415
|
+
if (!removed) return { file: rel, status: "unchanged" };
|
|
3416
|
+
if (kept.length) hooks.PreToolUse = kept;
|
|
3417
|
+
else delete hooks.PreToolUse;
|
|
3418
|
+
if (hooks && Object.keys(hooks).length === 0) delete settings.hooks;
|
|
3419
|
+
writeSettings(file, settings);
|
|
3420
|
+
return { file: rel, status: "written" };
|
|
3421
|
+
}
|
|
3422
|
+
function writeSettings(file, settings) {
|
|
3423
|
+
fs10.mkdirSync(path39.dirname(file), { recursive: true });
|
|
3424
|
+
fs10.writeFileSync(file, `${JSON.stringify(settings, null, 2)}
|
|
3425
|
+
`);
|
|
3426
|
+
}
|
|
3336
3427
|
|
|
3337
3428
|
// src/commands/install.ts
|
|
3338
3429
|
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) {
|
|
3430
|
+
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
3431
|
const global = readGlobal(this);
|
|
3341
3432
|
const root2 = rootOf(global);
|
|
3342
3433
|
const detected = opts.detect ? detectAssistants(root2) : [];
|
|
@@ -3400,6 +3491,12 @@ function registerInstall(program) {
|
|
|
3400
3491
|
for (const r of results) {
|
|
3401
3492
|
info(`${c.green("\u2714")} ${c.bold(r.id)} \u2014 wrote ${r.wrote.join(", ")}${r.skipped.length ? c.dim(` (skipped ${r.skipped.join(", ")})`) : ""}`);
|
|
3402
3493
|
}
|
|
3494
|
+
if (opts.hooks && targets.some((a) => a.id === "claude")) {
|
|
3495
|
+
const vgBin = launch.command === "npx" ? null : launch.command;
|
|
3496
|
+
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" };
|
|
3497
|
+
if (hooksResult.status === "written") info(`${c.green("\u2714")} ${c.bold("hooks")} \u2014 wrote PreToolUse enrichment into ${hooksResult.file}`);
|
|
3498
|
+
else if (hooksResult.note) info(`${c.yellow("!")} hooks \u2014 ${hooksResult.note}`);
|
|
3499
|
+
}
|
|
3403
3500
|
if (launch.note && results.some((r) => r.note)) info(`${c.yellow("!")} ${launch.note}`);
|
|
3404
3501
|
if (smallRepo) info(c.dim(` note: small repo (${fileCount} files) \u2014 nudge says searching is fine; vg is still used for impact/tests`));
|
|
3405
3502
|
info(c.dim(` wrote ${navConfig} \u2014 deferred-loading config for Claude-API agents (lower per-step token cost)`));
|
|
@@ -3410,6 +3507,10 @@ function registerInstall(program) {
|
|
|
3410
3507
|
const global = readGlobal(this);
|
|
3411
3508
|
const root2 = rootOf(global);
|
|
3412
3509
|
const results = tools.map(resolve5).map((a) => ({ id: a.id, removed: uninstallAssistant(a, root2, !!opts.purge) }));
|
|
3510
|
+
if (tools.map(resolve5).some((a) => a.id === "claude")) {
|
|
3511
|
+
const hooksResult = uninstallClaudeHooks(root2);
|
|
3512
|
+
if (hooksResult.status === "written") results.find((r) => r.id === "claude")?.removed.push(`${hooksResult.file} (vg hook entries)`);
|
|
3513
|
+
}
|
|
3413
3514
|
if (global.json) {
|
|
3414
3515
|
json({ root: root2, results });
|
|
3415
3516
|
return;
|
|
@@ -3434,14 +3535,289 @@ function resolve5(id) {
|
|
|
3434
3535
|
}
|
|
3435
3536
|
return a;
|
|
3436
3537
|
}
|
|
3538
|
+
var RELEVANCE_MODULE_NAME = "@vibgrate/relevance";
|
|
3539
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
3540
|
+
function registryBase(opts) {
|
|
3541
|
+
return (process.env.VIBGRATE_MODULE_REGISTRY || opts.registry || DEFAULT_REGISTRY).replace(/\/+$/, "");
|
|
3542
|
+
}
|
|
3543
|
+
function stateFile() {
|
|
3544
|
+
return path39.join(path39.dirname(relevanceModuleDir()), "consent.json");
|
|
3545
|
+
}
|
|
3546
|
+
function readConsent() {
|
|
3547
|
+
try {
|
|
3548
|
+
return JSON.parse(fs10.readFileSync(stateFile(), "utf8"));
|
|
3549
|
+
} catch {
|
|
3550
|
+
return {};
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3553
|
+
function writeConsent(state) {
|
|
3554
|
+
try {
|
|
3555
|
+
fs10.mkdirSync(path39.dirname(stateFile()), { recursive: true });
|
|
3556
|
+
fs10.writeFileSync(stateFile(), JSON.stringify(state));
|
|
3557
|
+
} catch {
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
function kernelDisabled() {
|
|
3561
|
+
const v = process.env.VIBGRATE_NO_KERNEL;
|
|
3562
|
+
return v === "1" || v === "true";
|
|
3563
|
+
}
|
|
3564
|
+
function moduleInstalled() {
|
|
3565
|
+
try {
|
|
3566
|
+
const meta = JSON.parse(fs10.readFileSync(path39.join(relevanceModuleDir(), ".module.json"), "utf8"));
|
|
3567
|
+
if (fs10.existsSync(path39.join(relevanceModuleDir(), "index.js"))) {
|
|
3568
|
+
return { installed: true, version: meta.version };
|
|
3569
|
+
}
|
|
3570
|
+
} catch {
|
|
3571
|
+
}
|
|
3572
|
+
return { installed: false };
|
|
3573
|
+
}
|
|
3574
|
+
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.";
|
|
3575
|
+
function verifyIntegrity(buf, integrity, shasum) {
|
|
3576
|
+
if (integrity) {
|
|
3577
|
+
const [algo, expected] = integrity.split("-", 2);
|
|
3578
|
+
if (!algo || !expected) throw new Error("malformed integrity metadata");
|
|
3579
|
+
const actual = createHash(algo).update(buf).digest("base64");
|
|
3580
|
+
if (actual !== expected) throw new Error(`integrity mismatch (${algo})`);
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
if (shasum) {
|
|
3584
|
+
const actual = createHash("sha1").update(buf).digest("hex");
|
|
3585
|
+
if (actual !== shasum) throw new Error("integrity mismatch (shasum)");
|
|
3586
|
+
return;
|
|
3587
|
+
}
|
|
3588
|
+
throw new Error("registry provided no integrity metadata");
|
|
3589
|
+
}
|
|
3590
|
+
function untar(data) {
|
|
3591
|
+
const out2 = [];
|
|
3592
|
+
let offset = 0;
|
|
3593
|
+
let pendingName = null;
|
|
3594
|
+
while (offset + 512 <= data.length) {
|
|
3595
|
+
const block = data.subarray(offset, offset + 512);
|
|
3596
|
+
offset += 512;
|
|
3597
|
+
if (block.every((b) => b === 0)) continue;
|
|
3598
|
+
const rawName = block.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
|
|
3599
|
+
const size = parseInt(block.subarray(124, 136).toString("utf8").replace(/\0.*$/, "").trim() || "0", 8);
|
|
3600
|
+
const type = String.fromCharCode(block[156]);
|
|
3601
|
+
const prefix = block.subarray(345, 500).toString("utf8").replace(/\0.*$/, "");
|
|
3602
|
+
const body = data.subarray(offset, offset + size);
|
|
3603
|
+
offset += Math.ceil(size / 512) * 512;
|
|
3604
|
+
if (type === "L") {
|
|
3605
|
+
pendingName = body.toString("utf8").replace(/\0.*$/, "");
|
|
3606
|
+
continue;
|
|
3607
|
+
}
|
|
3608
|
+
if (type === "x" || type === "g") {
|
|
3609
|
+
const m = /(?:^|\n)\d+ path=([^\n]+)\n/.exec(body.toString("utf8"));
|
|
3610
|
+
if (m) pendingName = m[1];
|
|
3611
|
+
continue;
|
|
3612
|
+
}
|
|
3613
|
+
if (type !== "0" && type !== "\0") continue;
|
|
3614
|
+
const name = pendingName ?? (prefix ? `${prefix}/${rawName}` : rawName);
|
|
3615
|
+
pendingName = null;
|
|
3616
|
+
if (name.split("/").includes("..") || path39.isAbsolute(name)) {
|
|
3617
|
+
throw new Error(`unsafe path in tarball: ${name}`);
|
|
3618
|
+
}
|
|
3619
|
+
out2.push({ name, body: Buffer.from(body) });
|
|
3620
|
+
}
|
|
3621
|
+
return out2;
|
|
3622
|
+
}
|
|
3623
|
+
async function installRelevanceModule(opts = {}) {
|
|
3624
|
+
if (kernelDisabled()) return { status: "disabled", detail: "VIBGRATE_NO_KERNEL is set" };
|
|
3625
|
+
const existing = moduleInstalled();
|
|
3626
|
+
if (existing.installed && !opts.force) return { status: "already-installed", version: existing.version };
|
|
3627
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
3628
|
+
const base = registryBase(opts);
|
|
3629
|
+
try {
|
|
3630
|
+
const metaRes = await doFetch(`${base}/${RELEVANCE_MODULE_NAME.replace("/", "%2f")}`);
|
|
3631
|
+
if (!metaRes.ok) return { status: "unavailable", detail: `registry ${metaRes.status}` };
|
|
3632
|
+
const meta = await metaRes.json();
|
|
3633
|
+
const version = meta["dist-tags"]?.latest;
|
|
3634
|
+
const dist = version ? meta.versions?.[version]?.dist : void 0;
|
|
3635
|
+
if (!version || !dist?.tarball) return { status: "unavailable", detail: "no published version" };
|
|
3636
|
+
const tarRes = await doFetch(dist.tarball);
|
|
3637
|
+
if (!tarRes.ok) return { status: "unavailable", detail: `tarball ${tarRes.status}` };
|
|
3638
|
+
const gz = Buffer.from(await tarRes.arrayBuffer());
|
|
3639
|
+
verifyIntegrity(gz, dist.integrity, dist.shasum);
|
|
3640
|
+
const entries = untar(zlib.gunzipSync(gz));
|
|
3641
|
+
const dir = relevanceModuleDir();
|
|
3642
|
+
fs10.rmSync(dir, { recursive: true, force: true });
|
|
3643
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
3644
|
+
let wrote = 0;
|
|
3645
|
+
for (const e of entries) {
|
|
3646
|
+
let rel = null;
|
|
3647
|
+
if (e.name.startsWith("package/dist/")) rel = e.name.slice("package/dist/".length);
|
|
3648
|
+
else if (e.name === "package/LICENSE" || e.name === "package/README.md") rel = e.name.slice("package/".length);
|
|
3649
|
+
if (!rel) continue;
|
|
3650
|
+
const target = path39.join(dir, rel);
|
|
3651
|
+
if (!target.startsWith(dir + path39.sep) && target !== dir) throw new Error(`unsafe extract path: ${rel}`);
|
|
3652
|
+
fs10.mkdirSync(path39.dirname(target), { recursive: true });
|
|
3653
|
+
fs10.writeFileSync(target, e.body);
|
|
3654
|
+
wrote += 1;
|
|
3655
|
+
}
|
|
3656
|
+
if (!wrote || !fs10.existsSync(path39.join(dir, "index.js"))) {
|
|
3657
|
+
fs10.rmSync(dir, { recursive: true, force: true });
|
|
3658
|
+
return { status: "unavailable", detail: "package layout not recognized (no dist/index.js)" };
|
|
3659
|
+
}
|
|
3660
|
+
fs10.writeFileSync(path39.join(dir, ".module.json"), JSON.stringify({ name: RELEVANCE_MODULE_NAME, version }));
|
|
3661
|
+
resetRelevanceProviderCache();
|
|
3662
|
+
return { status: "installed", version };
|
|
3663
|
+
} catch (e) {
|
|
3664
|
+
return { status: "unavailable", detail: String(e.message ?? e).slice(0, 200) };
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
function removeRelevanceModule() {
|
|
3668
|
+
fs10.rmSync(relevanceModuleDir(), { recursive: true, force: true });
|
|
3669
|
+
resetRelevanceProviderCache();
|
|
3670
|
+
}
|
|
3671
|
+
async function ensureRelevanceModule(io = {}) {
|
|
3672
|
+
try {
|
|
3673
|
+
if (kernelDisabled()) return { status: "disabled" };
|
|
3674
|
+
const existing = moduleInstalled();
|
|
3675
|
+
if (existing.installed) return { status: "already-installed", version: existing.version };
|
|
3676
|
+
if (readConsent().relevance === "denied") return { status: "declined" };
|
|
3677
|
+
return await installRelevanceModule({ fetchImpl: io.fetchImpl });
|
|
3678
|
+
} catch {
|
|
3679
|
+
return { status: "unavailable", detail: "auto-install failed" };
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
// src/commands/module.ts
|
|
3684
|
+
function registerModule(program) {
|
|
3685
|
+
const cmd = program.command("module").description("manage optional local modules (relevance)");
|
|
3686
|
+
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) {
|
|
3687
|
+
const global = readGlobal(this);
|
|
3688
|
+
requireRelevance(name);
|
|
3689
|
+
if (kernelDisabled()) {
|
|
3690
|
+
throw new CliError("VIBGRATE_NO_KERNEL is set \u2014 unset it to install the relevance module", ExitCode.USAGE_ERROR);
|
|
3691
|
+
}
|
|
3692
|
+
if (!opts.yes && process.stdin.isTTY && process.stdout.isTTY) {
|
|
3693
|
+
const ok = await confirm(`${DISCLOSURE}
|
|
3694
|
+
Install now? [Y/n] `);
|
|
3695
|
+
if (!ok) {
|
|
3696
|
+
writeConsent({ ...readConsent(), relevance: "denied" });
|
|
3697
|
+
info("not installed");
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
writeConsent({ ...readConsent(), relevance: "granted" });
|
|
3702
|
+
const result = await installRelevanceModule({ force: opts.force });
|
|
3703
|
+
if (global.json) {
|
|
3704
|
+
json(result);
|
|
3705
|
+
if (result.status === "unavailable") process.exitCode = ExitCode.ERROR;
|
|
3706
|
+
return;
|
|
3707
|
+
}
|
|
3708
|
+
if (result.status === "installed") out(`installed ${RELEVANCE_MODULE_NAME}@${result.version}`);
|
|
3709
|
+
else if (result.status === "already-installed") out(`already installed (${result.version ?? "unknown"}) \u2014 use --force to reinstall`);
|
|
3710
|
+
else throw new CliError(`install failed: ${result.detail ?? result.status} \u2014 check network access to the registry, or retry later`, ExitCode.ERROR);
|
|
3711
|
+
});
|
|
3712
|
+
cmd.command("remove").description("remove an installed module").argument("<name>", "module name (supported: relevance)").action(async function(name) {
|
|
3713
|
+
requireRelevance(name);
|
|
3714
|
+
removeRelevanceModule();
|
|
3715
|
+
out("removed");
|
|
3716
|
+
});
|
|
3717
|
+
cmd.command("status").description("show installed modules and whether they load").action(async function() {
|
|
3718
|
+
const global = readGlobal(this);
|
|
3719
|
+
const installed = moduleInstalled();
|
|
3720
|
+
resetRelevanceProviderCache();
|
|
3721
|
+
const provider = installed.installed ? await loadRelevanceProvider() : null;
|
|
3722
|
+
const status = {
|
|
3723
|
+
relevance: {
|
|
3724
|
+
installed: installed.installed,
|
|
3725
|
+
version: installed.version ?? null,
|
|
3726
|
+
loadable: !!provider,
|
|
3727
|
+
providerVersion: provider ? provider.version() : null,
|
|
3728
|
+
disabled: kernelDisabled(),
|
|
3729
|
+
consent: readConsent().relevance ?? "unset"
|
|
3730
|
+
}
|
|
3731
|
+
};
|
|
3732
|
+
if (global.json) {
|
|
3733
|
+
json(status);
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
const r = status.relevance;
|
|
3737
|
+
out(`relevance: ${r.installed ? `installed ${r.version}` : "not installed"}${r.disabled ? " (disabled via VIBGRATE_NO_KERNEL)" : ""}`);
|
|
3738
|
+
if (r.installed) out(` loads: ${r.loadable ? `yes (${r.providerVersion})` : "no"}`);
|
|
3739
|
+
info(c.dim(` consent: ${r.consent}`));
|
|
3740
|
+
});
|
|
3741
|
+
applyGlobalOptions(cmd);
|
|
3742
|
+
}
|
|
3743
|
+
function requireRelevance(name) {
|
|
3744
|
+
if (name !== "relevance") {
|
|
3745
|
+
throw usageError(`unknown module '${name}' \u2014 supported modules: relevance`);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
function confirm(question) {
|
|
3749
|
+
return new Promise((resolve21) => {
|
|
3750
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
3751
|
+
rl.question(question, (answer) => {
|
|
3752
|
+
rl.close();
|
|
3753
|
+
resolve21(answer.trim() === "" || /^y(es)?$/i.test(answer.trim()));
|
|
3754
|
+
});
|
|
3755
|
+
});
|
|
3756
|
+
}
|
|
3757
|
+
var MAX_HOOK_MATCHES = 5;
|
|
3758
|
+
var MIN_PATTERN_CHARS = 3;
|
|
3759
|
+
function patternToQuery(pattern) {
|
|
3760
|
+
return pattern.replace(/\\[dwsbDWSB]/g, " ").replace(/[\\^$.*+?()[\]{}|]/g, " ").replace(/\s+/g, " ").trim();
|
|
3761
|
+
}
|
|
3762
|
+
function hookContext(payloadText, root2, graphOverride) {
|
|
3763
|
+
let payload;
|
|
3764
|
+
try {
|
|
3765
|
+
payload = JSON.parse(payloadText);
|
|
3766
|
+
} catch {
|
|
3767
|
+
return null;
|
|
3768
|
+
}
|
|
3769
|
+
if (payload.tool_name !== "Grep" && payload.tool_name !== "Glob") return null;
|
|
3770
|
+
const raw = payload.tool_input?.pattern ?? payload.tool_input?.query ?? "";
|
|
3771
|
+
const query = patternToQuery(String(raw));
|
|
3772
|
+
if (query.length < MIN_PATTERN_CHARS) return null;
|
|
3773
|
+
const graphPath = resolveGraphPath(root2, graphOverride);
|
|
3774
|
+
let graph;
|
|
3775
|
+
try {
|
|
3776
|
+
const preferred = loadGraphPreferIndex(root2, graphPath);
|
|
3777
|
+
graph = preferred ? preferred.graph : parseGraph(fs10.readFileSync(graphPath, "utf8"));
|
|
3778
|
+
} catch {
|
|
3779
|
+
return null;
|
|
3780
|
+
}
|
|
3781
|
+
const result = queryGraph(graph, query, {});
|
|
3782
|
+
const matches = result.matches.slice(0, MAX_HOOK_MATCHES);
|
|
3783
|
+
if (!matches.length) return null;
|
|
3784
|
+
const lines = matches.map(
|
|
3785
|
+
(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]" : ""}`
|
|
3786
|
+
);
|
|
3787
|
+
return [
|
|
3788
|
+
`vg code map \u2014 symbols matching "${query}":`,
|
|
3789
|
+
...lines,
|
|
3790
|
+
"These locations come from the deterministic code graph; prefer them over scanning the raw grep output."
|
|
3791
|
+
].join("\n");
|
|
3792
|
+
}
|
|
3793
|
+
function registerHook(program) {
|
|
3794
|
+
const cmd = program.command("hook", { hidden: true }).description("assistant-host hook endpoints (wired by `vg install --hooks`)");
|
|
3795
|
+
const pre = cmd.command("pre-tool-use").description("PreToolUse enrichment: annotate Grep/Glob calls with graph context (stdin: host hook payload)").action(async function() {
|
|
3796
|
+
const global = readGlobal(this);
|
|
3797
|
+
const root2 = rootOf(global);
|
|
3798
|
+
try {
|
|
3799
|
+
const stdin = fs10.readFileSync(0, "utf8");
|
|
3800
|
+
const context = hookContext(stdin, root2, global.graph);
|
|
3801
|
+
if (context) {
|
|
3802
|
+
process.stdout.write(
|
|
3803
|
+
`${JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: context } })}
|
|
3804
|
+
`
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
} catch {
|
|
3808
|
+
}
|
|
3809
|
+
});
|
|
3810
|
+
applyGlobalOptions(pre);
|
|
3811
|
+
applyGlobalOptions(cmd);
|
|
3812
|
+
}
|
|
3437
3813
|
var HOOK_BEGIN = "# vg:begin";
|
|
3438
3814
|
var HOOK_END = "# vg:end";
|
|
3439
3815
|
function registerShare(program) {
|
|
3440
3816
|
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
3817
|
const global = readGlobal(this);
|
|
3442
3818
|
const root2 = rootOf(global);
|
|
3443
|
-
const gitDir =
|
|
3444
|
-
if (!
|
|
3819
|
+
const gitDir = path39.join(root2, ".git");
|
|
3820
|
+
if (!fs10.existsSync(gitDir)) {
|
|
3445
3821
|
throw new CliError("not a git repository \u2014 run `vg share` inside a git repo", ExitCode.USAGE_ERROR);
|
|
3446
3822
|
}
|
|
3447
3823
|
if (opts.undo) {
|
|
@@ -3462,23 +3838,23 @@ function registerShare(program) {
|
|
|
3462
3838
|
applyGlobalOptions(cmd);
|
|
3463
3839
|
}
|
|
3464
3840
|
function writeVibgrateGitignore(root2, reports) {
|
|
3465
|
-
const dir =
|
|
3466
|
-
|
|
3841
|
+
const dir = path39.join(root2, ".vibgrate");
|
|
3842
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
3467
3843
|
const lines = ["# Managed by `vg share` \u2014 keep graph.json committed, ignore the rest", "cache/", "facts.jsonl", "graph.snap"];
|
|
3468
3844
|
if (!reports) lines.push("graph.html", "GRAPH_REPORT.md");
|
|
3469
|
-
|
|
3845
|
+
fs10.writeFileSync(path39.join(dir, ".gitignore"), `${lines.join("\n")}
|
|
3470
3846
|
`);
|
|
3471
3847
|
}
|
|
3472
3848
|
function writeGitAttributes(root2) {
|
|
3473
|
-
const file =
|
|
3849
|
+
const file = path39.join(root2, ".gitattributes");
|
|
3474
3850
|
const line = ".vibgrate/graph.json merge=vg";
|
|
3475
|
-
let content =
|
|
3851
|
+
let content = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "";
|
|
3476
3852
|
if (!content.split("\n").some((l) => l.trim() === line)) {
|
|
3477
3853
|
content = content.length ? `${content.replace(/\s*$/, "")}
|
|
3478
3854
|
${line}
|
|
3479
3855
|
` : `${line}
|
|
3480
3856
|
`;
|
|
3481
|
-
|
|
3857
|
+
fs10.writeFileSync(file, content);
|
|
3482
3858
|
}
|
|
3483
3859
|
}
|
|
3484
3860
|
function configureMergeDriver(root2) {
|
|
@@ -3487,8 +3863,8 @@ function configureMergeDriver(root2) {
|
|
|
3487
3863
|
}
|
|
3488
3864
|
function installPreCommitHook(root2) {
|
|
3489
3865
|
const hooksDir = hookDir(root2);
|
|
3490
|
-
|
|
3491
|
-
const file =
|
|
3866
|
+
fs10.mkdirSync(hooksDir, { recursive: true });
|
|
3867
|
+
const file = path39.join(hooksDir, "pre-commit");
|
|
3492
3868
|
const block = [
|
|
3493
3869
|
HOOK_BEGIN,
|
|
3494
3870
|
"if command -v vg >/dev/null 2>&1; then",
|
|
@@ -3497,7 +3873,7 @@ function installPreCommitHook(root2) {
|
|
|
3497
3873
|
"fi",
|
|
3498
3874
|
HOOK_END
|
|
3499
3875
|
].join("\n");
|
|
3500
|
-
let content =
|
|
3876
|
+
let content = fs10.existsSync(file) ? fs10.readFileSync(file, "utf8") : "#!/bin/sh\n";
|
|
3501
3877
|
const re = new RegExp(`${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}`);
|
|
3502
3878
|
if (re.test(content)) content = content.replace(re, block);
|
|
3503
3879
|
else content = `${content.replace(/\s*$/, "")}
|
|
@@ -3506,21 +3882,21 @@ ${block}
|
|
|
3506
3882
|
`;
|
|
3507
3883
|
if (!content.startsWith("#!")) content = `#!/bin/sh
|
|
3508
3884
|
${content}`;
|
|
3509
|
-
|
|
3510
|
-
|
|
3885
|
+
fs10.writeFileSync(file, content);
|
|
3886
|
+
fs10.chmodSync(file, 493);
|
|
3511
3887
|
}
|
|
3512
3888
|
function undo(root2) {
|
|
3513
|
-
const hookFile =
|
|
3514
|
-
if (
|
|
3889
|
+
const hookFile = path39.join(hookDir(root2), "pre-commit");
|
|
3890
|
+
if (fs10.existsSync(hookFile)) {
|
|
3515
3891
|
const re = new RegExp(`\\n*${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}\\n*`);
|
|
3516
|
-
const next2 =
|
|
3517
|
-
if (next2.trim() === "#!/bin/sh")
|
|
3518
|
-
else
|
|
3892
|
+
const next2 = fs10.readFileSync(hookFile, "utf8").replace(re, "\n");
|
|
3893
|
+
if (next2.trim() === "#!/bin/sh") fs10.rmSync(hookFile);
|
|
3894
|
+
else fs10.writeFileSync(hookFile, next2);
|
|
3519
3895
|
}
|
|
3520
|
-
const attr =
|
|
3521
|
-
if (
|
|
3522
|
-
const next2 =
|
|
3523
|
-
|
|
3896
|
+
const attr = path39.join(root2, ".gitattributes");
|
|
3897
|
+
if (fs10.existsSync(attr)) {
|
|
3898
|
+
const next2 = fs10.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
|
|
3899
|
+
fs10.writeFileSync(attr, next2);
|
|
3524
3900
|
}
|
|
3525
3901
|
try {
|
|
3526
3902
|
git(root2, ["config", "--remove-section", "merge.vg"]);
|
|
@@ -3530,10 +3906,10 @@ function undo(root2) {
|
|
|
3530
3906
|
function hookDir(root2) {
|
|
3531
3907
|
try {
|
|
3532
3908
|
const configured = git(root2, ["config", "--get", "core.hooksPath"]).trim();
|
|
3533
|
-
if (configured) return
|
|
3909
|
+
if (configured) return path39.resolve(root2, configured);
|
|
3534
3910
|
} catch {
|
|
3535
3911
|
}
|
|
3536
|
-
return
|
|
3912
|
+
return path39.join(root2, ".git", "hooks");
|
|
3537
3913
|
}
|
|
3538
3914
|
function git(root2, args) {
|
|
3539
3915
|
return execFileSync("git", args, { cwd: root2, encoding: "utf8" });
|
|
@@ -3542,28 +3918,14 @@ function escapeRe(s) {
|
|
|
3542
3918
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3543
3919
|
}
|
|
3544
3920
|
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
3921
|
function registerWatch(program) {
|
|
3560
3922
|
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
3923
|
const global = readGlobal(this);
|
|
3562
3924
|
const root2 = rootOf(global);
|
|
3563
3925
|
const debounceMs = Math.max(50, Number(opts.debounce) || DEFAULT_DEBOUNCE_MS);
|
|
3564
|
-
const watchRoots = (paths.length ? paths : ["."]).map((p) =>
|
|
3926
|
+
const watchRoots = (paths.length ? paths : ["."]).map((p) => path39.resolve(root2, p));
|
|
3565
3927
|
for (const w of watchRoots) {
|
|
3566
|
-
if (!
|
|
3928
|
+
if (!fs10.existsSync(w)) {
|
|
3567
3929
|
throw new CliError(`watch path not found: ${w}`, ExitCode.USAGE_ERROR);
|
|
3568
3930
|
}
|
|
3569
3931
|
}
|
|
@@ -3616,16 +3978,12 @@ function registerWatch(program) {
|
|
|
3616
3978
|
const watchers = [];
|
|
3617
3979
|
for (const w of watchRoots) {
|
|
3618
3980
|
try {
|
|
3619
|
-
const watcher =
|
|
3981
|
+
const watcher = fs10.watch(w, { recursive: true }, (_event, filename) => {
|
|
3620
3982
|
if (!filename) {
|
|
3621
3983
|
schedule("change");
|
|
3622
3984
|
return;
|
|
3623
3985
|
}
|
|
3624
|
-
|
|
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
|
-
}
|
|
3986
|
+
if (!isRelevantChange(filename)) return;
|
|
3629
3987
|
schedule(filename);
|
|
3630
3988
|
});
|
|
3631
3989
|
watchers.push(watcher);
|
|
@@ -3633,7 +3991,7 @@ function registerWatch(program) {
|
|
|
3633
3991
|
throw new CliError(`cannot watch ${w}: ${err.message}`, ExitCode.ERROR);
|
|
3634
3992
|
}
|
|
3635
3993
|
}
|
|
3636
|
-
info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) =>
|
|
3994
|
+
info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path39.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
|
|
3637
3995
|
await new Promise((resolve21) => {
|
|
3638
3996
|
const stop = () => {
|
|
3639
3997
|
for (const w of watchers) w.close();
|
|
@@ -3966,10 +4324,10 @@ function normalizeStandards(raw) {
|
|
|
3966
4324
|
}
|
|
3967
4325
|
function loadStandards(root2) {
|
|
3968
4326
|
for (const rel of STANDARDS_FILES) {
|
|
3969
|
-
const p =
|
|
4327
|
+
const p = path39__default.join(root2, rel);
|
|
3970
4328
|
let text;
|
|
3971
4329
|
try {
|
|
3972
|
-
text =
|
|
4330
|
+
text = fs10__default.readFileSync(p, "utf8");
|
|
3973
4331
|
} catch {
|
|
3974
4332
|
continue;
|
|
3975
4333
|
}
|
|
@@ -4687,8 +5045,8 @@ async function runHostBench(options = {}) {
|
|
|
4687
5045
|
}
|
|
4688
5046
|
async function runArmSimulate(input) {
|
|
4689
5047
|
const { arm, lib, modelPath, turns, trie, env, live } = input;
|
|
4690
|
-
const
|
|
4691
|
-
const session = await acquireHostSession(lib,
|
|
5048
|
+
const path41 = `${modelPath}#${arm.id}`;
|
|
5049
|
+
const session = await acquireHostSession(lib, path41);
|
|
4692
5050
|
const system = "You are a coding agent with a Task Capsule.";
|
|
4693
5051
|
const capsule = "function readConfig(): Config { return load(); }";
|
|
4694
5052
|
let last = null;
|
|
@@ -5900,7 +6258,7 @@ function registerModels(program) {
|
|
|
5900
6258
|
);
|
|
5901
6259
|
}
|
|
5902
6260
|
} else {
|
|
5903
|
-
if (!target.path || !
|
|
6261
|
+
if (!target.path || !fs10.existsSync(target.path)) {
|
|
5904
6262
|
throw new CliError(
|
|
5905
6263
|
`model file not found at ${target.path || "(unknown path)"} \u2014 it may already be removed.`,
|
|
5906
6264
|
ExitCode.NOT_FOUND
|
|
@@ -5914,7 +6272,7 @@ function registerModels(program) {
|
|
|
5914
6272
|
}
|
|
5915
6273
|
if (!global.json) info(c.dim(` $ rm ${target.path}`));
|
|
5916
6274
|
try {
|
|
5917
|
-
|
|
6275
|
+
fs10.unlinkSync(target.path);
|
|
5918
6276
|
} catch (e) {
|
|
5919
6277
|
const msg = e instanceof Error ? e.message : String(e);
|
|
5920
6278
|
throw new CliError(`could not delete ${target.path}: ${msg}`, ExitCode.ERROR);
|
|
@@ -6052,9 +6410,9 @@ function registerModels(program) {
|
|
|
6052
6410
|
}
|
|
6053
6411
|
});
|
|
6054
6412
|
if (opts.out) {
|
|
6055
|
-
const outPath =
|
|
6056
|
-
|
|
6057
|
-
|
|
6413
|
+
const outPath = path39.resolve(opts.out);
|
|
6414
|
+
fs10.mkdirSync(path39.dirname(outPath), { recursive: true });
|
|
6415
|
+
fs10.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
|
|
6058
6416
|
`);
|
|
6059
6417
|
if (!global.json) info(c.dim(` wrote ${outPath}`));
|
|
6060
6418
|
}
|
|
@@ -6203,14 +6561,14 @@ function resolveUninstallTarget(name, runtimeOpt) {
|
|
|
6203
6561
|
}
|
|
6204
6562
|
return exact[0];
|
|
6205
6563
|
}
|
|
6206
|
-
const base =
|
|
6564
|
+
const base = path39.basename(wantLc);
|
|
6207
6565
|
const soft = fleet.filter((m) => {
|
|
6208
6566
|
const n = m.name.toLowerCase();
|
|
6209
|
-
return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) ||
|
|
6567
|
+
return n === base || n.endsWith("/" + base) || n.endsWith(wantLc) || path39.basename(n) === base;
|
|
6210
6568
|
});
|
|
6211
6569
|
if (soft.length === 1) return soft[0];
|
|
6212
6570
|
if (soft.length > 1) {
|
|
6213
|
-
const baseHits = soft.filter((m) =>
|
|
6571
|
+
const baseHits = soft.filter((m) => path39.basename(m.name).toLowerCase() === base);
|
|
6214
6572
|
const pool = baseHits.length ? baseHits : soft;
|
|
6215
6573
|
const order = ["ollama", "gguf", "lm-studio"];
|
|
6216
6574
|
for (const rt of order) {
|
|
@@ -6248,11 +6606,11 @@ function printBackends(backends) {
|
|
|
6248
6606
|
}
|
|
6249
6607
|
}
|
|
6250
6608
|
function codeConfigPath(root2) {
|
|
6251
|
-
return
|
|
6609
|
+
return path39.join(root2, ".vibgrate", "code.json");
|
|
6252
6610
|
}
|
|
6253
6611
|
function loadCodeConfig(root2) {
|
|
6254
6612
|
try {
|
|
6255
|
-
const raw = JSON.parse(
|
|
6613
|
+
const raw = JSON.parse(fs10.readFileSync(codeConfigPath(root2), "utf8"));
|
|
6256
6614
|
return sanitize(raw);
|
|
6257
6615
|
} catch {
|
|
6258
6616
|
return {};
|
|
@@ -6319,7 +6677,7 @@ function contextBudgetFor(config, modelContextWindow) {
|
|
|
6319
6677
|
var MCP_CONFIG_FILES = [".cursor/mcp.json", ".vscode/mcp.json", ".mcp.json"];
|
|
6320
6678
|
function readMcpServersFile(file) {
|
|
6321
6679
|
try {
|
|
6322
|
-
const raw = JSON.parse(
|
|
6680
|
+
const raw = JSON.parse(fs10.readFileSync(file, "utf8"));
|
|
6323
6681
|
const map = raw.mcpServers ?? raw.servers;
|
|
6324
6682
|
return map && typeof map === "object" ? parseMcpServers(map) : {};
|
|
6325
6683
|
} catch {
|
|
@@ -6330,7 +6688,7 @@ function discoverMcpServers(root2, ownServers) {
|
|
|
6330
6688
|
const servers = {};
|
|
6331
6689
|
const sources = [];
|
|
6332
6690
|
for (const rel of MCP_CONFIG_FILES) {
|
|
6333
|
-
const found = readMcpServersFile(
|
|
6691
|
+
const found = readMcpServersFile(path39.join(root2, rel));
|
|
6334
6692
|
const names = Object.keys(found);
|
|
6335
6693
|
if (names.length) {
|
|
6336
6694
|
sources.push(rel);
|
|
@@ -6349,6 +6707,9 @@ function registerCode(program) {
|
|
|
6349
6707
|
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
6708
|
const global = readGlobal(this);
|
|
6351
6709
|
const instruction = (instructionParts ?? []).join(" ").trim();
|
|
6710
|
+
if (!global.local) {
|
|
6711
|
+
await ensureRelevanceModule();
|
|
6712
|
+
}
|
|
6352
6713
|
const config = loadCodeConfig(rootOf(global));
|
|
6353
6714
|
let provider = opts.provider ?? config.provider;
|
|
6354
6715
|
let model = opts.model ?? config.model;
|
|
@@ -6359,7 +6720,7 @@ function registerCode(program) {
|
|
|
6359
6720
|
try {
|
|
6360
6721
|
const { parseMode: parseMode2, resolveMode: resolveMode2, readOrchestratorState: readOrchestratorState2, activePin: activePin2 } = await import('./model-orchestrator-LHYPJBFH.js');
|
|
6361
6722
|
const { gatherSystemMemory: gatherSystemMemory2 } = await import('./local-runtime-2ED33KK6.js');
|
|
6362
|
-
const { loadGraph: loadGraph2 } = await import('./load-
|
|
6723
|
+
const { loadGraph: loadGraph2 } = await import('./load-MWG6WZTK.js');
|
|
6363
6724
|
const state = readOrchestratorState2();
|
|
6364
6725
|
const mode = parseMode2(modeFlag) ?? state.defaultMode ?? void 0;
|
|
6365
6726
|
const pin = mode ? activePin2(mode, state) : null;
|
|
@@ -6439,11 +6800,12 @@ function registerCode(program) {
|
|
|
6439
6800
|
const verifyCommand = opts.verify === true ? config.testCommand : typeof opts.verify === "string" ? opts.verify : void 0;
|
|
6440
6801
|
const verify3 = verifyCommand ? { command: verifyCommand } : void 0;
|
|
6441
6802
|
const mcp = discoverMcpServers(rootOf(global), config.mcpServers);
|
|
6442
|
-
|
|
6803
|
+
const stdinFirstTurn = !instruction && !!opts.streamJson && !!opts.session;
|
|
6804
|
+
if (!instruction && !opts.mock && !stdinFirstTurn) {
|
|
6443
6805
|
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
6444
6806
|
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
6807
|
}
|
|
6446
|
-
const { runInteractive } = await import('./interactive-
|
|
6808
|
+
const { runInteractive } = await import('./interactive-TNRE4OEK.js');
|
|
6447
6809
|
await runInteractive(
|
|
6448
6810
|
rootOf(global),
|
|
6449
6811
|
global,
|
|
@@ -6471,9 +6833,9 @@ function registerCode(program) {
|
|
|
6471
6833
|
);
|
|
6472
6834
|
return;
|
|
6473
6835
|
}
|
|
6474
|
-
if (!instruction) throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"`');
|
|
6836
|
+
if (!instruction && !stdinFirstTurn) throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"`');
|
|
6475
6837
|
{
|
|
6476
|
-
const { ensureCodeMap } = await import('./ensure-map-
|
|
6838
|
+
const { ensureCodeMap } = await import('./ensure-map-5YEI7R7V.js');
|
|
6477
6839
|
const mapRoot = rootOf(global);
|
|
6478
6840
|
try {
|
|
6479
6841
|
await ensureCodeMap(mapRoot, global, {
|
|
@@ -6510,7 +6872,7 @@ function registerCode(program) {
|
|
|
6510
6872
|
let mockReply;
|
|
6511
6873
|
if (opts.mock) {
|
|
6512
6874
|
try {
|
|
6513
|
-
mockReply =
|
|
6875
|
+
mockReply = fs10.readFileSync(opts.mock, "utf8");
|
|
6514
6876
|
} catch {
|
|
6515
6877
|
throw new CliError(`couldn't read the --mock file: ${opts.mock}`, ExitCode.USAGE_ERROR);
|
|
6516
6878
|
}
|
|
@@ -6558,20 +6920,20 @@ function registerCode(program) {
|
|
|
6558
6920
|
process.stdout.write(JSON.stringify(line) + "\n");
|
|
6559
6921
|
};
|
|
6560
6922
|
try {
|
|
6561
|
-
const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-
|
|
6923
|
+
const { RunOutcomeRecorder, newOneShotRunId, turnRunId } = await import('./run-outcome-375HMSQG.js');
|
|
6562
6924
|
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-
|
|
6564
|
-
const { nodeCodeFs } = await import('./session-
|
|
6565
|
-
const
|
|
6925
|
+
const { runCodeStreamJson, parseHostMessage } = await import('./stream-json-AUMU3NLV.js');
|
|
6926
|
+
const { nodeCodeFs } = await import('./session-2NGJLI5Y.js');
|
|
6927
|
+
const readline6 = await import('readline');
|
|
6566
6928
|
const child = await import('child_process');
|
|
6567
6929
|
const { loadOrDiscoverFederation } = await import('./federation-MDQPO3PW.js');
|
|
6568
6930
|
const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
|
|
6569
6931
|
const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
|
|
6570
|
-
const { startCodeRuntimeSession } = await import('./runtime-session-
|
|
6571
|
-
const { resolveGraphBackend } = await import('./graph-backend-
|
|
6932
|
+
const { startCodeRuntimeSession } = await import('./runtime-session-3MPWXNRL.js');
|
|
6933
|
+
const { resolveGraphBackend } = await import('./graph-backend-CPHLUKUC.js');
|
|
6572
6934
|
const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
|
|
6573
6935
|
const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
|
|
6574
|
-
const { vgdRequest: vgdRequest2 } = await import('./vgd-
|
|
6936
|
+
const { vgdRequest: vgdRequest2 } = await import('./vgd-Z23PXSP4.js');
|
|
6575
6937
|
const federation = loadOrDiscoverFederation(root2);
|
|
6576
6938
|
const modelProfile = mergeModelExecutionProfile(
|
|
6577
6939
|
resolveModelExecutionProfile({
|
|
@@ -6629,7 +6991,7 @@ ${res.stderr}` : ""),
|
|
|
6629
6991
|
exitCode: res.status ?? 1
|
|
6630
6992
|
};
|
|
6631
6993
|
};
|
|
6632
|
-
const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-
|
|
6994
|
+
const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-D463EHQI.js');
|
|
6633
6995
|
const vgBuiltin = createVgBuiltinMcpTools({
|
|
6634
6996
|
getGraph: () => graph,
|
|
6635
6997
|
root: root2,
|
|
@@ -6653,7 +7015,7 @@ ${res.stderr}` : ""),
|
|
|
6653
7015
|
const os4 = await import('os');
|
|
6654
7016
|
const pathMod = await import('path');
|
|
6655
7017
|
const checkpointIndex = pathMod.join(
|
|
6656
|
-
|
|
7018
|
+
fs10.mkdtempSync(pathMod.join(os4.tmpdir(), "vg-code-cp-")),
|
|
6657
7019
|
"index"
|
|
6658
7020
|
);
|
|
6659
7021
|
const gitRunner = (gitArgs, gitEnv) => {
|
|
@@ -6703,6 +7065,8 @@ ${res.stderr}` : ""),
|
|
|
6703
7065
|
capsule,
|
|
6704
7066
|
files: opts.file.length ? opts.file : void 0,
|
|
6705
7067
|
worktreeOverlay: true,
|
|
7068
|
+
// Real-model host: compaction writes a model checkpoint summary.
|
|
7069
|
+
llmCompaction: true,
|
|
6706
7070
|
// Full coding agent: free discovery by default. Capsule is context only.
|
|
6707
7071
|
advancedMode: true,
|
|
6708
7072
|
externalTools,
|
|
@@ -6717,15 +7081,16 @@ ${res.stderr}` : ""),
|
|
|
6717
7081
|
};
|
|
6718
7082
|
try {
|
|
6719
7083
|
if (opts.session) {
|
|
6720
|
-
const { runCodeStreamJsonSession } = await import('./stream-json-
|
|
6721
|
-
const { runAgent: runAgent2 } = await import('./agent-
|
|
7084
|
+
const { runCodeStreamJsonSession } = await import('./stream-json-AUMU3NLV.js');
|
|
7085
|
+
const { runAgent: runAgent2 } = await import('./agent-HNV2VUCO.js');
|
|
6722
7086
|
const {
|
|
7087
|
+
condenseSession,
|
|
6723
7088
|
loadLatestSession,
|
|
6724
7089
|
newSession,
|
|
6725
7090
|
recordTask,
|
|
6726
7091
|
saveSession,
|
|
6727
7092
|
summarizeSession
|
|
6728
|
-
} = await import('./session-store-
|
|
7093
|
+
} = await import('./session-store-F7NX7SZN.js');
|
|
6729
7094
|
const resumedRecord = opts.continue ? loadLatestSession(root2) : void 0;
|
|
6730
7095
|
let record = resumedRecord ?? newSession(
|
|
6731
7096
|
`s${Date.now().toString(36)}`,
|
|
@@ -6736,13 +7101,13 @@ ${res.stderr}` : ""),
|
|
|
6736
7101
|
const pendingTurns = [];
|
|
6737
7102
|
let wakeTurn;
|
|
6738
7103
|
let ended = false;
|
|
6739
|
-
const pushTurn = (
|
|
7104
|
+
const pushTurn = (turn) => {
|
|
6740
7105
|
if (wakeTurn) {
|
|
6741
7106
|
const wake = wakeTurn;
|
|
6742
7107
|
wakeTurn = void 0;
|
|
6743
|
-
wake(
|
|
6744
|
-
} else if (
|
|
6745
|
-
pendingTurns.push(
|
|
7108
|
+
wake(turn);
|
|
7109
|
+
} else if (turn !== null) {
|
|
7110
|
+
pendingTurns.push(turn);
|
|
6746
7111
|
}
|
|
6747
7112
|
};
|
|
6748
7113
|
const nextTurn = () => {
|
|
@@ -6763,7 +7128,7 @@ ${res.stderr}` : ""),
|
|
|
6763
7128
|
nextTurn,
|
|
6764
7129
|
bindDecisions: (session) => {
|
|
6765
7130
|
streamApprove = (action) => session.approve(action);
|
|
6766
|
-
const rl =
|
|
7131
|
+
const rl = readline6.createInterface({ input: process.stdin });
|
|
6767
7132
|
rl.on("line", (raw) => {
|
|
6768
7133
|
const msg = parseHostMessage(raw);
|
|
6769
7134
|
if (!msg) return;
|
|
@@ -6771,7 +7136,8 @@ ${res.stderr}` : ""),
|
|
|
6771
7136
|
session.submitDecision(msg.id, msg.approve);
|
|
6772
7137
|
runOutcome.noteDecision(msg.id, msg.approve);
|
|
6773
7138
|
} else if (msg.kind === "answer") session.submitAnswer(msg.id, msg.answer);
|
|
6774
|
-
else if (msg.kind === "submit")
|
|
7139
|
+
else if (msg.kind === "submit")
|
|
7140
|
+
pushTurn({ instruction: msg.instruction, agentMode: msg.agentMode, images: msg.images });
|
|
6775
7141
|
else if (msg.kind === "restore") {
|
|
6776
7142
|
void import('./checkpoint-4WFZMKEO.js').then(({ restoreCheckpoint }) => {
|
|
6777
7143
|
const outcome = restoreCheckpoint(gitRunner, {
|
|
@@ -6780,6 +7146,14 @@ ${res.stderr}` : ""),
|
|
|
6780
7146
|
});
|
|
6781
7147
|
emitStream({ event: "checkpoint-restored", commit: msg.commit, ...outcome });
|
|
6782
7148
|
});
|
|
7149
|
+
} else if (msg.kind === "compact") {
|
|
7150
|
+
record = condenseSession(record, Date.now());
|
|
7151
|
+
saveSession(root2, record);
|
|
7152
|
+
emitStream({
|
|
7153
|
+
event: "event",
|
|
7154
|
+
type: "notice",
|
|
7155
|
+
text: "Conversation compacted \u2014 earlier turns condensed into a checkpoint."
|
|
7156
|
+
});
|
|
6783
7157
|
} else if (msg.kind === "cancel") {
|
|
6784
7158
|
session.cancelTurn();
|
|
6785
7159
|
runOutcome.cancelPending();
|
|
@@ -6795,14 +7169,20 @@ ${res.stderr}` : ""),
|
|
|
6795
7169
|
pushTurn(null);
|
|
6796
7170
|
});
|
|
6797
7171
|
},
|
|
6798
|
-
runTurn: ({ instruction: turnInstruction,
|
|
7172
|
+
runTurn: ({ instruction: turnInstruction, signal, session, agentMode, auto: turnAuto, images }) => {
|
|
7173
|
+
const priorSummary = summarizeSession(record) || void 0;
|
|
6799
7174
|
turnIndex++;
|
|
6800
7175
|
runOutcome.beginRun(turnRunId(record.id, turnIndex), turnInstruction);
|
|
7176
|
+
const plan = agentMode === "plan";
|
|
7177
|
+
streamApprove = plan ? async () => false : (action) => session.approve(action);
|
|
6801
7178
|
return runAgent2({
|
|
6802
7179
|
...baseAgentOptions,
|
|
6803
7180
|
instruction: turnInstruction,
|
|
6804
7181
|
priorSummary,
|
|
6805
7182
|
signal,
|
|
7183
|
+
auto: turnAuto,
|
|
7184
|
+
plan,
|
|
7185
|
+
images,
|
|
6806
7186
|
approve: session.approve,
|
|
6807
7187
|
askUser: session.askUser,
|
|
6808
7188
|
onEvent: session.onEvent
|
|
@@ -6831,7 +7211,7 @@ ${res.stderr}` : ""),
|
|
|
6831
7211
|
emit: emitAndRecord,
|
|
6832
7212
|
bindDecisions: (session) => {
|
|
6833
7213
|
streamApprove = (action) => session.approve(action);
|
|
6834
|
-
const rl =
|
|
7214
|
+
const rl = readline6.createInterface({ input: process.stdin });
|
|
6835
7215
|
rl.on("line", (raw) => {
|
|
6836
7216
|
const msg = parseHostMessage(raw);
|
|
6837
7217
|
if (!msg) return;
|
|
@@ -6866,17 +7246,17 @@ ${res.stderr}` : ""),
|
|
|
6866
7246
|
if (!autonomous && !tty) {
|
|
6867
7247
|
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
7248
|
}
|
|
6869
|
-
const { agentTask } = await import('./interactive-
|
|
6870
|
-
const { nodeCodeFs } = await import('./session-
|
|
7249
|
+
const { agentTask } = await import('./interactive-TNRE4OEK.js');
|
|
7250
|
+
const { nodeCodeFs } = await import('./session-2NGJLI5Y.js');
|
|
6871
7251
|
const { TtyPrompter } = await import('./ui-K7D3BCHD.js');
|
|
6872
7252
|
let priorSummary;
|
|
6873
7253
|
if (opts.continue) {
|
|
6874
|
-
const { loadLatestSession, summarizeSession } = await import('./session-store-
|
|
7254
|
+
const { loadLatestSession, summarizeSession } = await import('./session-store-F7NX7SZN.js');
|
|
6875
7255
|
const prev = loadLatestSession(root2);
|
|
6876
7256
|
if (prev) priorSummary = summarizeSession(prev);
|
|
6877
7257
|
}
|
|
6878
7258
|
const prompter = tty ? new TtyPrompter() : void 0;
|
|
6879
|
-
const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-
|
|
7259
|
+
const { createVgBuiltinMcpTools, mergeExternalToolsets } = await import('./vg-mcp-bridge-D463EHQI.js');
|
|
6880
7260
|
const vgBuiltin = createVgBuiltinMcpTools({
|
|
6881
7261
|
getGraph: () => graph,
|
|
6882
7262
|
root: root2,
|
|
@@ -6900,11 +7280,11 @@ ${res.stderr}` : ""),
|
|
|
6900
7280
|
const { loadFederation } = await import('./federation-MDQPO3PW.js');
|
|
6901
7281
|
const { resolveExecutionEnv } = await import('./execution-env-4MS5AYAN.js');
|
|
6902
7282
|
const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-ELWF3Z6H.js');
|
|
6903
|
-
const { startCodeRuntimeSession } = await import('./runtime-session-
|
|
6904
|
-
const { resolveGraphBackend } = await import('./graph-backend-
|
|
7283
|
+
const { startCodeRuntimeSession } = await import('./runtime-session-3MPWXNRL.js');
|
|
7284
|
+
const { resolveGraphBackend } = await import('./graph-backend-CPHLUKUC.js');
|
|
6905
7285
|
const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
|
|
6906
7286
|
const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
|
|
6907
|
-
const { vgdRequest: vgdRequest2 } = await import('./vgd-
|
|
7287
|
+
const { vgdRequest: vgdRequest2 } = await import('./vgd-Z23PXSP4.js');
|
|
6908
7288
|
const federation = loadFederation(root2);
|
|
6909
7289
|
const modelProfile = mergeModelExecutionProfile(
|
|
6910
7290
|
resolveModelExecutionProfile({
|
|
@@ -6960,7 +7340,8 @@ ${res.stderr}` : ""),
|
|
|
6960
7340
|
files: opts.file.length ? opts.file : void 0,
|
|
6961
7341
|
executionEnv,
|
|
6962
7342
|
graphBackend,
|
|
6963
|
-
modelProfile
|
|
7343
|
+
modelProfile,
|
|
7344
|
+
llmCompaction: true
|
|
6964
7345
|
});
|
|
6965
7346
|
if (global.json) json(agentResult);
|
|
6966
7347
|
if (agentResult.stopped === "error") process.exitCode = ExitCode.ERROR;
|
|
@@ -6974,7 +7355,7 @@ ${res.stderr}` : ""),
|
|
|
6974
7355
|
}
|
|
6975
7356
|
let consent = !!opts.yes;
|
|
6976
7357
|
if (opts.apply && !consent && process.stdin.isTTY && process.stdout.isTTY) {
|
|
6977
|
-
consent = await
|
|
7358
|
+
consent = await confirm2(`Apply the proposed change to ${root2}?`);
|
|
6978
7359
|
}
|
|
6979
7360
|
const onPhase = (phase, detail) => {
|
|
6980
7361
|
if (!global.json && !global.quiet) info(c.dim(` ${phase}: ${detail}`));
|
|
@@ -6996,7 +7377,7 @@ ${res.stderr}` : ""),
|
|
|
6996
7377
|
attribution: { client: "vg-code", provider: providerSlug, model: primary?.model }
|
|
6997
7378
|
});
|
|
6998
7379
|
if (opts.out) {
|
|
6999
|
-
|
|
7380
|
+
fs10.writeFileSync(opts.out, JSON.stringify(result, null, 2) + "\n");
|
|
7000
7381
|
}
|
|
7001
7382
|
if (global.json) {
|
|
7002
7383
|
json(result);
|
|
@@ -7047,7 +7428,7 @@ function resolveSecurityTierFlag(flag, fromConfig, auto) {
|
|
|
7047
7428
|
if (fromConfig) return fromConfig;
|
|
7048
7429
|
return auto ? "L1" : "L0";
|
|
7049
7430
|
}
|
|
7050
|
-
function
|
|
7431
|
+
function confirm2(question) {
|
|
7051
7432
|
return new Promise((resolve21) => {
|
|
7052
7433
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
7053
7434
|
rl.question(`${question} [y/N] `, (answer) => {
|
|
@@ -7209,7 +7590,7 @@ async function addCmd(root2, rest, opts, asJson) {
|
|
|
7209
7590
|
}
|
|
7210
7591
|
function readPackageVersion(root2) {
|
|
7211
7592
|
try {
|
|
7212
|
-
const pkg = JSON.parse(
|
|
7593
|
+
const pkg = JSON.parse(fs10__default.readFileSync(path39__default.join(root2, "package.json"), "utf8"));
|
|
7213
7594
|
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
7214
7595
|
} catch {
|
|
7215
7596
|
return void 0;
|
|
@@ -7217,7 +7598,7 @@ function readPackageVersion(root2) {
|
|
|
7217
7598
|
}
|
|
7218
7599
|
function readOptionalFile(p) {
|
|
7219
7600
|
try {
|
|
7220
|
-
const t =
|
|
7601
|
+
const t = fs10__default.readFileSync(p, "utf8");
|
|
7221
7602
|
return t.trim() ? t : void 0;
|
|
7222
7603
|
} catch {
|
|
7223
7604
|
return void 0;
|
|
@@ -7232,8 +7613,8 @@ async function publishCmd(root2, rest, opts, global, asJson) {
|
|
|
7232
7613
|
if (!parsed) throw new CliError("publishing a private library requires a DSN \u2014 run `vibgrate login` or set VIBGRATE_DSN", ExitCode.USAGE_ERROR);
|
|
7233
7614
|
const version = (opts.version || readPackageVersion(root2) || "").trim();
|
|
7234
7615
|
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 ?
|
|
7236
|
-
const dts = opts.dts ? readOptionalFile(
|
|
7616
|
+
const readme = readOptionalFile(opts.readme ? path39__default.resolve(opts.readme) : path39__default.join(root2, "README.md"));
|
|
7617
|
+
const dts = opts.dts ? readOptionalFile(path39__default.resolve(opts.dts)) : void 0;
|
|
7237
7618
|
if (!readme && !dts) throw usageError("nothing to publish \u2014 no README.md found and no --dts given");
|
|
7238
7619
|
const result = await publishPrivateLibrary(
|
|
7239
7620
|
{ name, version, readme, dts, language: opts.language },
|
|
@@ -7365,8 +7746,8 @@ function registerExport(program) {
|
|
|
7365
7746
|
out(content.trimEnd());
|
|
7366
7747
|
return;
|
|
7367
7748
|
}
|
|
7368
|
-
|
|
7369
|
-
|
|
7749
|
+
fs10.mkdirSync(path39.dirname(path39.resolve(file)), { recursive: true });
|
|
7750
|
+
fs10.writeFileSync(file, content);
|
|
7370
7751
|
info(`${c.green("\u2714")} wrote ${file} ${c.dim(`(${format})`)}`);
|
|
7371
7752
|
});
|
|
7372
7753
|
applyGlobalOptions(cmd);
|
|
@@ -7376,43 +7757,43 @@ function detectFormat(file) {
|
|
|
7376
7757
|
if (lower.endsWith(".cdx.json")) return "cyclonedx";
|
|
7377
7758
|
if (lower.endsWith(".spdx.json")) return "spdx";
|
|
7378
7759
|
if (file === "-") return "json";
|
|
7379
|
-
return formatForExt(
|
|
7760
|
+
return formatForExt(path39.extname(file));
|
|
7380
7761
|
}
|
|
7381
7762
|
function registerBundle(program) {
|
|
7382
7763
|
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
7764
|
const global = readGlobal(this);
|
|
7384
7765
|
const root2 = rootOf(global);
|
|
7385
|
-
const outDir =
|
|
7766
|
+
const outDir = path39.resolve(root2, opts.out ?? "vg-bundle");
|
|
7386
7767
|
let grammarFiles;
|
|
7387
7768
|
try {
|
|
7388
7769
|
grammarFiles = resolvedGrammarFiles();
|
|
7389
7770
|
} catch {
|
|
7390
7771
|
throw new CliError("no grammars found to bundle (run a build first)", ExitCode.ERROR);
|
|
7391
7772
|
}
|
|
7392
|
-
|
|
7773
|
+
fs10.mkdirSync(path39.join(outDir, "grammars"), { recursive: true });
|
|
7393
7774
|
let grammarCount = 0;
|
|
7394
7775
|
for (const { fileName, absPath } of grammarFiles) {
|
|
7395
|
-
|
|
7776
|
+
fs10.copyFileSync(absPath, path39.join(outDir, "grammars", fileName));
|
|
7396
7777
|
grammarCount++;
|
|
7397
7778
|
}
|
|
7398
7779
|
const included = [`grammars/ (${grammarCount} .wasm)`];
|
|
7399
7780
|
const graphSrc = resolveGraphPath(root2, global.graph);
|
|
7400
|
-
if (
|
|
7401
|
-
|
|
7781
|
+
if (fs10.existsSync(graphSrc)) {
|
|
7782
|
+
fs10.copyFileSync(graphSrc, path39.join(outDir, "graph.json"));
|
|
7402
7783
|
included.push("graph.json");
|
|
7403
7784
|
} else {
|
|
7404
7785
|
const graph = loadGraphFileWithSnapshot(graphSrc);
|
|
7405
7786
|
if (graph) {
|
|
7406
|
-
|
|
7787
|
+
fs10.writeFileSync(path39.join(outDir, "graph.json"), serializeGraph(graph));
|
|
7407
7788
|
included.push("graph.json");
|
|
7408
7789
|
}
|
|
7409
7790
|
}
|
|
7410
7791
|
const cat = catalogPath(root2);
|
|
7411
|
-
if (
|
|
7412
|
-
|
|
7792
|
+
if (fs10.existsSync(cat)) {
|
|
7793
|
+
fs10.copyFileSync(cat, path39.join(outDir, "vibgrate.lib.json"));
|
|
7413
7794
|
included.push("vibgrate.lib.json");
|
|
7414
|
-
if (
|
|
7415
|
-
|
|
7795
|
+
if (fs10.existsSync(libDir(root2))) {
|
|
7796
|
+
fs10.cpSync(libDir(root2), path39.join(outDir, "lib"), { recursive: true });
|
|
7416
7797
|
included.push("lib/");
|
|
7417
7798
|
}
|
|
7418
7799
|
}
|
|
@@ -7424,15 +7805,15 @@ function registerBundle(program) {
|
|
|
7424
7805
|
included,
|
|
7425
7806
|
usage: "Run `vg build --grammars <this dir>/grammars` to build fully offline."
|
|
7426
7807
|
};
|
|
7427
|
-
|
|
7808
|
+
fs10.writeFileSync(path39.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
|
|
7428
7809
|
`);
|
|
7429
7810
|
if (global.json) {
|
|
7430
|
-
json({ out:
|
|
7811
|
+
json({ out: path39.relative(root2, outDir), ...manifest });
|
|
7431
7812
|
return;
|
|
7432
7813
|
}
|
|
7433
|
-
info(`${c.cyan("vg bundle")} \xB7 wrote ${
|
|
7814
|
+
info(`${c.cyan("vg bundle")} \xB7 wrote ${path39.relative(root2, outDir)}/`);
|
|
7434
7815
|
for (const i of included) info(` ${c.green("\u2714")} ${i}`);
|
|
7435
|
-
info(c.dim(` offline: vg build --grammars "${
|
|
7816
|
+
info(c.dim(` offline: vg build --grammars "${path39.relative(root2, outDir)}/grammars"`));
|
|
7436
7817
|
});
|
|
7437
7818
|
applyGlobalOptions(cmd);
|
|
7438
7819
|
}
|
|
@@ -7450,7 +7831,7 @@ async function runDoctor(global) {
|
|
|
7450
7831
|
const root2 = rootOf(global);
|
|
7451
7832
|
const local = global.local === true;
|
|
7452
7833
|
const graphPath = resolveGraphPath(root2, global.graph);
|
|
7453
|
-
const configFile = CONFIG_BASENAMES.find((f) =>
|
|
7834
|
+
const configFile = CONFIG_BASENAMES.find((f) => fs10.existsSync(path39.join(root2, f))) ?? null;
|
|
7454
7835
|
const graph = loadGraph(root2, graphPath);
|
|
7455
7836
|
let staleFiles = null;
|
|
7456
7837
|
if (graph) {
|
|
@@ -7476,14 +7857,14 @@ async function runDoctor(global) {
|
|
|
7476
7857
|
root: root2,
|
|
7477
7858
|
configFile,
|
|
7478
7859
|
map: {
|
|
7479
|
-
path:
|
|
7860
|
+
path: path39.relative(root2, graphPath),
|
|
7480
7861
|
built: graph !== null,
|
|
7481
7862
|
generatedAt: graph?.generatedAt ?? null,
|
|
7482
7863
|
staleFiles
|
|
7483
7864
|
},
|
|
7484
7865
|
libCatalog: {
|
|
7485
|
-
path:
|
|
7486
|
-
present:
|
|
7866
|
+
path: path39.relative(root2, catalogPath(root2)),
|
|
7867
|
+
present: fs10.existsSync(catalogPath(root2)),
|
|
7487
7868
|
libraries: libCount
|
|
7488
7869
|
},
|
|
7489
7870
|
credentials: creds,
|
|
@@ -7540,7 +7921,7 @@ async function runDoctor(global) {
|
|
|
7540
7921
|
);
|
|
7541
7922
|
info(
|
|
7542
7923
|
` host pool ${li.hostPool.size} warm session(s)` + (li.hostPool.sessions[0] ? c.dim(
|
|
7543
|
-
` \xB7 last ${
|
|
7924
|
+
` \xB7 last ${path39.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
|
|
7544
7925
|
) : c.dim(" \xB7 none (load via vg code / vgd host-load)"))
|
|
7545
7926
|
);
|
|
7546
7927
|
if (li.dynamicOnToken || li.dynamicCustomSampler) {
|
|
@@ -7716,7 +8097,7 @@ function registerDaemon(program) {
|
|
|
7716
8097
|
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
8098
|
const global = readGlobal(this);
|
|
7718
8099
|
const socketPath = socketOf(this);
|
|
7719
|
-
const root2 =
|
|
8100
|
+
const root2 = path39.resolve(rootArg ?? rootOf(global));
|
|
7720
8101
|
if (!await vgdIsRunning({ socketPath })) {
|
|
7721
8102
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
7722
8103
|
}
|
|
@@ -7752,7 +8133,7 @@ function registerDaemon(program) {
|
|
|
7752
8133
|
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
8134
|
const global = readGlobal(this);
|
|
7754
8135
|
const socketPath = socketOf(this);
|
|
7755
|
-
const primary =
|
|
8136
|
+
const primary = path39.resolve(rootArg ?? rootOf(global));
|
|
7756
8137
|
if (!await vgdIsRunning({ socketPath })) {
|
|
7757
8138
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
7758
8139
|
}
|
|
@@ -7780,7 +8161,7 @@ function registerDaemon(program) {
|
|
|
7780
8161
|
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
8162
|
const global = readGlobal(this);
|
|
7782
8163
|
const socketPath = socketOf(this);
|
|
7783
|
-
const root2 =
|
|
8164
|
+
const root2 = path39.resolve(rootArg ?? rootOf(global));
|
|
7784
8165
|
if (!await vgdIsRunning({ socketPath })) {
|
|
7785
8166
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon ensure\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
7786
8167
|
}
|
|
@@ -7794,7 +8175,7 @@ function registerDaemon(program) {
|
|
|
7794
8175
|
throw new CliError(loaded.error, ExitCode.NOT_FOUND);
|
|
7795
8176
|
}
|
|
7796
8177
|
if (!loaded.ok) {
|
|
7797
|
-
const { loadGraph: loadGraph2 } = await import('./load-
|
|
8178
|
+
const { loadGraph: loadGraph2 } = await import('./load-MWG6WZTK.js');
|
|
7798
8179
|
const { detectGitRef } = await import('./git-ref-RSRAN4OH.js');
|
|
7799
8180
|
const { repositoryIdFromRoot } = await import('./paths-62AKTFSR.js');
|
|
7800
8181
|
const graph = loadGraph2(root2, global.graph);
|
|
@@ -7910,7 +8291,7 @@ function socketOf(cmd) {
|
|
|
7910
8291
|
let c2 = cmd;
|
|
7911
8292
|
while (c2) {
|
|
7912
8293
|
const opts = c2.opts();
|
|
7913
|
-
if (opts.socket) return
|
|
8294
|
+
if (opts.socket) return path39.resolve(opts.socket);
|
|
7914
8295
|
c2 = c2.parent;
|
|
7915
8296
|
}
|
|
7916
8297
|
return vgdSocketPath();
|
|
@@ -7982,7 +8363,7 @@ async function restartVgdIfRunning(socketPath = vgdSocketPath()) {
|
|
|
7982
8363
|
}
|
|
7983
8364
|
function readVgdPid() {
|
|
7984
8365
|
try {
|
|
7985
|
-
const raw =
|
|
8366
|
+
const raw = fs10.readFileSync(vgdPidPath(), "utf8").trim();
|
|
7986
8367
|
const pid = Number.parseInt(raw, 10);
|
|
7987
8368
|
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
7988
8369
|
} catch {
|
|
@@ -8067,7 +8448,7 @@ function registerPolicy(program) {
|
|
|
8067
8448
|
const global = readGlobal(this);
|
|
8068
8449
|
let raw;
|
|
8069
8450
|
try {
|
|
8070
|
-
raw =
|
|
8451
|
+
raw = fs10.readFileSync(file, "utf8");
|
|
8071
8452
|
} catch {
|
|
8072
8453
|
throw new CliError(`cannot read ${file}`, ExitCode.NOT_FOUND);
|
|
8073
8454
|
}
|
|
@@ -8187,11 +8568,11 @@ function registerLlmHost(program) {
|
|
|
8187
8568
|
applyGlobalOptions(cmd);
|
|
8188
8569
|
}
|
|
8189
8570
|
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 =
|
|
8191
|
-
const vibgrateDir2 =
|
|
8571
|
+
const rootDir = path39.resolve(targetPath);
|
|
8572
|
+
const vibgrateDir2 = path39.join(rootDir, ".vibgrate");
|
|
8192
8573
|
await ensureDir(vibgrateDir2);
|
|
8193
8574
|
console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold(".vibgrate/")} directory`);
|
|
8194
|
-
const configPath =
|
|
8575
|
+
const configPath = path39.join(rootDir, "vibgrate.config.ts");
|
|
8195
8576
|
if (await pathExists(configPath)) {
|
|
8196
8577
|
console.log(chalk7.dim(" vibgrate.config.ts already exists, skipping"));
|
|
8197
8578
|
} else {
|
|
@@ -8199,7 +8580,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
|
|
|
8199
8580
|
console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold("vibgrate.config.ts")}`);
|
|
8200
8581
|
}
|
|
8201
8582
|
if (opts.baseline) {
|
|
8202
|
-
const { runBaseline } = await import('./baseline-
|
|
8583
|
+
const { runBaseline } = await import('./baseline-6WTULHM5.js');
|
|
8203
8584
|
await runBaseline(rootDir);
|
|
8204
8585
|
}
|
|
8205
8586
|
console.log("");
|
|
@@ -8302,7 +8683,7 @@ function collectPackageImports(graph, ecosystem, pkg) {
|
|
|
8302
8683
|
};
|
|
8303
8684
|
}
|
|
8304
8685
|
async function firstReferenceLine(rootDir, relFile, identifier, readFile3) {
|
|
8305
|
-
const content = await readFile3(
|
|
8686
|
+
const content = await readFile3(path39.join(rootDir, relFile));
|
|
8306
8687
|
if (!content) return null;
|
|
8307
8688
|
const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8308
8689
|
const re = new RegExp(`\\b${escaped}\\b`);
|
|
@@ -8340,9 +8721,9 @@ function sitesFromImportFiles(files, limit = 10) {
|
|
|
8340
8721
|
}
|
|
8341
8722
|
async function defaultReadFile(absPath) {
|
|
8342
8723
|
try {
|
|
8343
|
-
const stat2 = await
|
|
8724
|
+
const stat2 = await fs24.stat(absPath);
|
|
8344
8725
|
if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
|
|
8345
|
-
return await
|
|
8726
|
+
return await fs24.readFile(absPath, "utf8");
|
|
8346
8727
|
} catch {
|
|
8347
8728
|
return null;
|
|
8348
8729
|
}
|
|
@@ -8538,7 +8919,7 @@ var AI_ASSISTANT_DETECTORS = [
|
|
|
8538
8919
|
async function detectAiAssistant(rootDir) {
|
|
8539
8920
|
for (const detector of AI_ASSISTANT_DETECTORS) {
|
|
8540
8921
|
for (const file of detector.files) {
|
|
8541
|
-
if (await pathExists$1(
|
|
8922
|
+
if (await pathExists$1(path39.join(rootDir, file))) {
|
|
8542
8923
|
return detector.name;
|
|
8543
8924
|
}
|
|
8544
8925
|
}
|
|
@@ -8732,7 +9113,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
|
|
|
8732
9113
|
collectExcludes,
|
|
8733
9114
|
[]
|
|
8734
9115
|
).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 =
|
|
9116
|
+
const rootDir = path39.resolve(targetPath);
|
|
8736
9117
|
if (!await pathExists$1(rootDir)) {
|
|
8737
9118
|
console.error(chalk7.red(`Path does not exist: ${rootDir}`));
|
|
8738
9119
|
process.exit(1);
|
|
@@ -8740,7 +9121,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
|
|
|
8740
9121
|
const hasDsn = !!resolveDsn(opts.dsn);
|
|
8741
9122
|
const willPush = !opts.offline && (opts.push || hasDsn);
|
|
8742
9123
|
const noLocalArtifacts = opts.localArtifacts === false;
|
|
8743
|
-
const isFirstRun = !await pathExists$1(
|
|
9124
|
+
const isFirstRun = !await pathExists$1(path39.join(rootDir, ".vibgrate", "scan_result.json"));
|
|
8744
9125
|
let pinnedRegion;
|
|
8745
9126
|
let planTier;
|
|
8746
9127
|
let upgradeUrl;
|
|
@@ -8999,7 +9380,7 @@ var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
|
8999
9380
|
function scanStaleness(rootDir, artifactPath) {
|
|
9000
9381
|
let ref;
|
|
9001
9382
|
try {
|
|
9002
|
-
ref =
|
|
9383
|
+
ref = fs10.statSync(artifactPath).mtimeMs;
|
|
9003
9384
|
} catch {
|
|
9004
9385
|
return { stale: false };
|
|
9005
9386
|
}
|
|
@@ -9011,7 +9392,7 @@ function scanStaleness(rootDir, artifactPath) {
|
|
|
9011
9392
|
if (depth > 8 || scanned > MAX_ENTRIES2) return;
|
|
9012
9393
|
let entries;
|
|
9013
9394
|
try {
|
|
9014
|
-
entries =
|
|
9395
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
9015
9396
|
} catch {
|
|
9016
9397
|
return;
|
|
9017
9398
|
}
|
|
@@ -9019,20 +9400,20 @@ function scanStaleness(rootDir, artifactPath) {
|
|
|
9019
9400
|
scanned++;
|
|
9020
9401
|
if (scanned > MAX_ENTRIES2) break;
|
|
9021
9402
|
if (e.isDirectory()) {
|
|
9022
|
-
if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(
|
|
9403
|
+
if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path39.join(dir, e.name), depth + 1);
|
|
9023
9404
|
continue;
|
|
9024
9405
|
}
|
|
9025
9406
|
if (!WATCHED_FILES.has(e.name) && !WATCHED_EXT.test(e.name)) continue;
|
|
9026
|
-
const abs =
|
|
9407
|
+
const abs = path39.join(dir, e.name);
|
|
9027
9408
|
let mtimeMs;
|
|
9028
9409
|
try {
|
|
9029
|
-
mtimeMs =
|
|
9410
|
+
mtimeMs = fs10.statSync(abs).mtimeMs;
|
|
9030
9411
|
} catch {
|
|
9031
9412
|
continue;
|
|
9032
9413
|
}
|
|
9033
9414
|
if (mtimeMs > newest) {
|
|
9034
9415
|
newest = mtimeMs;
|
|
9035
|
-
newestChanged =
|
|
9416
|
+
newestChanged = path39.relative(rootDir, abs) || e.name;
|
|
9036
9417
|
}
|
|
9037
9418
|
}
|
|
9038
9419
|
};
|
|
@@ -9163,7 +9544,7 @@ function analyzeTree(root2, packages) {
|
|
|
9163
9544
|
if (depth > MAX_DEPTH || filesSeen >= MAX_FILES) return;
|
|
9164
9545
|
let entries;
|
|
9165
9546
|
try {
|
|
9166
|
-
entries =
|
|
9547
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
9167
9548
|
} catch {
|
|
9168
9549
|
return;
|
|
9169
9550
|
}
|
|
@@ -9172,17 +9553,17 @@ function analyzeTree(root2, packages) {
|
|
|
9172
9553
|
if (filesSeen >= MAX_FILES) return;
|
|
9173
9554
|
if (entry.isDirectory()) {
|
|
9174
9555
|
if (SKIP_DIRS3.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
9175
|
-
walk2(
|
|
9556
|
+
walk2(path39.join(dir, entry.name), depth + 1);
|
|
9176
9557
|
continue;
|
|
9177
9558
|
}
|
|
9178
|
-
const fileEco = EXT_ECOSYSTEM[
|
|
9559
|
+
const fileEco = EXT_ECOSYSTEM[path39.extname(entry.name)];
|
|
9179
9560
|
if (!fileEco || fileEco === "unknown") continue;
|
|
9180
9561
|
filesSeen++;
|
|
9181
|
-
const full =
|
|
9562
|
+
const full = path39.join(dir, entry.name);
|
|
9182
9563
|
let content;
|
|
9183
9564
|
try {
|
|
9184
|
-
if (
|
|
9185
|
-
content =
|
|
9565
|
+
if (fs10.statSync(full).size > MAX_FILE_BYTES2) continue;
|
|
9566
|
+
content = fs10.readFileSync(full, "utf8");
|
|
9186
9567
|
} catch {
|
|
9187
9568
|
continue;
|
|
9188
9569
|
}
|
|
@@ -9493,7 +9874,7 @@ function applyPlan(rootDir, upgrades, opts = {}) {
|
|
|
9493
9874
|
}
|
|
9494
9875
|
const outcomes = effective.map((t) => {
|
|
9495
9876
|
const c2 = pmCommandFor(u.ecosystem, u.package, u.to, opts.packageManager, { workspaceRoot: t.isWorkspaceRoot });
|
|
9496
|
-
return { t, res: run(c2,
|
|
9877
|
+
return { t, res: run(c2, path39.join(rootDir, t.dir)) };
|
|
9497
9878
|
});
|
|
9498
9879
|
const failures = outcomes.filter((o) => !o.res.ok);
|
|
9499
9880
|
if (failures.length === 0) {
|
|
@@ -9522,8 +9903,8 @@ function applyPlan(rootDir, upgrades, opts = {}) {
|
|
|
9522
9903
|
return results;
|
|
9523
9904
|
}
|
|
9524
9905
|
var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
|
|
9525
|
-
var CACHE_DIR =
|
|
9526
|
-
var CACHE_FILE =
|
|
9906
|
+
var CACHE_DIR = path39.join(os.homedir(), ".vibgrate");
|
|
9907
|
+
var CACHE_FILE = path39.join(CACHE_DIR, "update-check.json");
|
|
9527
9908
|
async function fetchLatestVersion() {
|
|
9528
9909
|
try {
|
|
9529
9910
|
const controller = new AbortController();
|
|
@@ -9550,8 +9931,8 @@ async function fetchLatestVersion() {
|
|
|
9550
9931
|
}
|
|
9551
9932
|
async function writeCache(data) {
|
|
9552
9933
|
try {
|
|
9553
|
-
await
|
|
9554
|
-
await
|
|
9934
|
+
await fs24.mkdir(CACHE_DIR, { recursive: true });
|
|
9935
|
+
await fs24.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
9555
9936
|
} catch {
|
|
9556
9937
|
}
|
|
9557
9938
|
}
|
|
@@ -9562,7 +9943,7 @@ function detectGlobalInstall(execPath = process.argv[1] || "", cwd = process.cwd
|
|
|
9562
9943
|
if (!execPath) return null;
|
|
9563
9944
|
let resolved = execPath;
|
|
9564
9945
|
try {
|
|
9565
|
-
resolved =
|
|
9946
|
+
resolved = fs10.realpathSync(execPath);
|
|
9566
9947
|
} catch {
|
|
9567
9948
|
}
|
|
9568
9949
|
const p = resolved.replace(/\\/g, "/");
|
|
@@ -9592,14 +9973,14 @@ async function findGlobalInstall(pkg = PACKAGE_NAME, run = defaultRunner) {
|
|
|
9592
9973
|
pm: "yarn",
|
|
9593
9974
|
root: () => {
|
|
9594
9975
|
const dir = tryRun("yarn global dir");
|
|
9595
|
-
return dir ?
|
|
9976
|
+
return dir ? path39.join(dir, "node_modules") : null;
|
|
9596
9977
|
}
|
|
9597
9978
|
},
|
|
9598
|
-
{ pm: "bun", root: () =>
|
|
9979
|
+
{ pm: "bun", root: () => path39.join(os.homedir(), ".bun", "install", "global", "node_modules") }
|
|
9599
9980
|
];
|
|
9600
9981
|
for (const probe of probes) {
|
|
9601
9982
|
const root2 = probe.root();
|
|
9602
|
-
if (root2 && await pathExists(
|
|
9983
|
+
if (root2 && await pathExists(path39.join(root2, pkg))) return probe.pm;
|
|
9603
9984
|
}
|
|
9604
9985
|
return null;
|
|
9605
9986
|
}
|
|
@@ -9618,15 +9999,15 @@ function getGlobalUpdateCommand(pm, pkg, version) {
|
|
|
9618
9999
|
}
|
|
9619
10000
|
}
|
|
9620
10001
|
async function detectPackageManager(cwd) {
|
|
9621
|
-
if (await pathExists(
|
|
9622
|
-
if (await pathExists(
|
|
9623
|
-
if (await pathExists(
|
|
10002
|
+
if (await pathExists(path39.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
10003
|
+
if (await pathExists(path39.join(cwd, "bun.lockb"))) return "bun";
|
|
10004
|
+
if (await pathExists(path39.join(cwd, "yarn.lock"))) return "yarn";
|
|
9624
10005
|
return "npm";
|
|
9625
10006
|
}
|
|
9626
10007
|
async function detectWorkspaceRoot(cwd) {
|
|
9627
|
-
if (await pathExists(
|
|
10008
|
+
if (await pathExists(path39.join(cwd, "pnpm-workspace.yaml"))) return true;
|
|
9628
10009
|
try {
|
|
9629
|
-
const pkgPath =
|
|
10010
|
+
const pkgPath = path39.join(cwd, "package.json");
|
|
9630
10011
|
const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
|
|
9631
10012
|
const pkg = JSON.parse(raw);
|
|
9632
10013
|
return pkg.workspaces != null;
|
|
@@ -9651,7 +10032,7 @@ function getInstallCommand(pm, pkg, version, isDev, opts = {}) {
|
|
|
9651
10032
|
}
|
|
9652
10033
|
async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
|
|
9653
10034
|
try {
|
|
9654
|
-
const pkgPath =
|
|
10035
|
+
const pkgPath = path39.join(cwd, "package.json");
|
|
9655
10036
|
const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
|
|
9656
10037
|
const parsed = JSON.parse(raw);
|
|
9657
10038
|
if (parsed.devDependencies?.[pkg]) return "dev";
|
|
@@ -9820,13 +10201,13 @@ function collectCandidates(artifact) {
|
|
|
9820
10201
|
return out2;
|
|
9821
10202
|
}
|
|
9822
10203
|
var defaultFixScanner = async (rootDir) => {
|
|
9823
|
-
const scratch =
|
|
10204
|
+
const scratch = path39.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
|
|
9824
10205
|
const scanOpts = { vibgrateVersion: VERSION, format: "json", out: scratch, quiet: true, concurrency: 8 };
|
|
9825
10206
|
const advanced = await loadAdvancedScanHook();
|
|
9826
10207
|
return runCoreScan(rootDir, scanOpts, advanced);
|
|
9827
10208
|
};
|
|
9828
10209
|
async function loadArtifact(rootDir, inFile, scan = defaultFixScanner) {
|
|
9829
|
-
const artifactPath =
|
|
10210
|
+
const artifactPath = path39.isAbsolute(inFile) ? inFile : path39.join(rootDir, inFile);
|
|
9830
10211
|
if (await pathExists(artifactPath)) {
|
|
9831
10212
|
const staleness = scanStaleness(rootDir, artifactPath);
|
|
9832
10213
|
if (!staleness.stale) {
|
|
@@ -9853,7 +10234,7 @@ async function repositoryIdentity(rootDir, override) {
|
|
|
9853
10234
|
}
|
|
9854
10235
|
}
|
|
9855
10236
|
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 =
|
|
10237
|
+
const rootDir = path39.resolve(targetPath);
|
|
9857
10238
|
if (!await pathExists(rootDir)) {
|
|
9858
10239
|
console.error(chalk7.red(`Path does not exist: ${rootDir}`));
|
|
9859
10240
|
process.exit(1);
|
|
@@ -10014,7 +10395,7 @@ function emit(report, format) {
|
|
|
10014
10395
|
}
|
|
10015
10396
|
}
|
|
10016
10397
|
function relProjectDir(rootDir, projectPath) {
|
|
10017
|
-
const rel =
|
|
10398
|
+
const rel = path39.isAbsolute(projectPath) ? path39.relative(rootDir, projectPath) : projectPath;
|
|
10018
10399
|
return rel === "" ? "." : rel;
|
|
10019
10400
|
}
|
|
10020
10401
|
async function buildTargetResolver(rootDir, artifact) {
|
|
@@ -10849,7 +11230,7 @@ function formatMarkdown(artifact) {
|
|
|
10849
11230
|
|
|
10850
11231
|
// src/reporting/commands/report.ts
|
|
10851
11232
|
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 =
|
|
11233
|
+
const artifactPath = path39.resolve(opts.in);
|
|
10853
11234
|
if (!await pathExists(artifactPath)) {
|
|
10854
11235
|
console.error(chalk7.red(`Artifact not found: ${artifactPath}`));
|
|
10855
11236
|
console.error(chalk7.dim('Run "vibgrate scan" first to generate a scan artifact.'));
|
|
@@ -10898,8 +11279,8 @@ function openUrl(url) {
|
|
|
10898
11279
|
// src/reporting/commands/login.ts
|
|
10899
11280
|
var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
10900
11281
|
function isInside(dir, file) {
|
|
10901
|
-
const rel =
|
|
10902
|
-
return !!rel && !rel.startsWith("..") && !
|
|
11282
|
+
const rel = path39.relative(dir, file);
|
|
11283
|
+
return !!rel && !rel.startsWith("..") && !path39.isAbsolute(rel);
|
|
10903
11284
|
}
|
|
10904
11285
|
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
11286
|
"--local",
|
|
@@ -11154,7 +11535,7 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
|
|
|
11154
11535
|
try {
|
|
11155
11536
|
const statements = [];
|
|
11156
11537
|
if (opts.from) {
|
|
11157
|
-
const fromPath =
|
|
11538
|
+
const fromPath = path39.resolve(opts.from);
|
|
11158
11539
|
if (!await pathExists(fromPath)) {
|
|
11159
11540
|
process.stderr.write(chalk7.red(`Statements file not found: ${fromPath}
|
|
11160
11541
|
`));
|
|
@@ -11172,9 +11553,9 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
|
|
|
11172
11553
|
});
|
|
11173
11554
|
const json2 = JSON.stringify(doc, null, 2);
|
|
11174
11555
|
if (opts.out) {
|
|
11175
|
-
await writeTextFile(
|
|
11556
|
+
await writeTextFile(path39.resolve(opts.out), json2 + "\n");
|
|
11176
11557
|
process.stderr.write(
|
|
11177
|
-
chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${
|
|
11558
|
+
chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path39.resolve(opts.out)}
|
|
11178
11559
|
`
|
|
11179
11560
|
);
|
|
11180
11561
|
} else {
|
|
@@ -11357,7 +11738,7 @@ function formatDeltaText(base, current) {
|
|
|
11357
11738
|
return lines.join("\n");
|
|
11358
11739
|
}
|
|
11359
11740
|
async function readArtifactOrExit(filePath) {
|
|
11360
|
-
const absolutePath =
|
|
11741
|
+
const absolutePath = path39.resolve(filePath);
|
|
11361
11742
|
if (!await pathExists(absolutePath)) {
|
|
11362
11743
|
console.error(chalk7.red(`Artifact not found: ${absolutePath}`));
|
|
11363
11744
|
process.exit(1);
|
|
@@ -11374,7 +11755,7 @@ var exportCommand = new Command("export").description("Export scan artifact as S
|
|
|
11374
11755
|
const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
|
|
11375
11756
|
const body = JSON.stringify(sbom, null, 2);
|
|
11376
11757
|
if (opts.out) {
|
|
11377
|
-
await writeTextFile(
|
|
11758
|
+
await writeTextFile(path39.resolve(opts.out), body);
|
|
11378
11759
|
console.log(chalk7.green("\u2714") + ` SBOM written to ${opts.out}`);
|
|
11379
11760
|
} else {
|
|
11380
11761
|
console.log(body);
|
|
@@ -11385,7 +11766,7 @@ var deltaCommand = new Command("delta").description("Show SBOM delta between two
|
|
|
11385
11766
|
const current = await readArtifactOrExit(opts.to);
|
|
11386
11767
|
const report = formatDeltaText(base, current);
|
|
11387
11768
|
if (opts.out) {
|
|
11388
|
-
await writeTextFile(
|
|
11769
|
+
await writeTextFile(path39.resolve(opts.out), report);
|
|
11389
11770
|
console.log(chalk7.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
|
|
11390
11771
|
} else {
|
|
11391
11772
|
console.log(report);
|
|
@@ -11516,20 +11897,20 @@ function resolveRegime(id) {
|
|
|
11516
11897
|
return regime;
|
|
11517
11898
|
}
|
|
11518
11899
|
function evidenceDir(root2) {
|
|
11519
|
-
return
|
|
11900
|
+
return path39.join(root2, ".vibgrate", "evidence");
|
|
11520
11901
|
}
|
|
11521
11902
|
function orgPath(root2) {
|
|
11522
|
-
return
|
|
11903
|
+
return path39.join(evidenceDir(root2), "org.json");
|
|
11523
11904
|
}
|
|
11524
11905
|
function productsPath(root2) {
|
|
11525
|
-
return
|
|
11906
|
+
return path39.join(evidenceDir(root2), "products.json");
|
|
11526
11907
|
}
|
|
11527
11908
|
function releasesDir(root2) {
|
|
11528
|
-
return
|
|
11909
|
+
return path39.join(evidenceDir(root2), "releases");
|
|
11529
11910
|
}
|
|
11530
11911
|
function releasePath(root2, productId, version) {
|
|
11531
11912
|
const safe = `${productId}@${version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
|
|
11532
|
-
return
|
|
11913
|
+
return path39.join(releasesDir(root2), `${safe}.json`);
|
|
11533
11914
|
}
|
|
11534
11915
|
var DEFAULT_ORG = {
|
|
11535
11916
|
responsiblePersons: [],
|
|
@@ -11560,7 +11941,7 @@ async function freezeRelease(root2, release) {
|
|
|
11560
11941
|
const p = releasePath(root2, release.productId, release.version);
|
|
11561
11942
|
if (await pathExists(p)) {
|
|
11562
11943
|
throw new CliError(
|
|
11563
|
-
`release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${
|
|
11944
|
+
`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
11945
|
ExitCode.USAGE_ERROR
|
|
11565
11946
|
);
|
|
11566
11947
|
}
|
|
@@ -11574,7 +11955,7 @@ async function loadReleases(root2, productId) {
|
|
|
11574
11955
|
const files = (await readdir(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
11575
11956
|
const releases = [];
|
|
11576
11957
|
for (const f of files) {
|
|
11577
|
-
const rel = await readJsonFile(
|
|
11958
|
+
const rel = await readJsonFile(path39.join(dir, f));
|
|
11578
11959
|
if (!productId || rel.productId === productId) releases.push(rel);
|
|
11579
11960
|
}
|
|
11580
11961
|
return releases;
|
|
@@ -12269,19 +12650,19 @@ function verifyEvidenceEnvelope(env, opts = {}) {
|
|
|
12269
12650
|
var DEFAULT_KEY = "attest-key.pem";
|
|
12270
12651
|
function resolveSigningKey(root2, explicit) {
|
|
12271
12652
|
const chosen = process.env.VG_ATTEST_KEY;
|
|
12272
|
-
const keyPath = chosen ?
|
|
12653
|
+
const keyPath = chosen ? path39.resolve(chosen) : path39.join(root2, ".vibgrate", DEFAULT_KEY);
|
|
12273
12654
|
let minted = false;
|
|
12274
|
-
if (!
|
|
12655
|
+
if (!fs10.existsSync(keyPath)) {
|
|
12275
12656
|
if (chosen) throw new CliError(`signing key not found: ${chosen}`, ExitCode.USAGE_ERROR);
|
|
12276
12657
|
const kp = generateKeypair();
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12658
|
+
fs10.mkdirSync(path39.dirname(keyPath), { recursive: true });
|
|
12659
|
+
fs10.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
|
|
12660
|
+
fs10.writeFileSync(`${keyPath}.pub`, kp.publicPem);
|
|
12280
12661
|
minted = true;
|
|
12281
12662
|
}
|
|
12282
12663
|
let key2;
|
|
12283
12664
|
try {
|
|
12284
|
-
key2 = crypto3.createPrivateKey(
|
|
12665
|
+
key2 = crypto3.createPrivateKey(fs10.readFileSync(keyPath, "utf8"));
|
|
12285
12666
|
} catch {
|
|
12286
12667
|
throw new CliError(`could not read an Ed25519 private key from ${keyPath}`, ExitCode.USAGE_ERROR);
|
|
12287
12668
|
}
|
|
@@ -12292,16 +12673,16 @@ function resolveSigningKey(root2, explicit) {
|
|
|
12292
12673
|
}
|
|
12293
12674
|
function writeBundle(input) {
|
|
12294
12675
|
const dir = input.outDir;
|
|
12295
|
-
|
|
12296
|
-
const write = (rel, data) =>
|
|
12676
|
+
fs10.mkdirSync(path39.join(dir, "inputs", "releases"), { recursive: true });
|
|
12677
|
+
const write = (rel, data) => fs10.writeFileSync(path39.join(dir, rel), `${JSON.stringify(data, null, 2)}
|
|
12297
12678
|
`);
|
|
12298
12679
|
write("result.json", input.result);
|
|
12299
|
-
write(
|
|
12680
|
+
write(path39.join("inputs", "advisory.json"), input.advisory);
|
|
12300
12681
|
for (const rel of input.releases) {
|
|
12301
12682
|
const safe = `${rel.productId}@${rel.version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
|
|
12302
|
-
write(
|
|
12683
|
+
write(path39.join("inputs", "releases", `${safe}.json`), rel);
|
|
12303
12684
|
}
|
|
12304
|
-
write(
|
|
12685
|
+
write(path39.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
|
|
12305
12686
|
write("provenance.json", {
|
|
12306
12687
|
method: "deterministic",
|
|
12307
12688
|
modelDrafted: [],
|
|
@@ -12317,13 +12698,13 @@ function writeBundle(input) {
|
|
|
12317
12698
|
disclaimer: input.regime.disclaimer
|
|
12318
12699
|
});
|
|
12319
12700
|
if (input.envelope) {
|
|
12320
|
-
|
|
12701
|
+
fs10.writeFileSync(path39.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
|
|
12321
12702
|
`);
|
|
12322
12703
|
}
|
|
12323
12704
|
if (input.timestampToken) {
|
|
12324
|
-
|
|
12705
|
+
fs10.writeFileSync(path39.join(dir, "timestamp.tsr"), input.timestampToken);
|
|
12325
12706
|
}
|
|
12326
|
-
|
|
12707
|
+
fs10.writeFileSync(path39.join(dir, "VERIFY.md"), verifyDoc(input));
|
|
12327
12708
|
return dir;
|
|
12328
12709
|
}
|
|
12329
12710
|
function verifyDoc(input) {
|
|
@@ -12384,13 +12765,13 @@ function undeterminedFields(result, regime) {
|
|
|
12384
12765
|
return gaps.filter((g) => regime.submission.requires.some((r) => g.startsWith(r)) || g.startsWith("exposure") || g.startsWith("member"));
|
|
12385
12766
|
}
|
|
12386
12767
|
async function recordDrill(root2, record) {
|
|
12387
|
-
const dir =
|
|
12388
|
-
const p =
|
|
12768
|
+
const dir = path39.join(evidenceDir(root2), "drills");
|
|
12769
|
+
const p = path39.join(dir, `${record.drillId}.json`);
|
|
12389
12770
|
await writeJsonFile(p, record);
|
|
12390
12771
|
return p;
|
|
12391
12772
|
}
|
|
12392
12773
|
async function hasRecentDrill(root2, asOf) {
|
|
12393
|
-
const dir =
|
|
12774
|
+
const dir = path39.join(evidenceDir(root2), "drills");
|
|
12394
12775
|
if (!await pathExists(dir)) return void 0;
|
|
12395
12776
|
const { readdir } = await import('fs/promises');
|
|
12396
12777
|
const { readJsonFile: readJsonFile2 } = await import('./fs-4G5A65KS.js');
|
|
@@ -12398,7 +12779,7 @@ async function hasRecentDrill(root2, asOf) {
|
|
|
12398
12779
|
if (files.length === 0) return void 0;
|
|
12399
12780
|
const cutoff = new Date(new Date(asOf).getTime() - 90 * 24 * 3600 * 1e3).toISOString();
|
|
12400
12781
|
for (const f of files) {
|
|
12401
|
-
const rec = await readJsonFile2(
|
|
12782
|
+
const rec = await readJsonFile2(path39.join(dir, f));
|
|
12402
12783
|
if (rec.ranAt >= cutoff) return true;
|
|
12403
12784
|
}
|
|
12404
12785
|
return false;
|
|
@@ -12478,7 +12859,7 @@ function formatRegimeList() {
|
|
|
12478
12859
|
|
|
12479
12860
|
// src/reporting/commands/evidence/index.ts
|
|
12480
12861
|
function root(opts) {
|
|
12481
|
-
return
|
|
12862
|
+
return path39.resolve(opts.cwd ?? process.cwd());
|
|
12482
12863
|
}
|
|
12483
12864
|
function slug(name) {
|
|
12484
12865
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "product";
|
|
@@ -12566,7 +12947,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
|
|
|
12566
12947
|
const release = await buildRelease({
|
|
12567
12948
|
productId: product.id,
|
|
12568
12949
|
version,
|
|
12569
|
-
from:
|
|
12950
|
+
from: path39.resolve(rootDir, opts.from),
|
|
12570
12951
|
shipDate: opts.shipDate,
|
|
12571
12952
|
buildId: opts.buildId,
|
|
12572
12953
|
artefactDigest: opts.digest,
|
|
@@ -12574,7 +12955,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
|
|
|
12574
12955
|
frozenAt: nowIso()
|
|
12575
12956
|
});
|
|
12576
12957
|
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 ${
|
|
12958
|
+
console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path39.relative(rootDir, p)}`);
|
|
12578
12959
|
});
|
|
12579
12960
|
async function runExposure(rootDir, vuln, opts) {
|
|
12580
12961
|
const org = await loadOrg(rootDir);
|
|
@@ -12626,7 +13007,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
|
|
|
12626
13007
|
console.log("\n" + buildPack(result, regime, org, stage));
|
|
12627
13008
|
}
|
|
12628
13009
|
if (opts.bundle) {
|
|
12629
|
-
const dir =
|
|
13010
|
+
const dir = path39.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
|
|
12630
13011
|
let envelope;
|
|
12631
13012
|
if (opts.sign !== false) {
|
|
12632
13013
|
const { key: key2, minted } = resolveSigningKey(rootDir);
|
|
@@ -12634,7 +13015,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
|
|
|
12634
13015
|
envelope = signEvidenceStatement(buildEvidenceStatement(result, VERSION), key2);
|
|
12635
13016
|
}
|
|
12636
13017
|
writeBundle({ outDir: dir, result, advisory, releases, regime, envelope, timestampToken, cliVersion: VERSION });
|
|
12637
|
-
console.error(chalk7.green("\u2714") + ` evidence bundle written to ${
|
|
13018
|
+
console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path39.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
|
|
12638
13019
|
}
|
|
12639
13020
|
process.exitCode = exposureExit(result.overallStatus);
|
|
12640
13021
|
});
|
|
@@ -12666,7 +13047,7 @@ var packCmd = new Command("pack").description("Build the submission pack a human
|
|
|
12666
13047
|
const stage = opts.stage ?? regime.clocks[0]?.stage ?? "early-warning";
|
|
12667
13048
|
const md = buildPack(result, regime, org, stage);
|
|
12668
13049
|
if (opts.out) {
|
|
12669
|
-
|
|
13050
|
+
fs10.writeFileSync(path39.resolve(rootDir, opts.out), md);
|
|
12670
13051
|
console.error(chalk7.green("\u2714") + ` pack written to ${opts.out}`);
|
|
12671
13052
|
} else {
|
|
12672
13053
|
console.log(md);
|
|
@@ -12708,20 +13089,20 @@ var drillCmd = new Command("drill").description("Timed dry-run of the determinat
|
|
|
12708
13089
|
}
|
|
12709
13090
|
});
|
|
12710
13091
|
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 =
|
|
12712
|
-
const envPath =
|
|
12713
|
-
if (!
|
|
12714
|
-
const envelope = JSON.parse(
|
|
12715
|
-
const resultPath =
|
|
12716
|
-
const result =
|
|
12717
|
-
const publicKeyPem = opts.pub ?
|
|
13092
|
+
const abs = path39.resolve(bundlePath);
|
|
13093
|
+
const envPath = fs10.statSync(abs).isDirectory() ? path39.join(abs, "evidence.intoto.jsonl") : abs;
|
|
13094
|
+
if (!fs10.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
|
|
13095
|
+
const envelope = JSON.parse(fs10.readFileSync(envPath, "utf8").trim().split("\n")[0]);
|
|
13096
|
+
const resultPath = path39.join(path39.dirname(envPath), "result.json");
|
|
13097
|
+
const result = fs10.existsSync(resultPath) ? JSON.parse(fs10.readFileSync(resultPath, "utf8")) : void 0;
|
|
13098
|
+
const publicKeyPem = opts.pub ? fs10.readFileSync(path39.resolve(opts.pub), "utf8") : void 0;
|
|
12718
13099
|
const v = verifyEvidenceEnvelope(envelope, { publicKeyPem, result });
|
|
12719
13100
|
const color = v.status === "verified" ? chalk7.green : v.status === "failed" ? chalk7.red : chalk7.yellow;
|
|
12720
13101
|
console.log(" " + color(v.status.toUpperCase()) + ` ${v.reason}`);
|
|
12721
13102
|
if (v.evidenceId) console.log(" " + chalk7.dim(`evidence ${v.evidenceId} \xB7 regime ${v.regime} \xB7 advisory ${v.advisoryId} \xB7 ${v.overallStatus}`));
|
|
12722
|
-
const tsrPath =
|
|
12723
|
-
if (
|
|
12724
|
-
const t = verifyTimestamp(
|
|
13103
|
+
const tsrPath = path39.join(path39.dirname(envPath), "timestamp.tsr");
|
|
13104
|
+
if (fs10.existsSync(tsrPath) && result) {
|
|
13105
|
+
const t = verifyTimestamp(fs10.readFileSync(tsrPath), exposureSubjectDigest(result));
|
|
12725
13106
|
const tcolor = t.imprintMatches ? chalk7.green : chalk7.red;
|
|
12726
13107
|
console.log(" " + tcolor("TIMESTAMP") + ` ${t.reason}`);
|
|
12727
13108
|
}
|
|
@@ -12788,12 +13169,12 @@ var exportCmd = new Command("export").description("Air-gap bundle of all evidenc
|
|
|
12788
13169
|
const releases = [];
|
|
12789
13170
|
for (const list of releasesByProduct.values()) releases.push(...list);
|
|
12790
13171
|
const report = computeReadiness({ regime, org, products, releasesByProduct, recentDrill: await hasRecentDrill(rootDir, today()) });
|
|
12791
|
-
const dir =
|
|
12792
|
-
await writeJsonFile(
|
|
12793
|
-
await writeJsonFile(
|
|
12794
|
-
for (const r of releases) await writeJsonFile(
|
|
12795
|
-
await writeJsonFile(
|
|
12796
|
-
console.error(chalk7.green("\u2714") + ` exported evidence state to ${
|
|
13172
|
+
const dir = path39.resolve(rootDir, opts.out);
|
|
13173
|
+
await writeJsonFile(path39.join(dir, "org.json"), org);
|
|
13174
|
+
await writeJsonFile(path39.join(dir, "products.json"), products);
|
|
13175
|
+
for (const r of releases) await writeJsonFile(path39.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
|
|
13176
|
+
await writeJsonFile(path39.join(dir, "readiness.json"), report);
|
|
13177
|
+
console.error(chalk7.green("\u2714") + ` exported evidence state to ${path39.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
|
|
12797
13178
|
});
|
|
12798
13179
|
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
13180
|
const rootDir = root(opts);
|
|
@@ -12819,10 +13200,10 @@ var pushCmd = new Command("push").description("Push the product registry (and an
|
|
|
12819
13200
|
}));
|
|
12820
13201
|
let exposure;
|
|
12821
13202
|
if (opts.result) {
|
|
12822
|
-
const raw =
|
|
12823
|
-
const resultPath =
|
|
12824
|
-
if (!
|
|
12825
|
-
exposure = JSON.parse(
|
|
13203
|
+
const raw = path39.resolve(rootDir, opts.result);
|
|
13204
|
+
const resultPath = fs10.existsSync(raw) && fs10.statSync(raw).isDirectory() ? path39.join(raw, "result.json") : raw;
|
|
13205
|
+
if (!fs10.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
|
|
13206
|
+
exposure = JSON.parse(fs10.readFileSync(resultPath, "utf8"));
|
|
12826
13207
|
}
|
|
12827
13208
|
const payload = { schemaVersion: "evidence-push-1", regime: regime.id, generatedAt: nowIso(), signed: Boolean(opts.signed), products: productPayload, exposure };
|
|
12828
13209
|
const body = JSON.stringify(payload);
|
|
@@ -12880,6 +13261,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
12880
13261
|
"serve",
|
|
12881
13262
|
"lsp",
|
|
12882
13263
|
"doctor",
|
|
13264
|
+
"module",
|
|
12883
13265
|
"daemon",
|
|
12884
13266
|
"policy",
|
|
12885
13267
|
"llm-host",
|
|
@@ -12887,6 +13269,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
12887
13269
|
"uninstall",
|
|
12888
13270
|
"share",
|
|
12889
13271
|
"watch",
|
|
13272
|
+
"hook",
|
|
12890
13273
|
"help",
|
|
12891
13274
|
// Drift-reporting verbs (merged from the Vibgrate CLI).
|
|
12892
13275
|
"init",
|
|
@@ -12926,6 +13309,8 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
|
|
|
12926
13309
|
registerServe(program);
|
|
12927
13310
|
registerLsp(program);
|
|
12928
13311
|
registerInstall(program);
|
|
13312
|
+
registerModule(program);
|
|
13313
|
+
registerHook(program);
|
|
12929
13314
|
registerShare(program);
|
|
12930
13315
|
registerWatch(program);
|
|
12931
13316
|
registerTests(program);
|
|
@@ -13012,7 +13397,7 @@ function dispatch(argv, cwd) {
|
|
|
13012
13397
|
}
|
|
13013
13398
|
const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
|
|
13014
13399
|
if (looksLikeQuestion) return ["ask", ...args];
|
|
13015
|
-
if (
|
|
13400
|
+
if (fs10.existsSync(path39.resolve(cwd, first))) {
|
|
13016
13401
|
return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
|
|
13017
13402
|
}
|
|
13018
13403
|
const moved = MOVED_COMMANDS[first];
|
|
@@ -13057,9 +13442,9 @@ async function main(argv = process.argv) {
|
|
|
13057
13442
|
}
|
|
13058
13443
|
function readCwd(raw) {
|
|
13059
13444
|
const i = raw.findIndex((a) => a === "-C" || a === "--cwd");
|
|
13060
|
-
if (i >= 0 && raw[i + 1]) return
|
|
13445
|
+
if (i >= 0 && raw[i + 1]) return path39.resolve(raw[i + 1]);
|
|
13061
13446
|
const eq = raw.find((a) => a.startsWith("--cwd="));
|
|
13062
|
-
if (eq) return
|
|
13447
|
+
if (eq) return path39.resolve(eq.slice("--cwd=".length));
|
|
13063
13448
|
return process.cwd();
|
|
13064
13449
|
}
|
|
13065
13450
|
function handleError(err) {
|