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