@vibgrate/cli 2026.727.2 → 2026.727.4
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/DOCS.md +21 -1
- package/README.md +2 -1
- package/dist/baseline-ENCOSJYQ.js +8 -0
- package/dist/{baseline-TG4ATZGZ.js.map → baseline-ENCOSJYQ.js.map} +1 -1
- package/dist/chunk-3SDV6ADQ.js +78 -0
- package/dist/chunk-3SDV6ADQ.js.map +1 -0
- package/dist/{chunk-LKVMI67M.js → chunk-6AXHLQBV.js} +220 -23
- package/dist/chunk-6AXHLQBV.js.map +1 -0
- package/dist/{chunk-6ABXHZRN.js → chunk-6UK6QPTR.js} +69 -70
- package/dist/chunk-6UK6QPTR.js.map +1 -0
- package/dist/{chunk-TCDAZZNP.js → chunk-77LYGXBI.js} +5 -5
- package/dist/{chunk-TCDAZZNP.js.map → chunk-77LYGXBI.js.map} +1 -1
- package/dist/{chunk-2XQDMLKB.js → chunk-B3YUO3NW.js} +7 -3
- package/dist/chunk-B3YUO3NW.js.map +1 -0
- package/dist/{chunk-RNP3SMTV.js → chunk-FPEOIS7K.js} +61 -26
- package/dist/chunk-FPEOIS7K.js.map +1 -0
- package/dist/{chunk-OOIG3RUM.js → chunk-GYSOQH5C.js} +18 -79
- package/dist/chunk-GYSOQH5C.js.map +1 -0
- package/dist/{chunk-6AYDFFP5.js → chunk-HK3AWUXH.js} +3 -3
- package/dist/{chunk-6AYDFFP5.js.map → chunk-HK3AWUXH.js.map} +1 -1
- package/dist/{chunk-EX4PQT6W.js → chunk-HYRAILGM.js} +4 -4
- package/dist/{chunk-EX4PQT6W.js.map → chunk-HYRAILGM.js.map} +1 -1
- package/dist/{chunk-NDMDSPFX.js → chunk-KKRSQQ3A.js} +4 -3
- package/dist/chunk-KKRSQQ3A.js.map +1 -0
- package/dist/chunk-KUIBP3LU.js +101 -0
- package/dist/chunk-KUIBP3LU.js.map +1 -0
- package/dist/{chunk-OFUC6RYN.js → chunk-KXSKFQMI.js} +6 -99
- package/dist/chunk-KXSKFQMI.js.map +1 -0
- package/dist/{chunk-KCKYKDMS.js → chunk-LJP2EPKM.js} +20 -17
- package/dist/chunk-LJP2EPKM.js.map +1 -0
- package/dist/{chunk-J4RFRKZH.js → chunk-MAUJTPQW.js} +8 -8
- package/dist/{chunk-J4RFRKZH.js.map → chunk-MAUJTPQW.js.map} +1 -1
- package/dist/{chunk-3Q7QBWFW.js → chunk-ON25BX6T.js} +9 -3
- package/dist/chunk-ON25BX6T.js.map +1 -0
- package/dist/{chunk-3V24O47U.js → chunk-PVZBYZZR.js} +19 -9
- package/dist/chunk-PVZBYZZR.js.map +1 -0
- package/dist/{chunk-CY4WKXB2.js → chunk-R6ZRVVZT.js} +4 -4
- package/dist/{chunk-CY4WKXB2.js.map → chunk-R6ZRVVZT.js.map} +1 -1
- package/dist/{chunk-WGUL45AV.js → chunk-T3AYRS7J.js} +14 -7
- package/dist/chunk-T3AYRS7J.js.map +1 -0
- package/dist/{chunk-2MBL43EJ.js → chunk-XPJZTSY7.js} +3 -3
- package/dist/{chunk-2MBL43EJ.js.map → chunk-XPJZTSY7.js.map} +1 -1
- package/dist/chunk-YCJIIGLP.js +356 -0
- package/dist/chunk-YCJIIGLP.js.map +1 -0
- package/dist/{chunk-KNELIQJO.js → chunk-YKVH2PGF.js} +640 -208
- package/dist/chunk-YKVH2PGF.js.map +1 -0
- package/dist/{chunk-KSBHGWRV.js → chunk-ZBTY6VV4.js} +4 -4
- package/dist/{chunk-KSBHGWRV.js.map → chunk-ZBTY6VV4.js.map} +1 -1
- package/dist/{chunk-K3MZIVZW.js → chunk-ZKNB4YH4.js} +19 -5
- package/dist/chunk-ZKNB4YH4.js.map +1 -0
- package/dist/cli.js +476 -393
- package/dist/cli.js.map +1 -1
- package/dist/{graph-backend-73URGTFY.js → graph-backend-UTOL3SHE.js} +5 -5
- package/dist/{graph-backend-73URGTFY.js.map → graph-backend-UTOL3SHE.js.map} +1 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +12 -11
- package/dist/index.js.map +1 -1
- package/dist/{interactive-372NLI5C.js → interactive-SMHVURYK.js} +54 -24
- package/dist/interactive-SMHVURYK.js.map +1 -0
- package/dist/load-QPOWQD7C.js +8 -0
- package/dist/{load-I333TGNI.js.map → load-QPOWQD7C.js.map} +1 -1
- package/dist/model-manager-PN7HEDXD.js +9 -0
- package/dist/{model-orchestrator-TVONAUPS.js.map → model-manager-PN7HEDXD.js.map} +1 -1
- package/dist/{model-orchestrator-TVONAUPS.js → model-orchestrator-4VSYP4J4.js} +3 -3
- package/dist/model-orchestrator-4VSYP4J4.js.map +1 -0
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +1 -1
- package/dist/resolve-gguf-Y6FH3CNB.js +9 -0
- package/dist/{resolve-gguf-VPL4YQ6J.js.map → resolve-gguf-Y6FH3CNB.js.map} +1 -1
- package/dist/{runtime-session-JRKCQUHY.js → runtime-session-4AMZIAAG.js} +7 -7
- package/dist/{runtime-session-JRKCQUHY.js.map → runtime-session-4AMZIAAG.js.map} +1 -1
- package/dist/session-W3646AOV.js +12 -0
- package/dist/{session-ITPYQ5XI.js.map → session-W3646AOV.js.map} +1 -1
- package/dist/sql-extract-JELDZA6W.js +81 -0
- package/dist/sql-extract-JELDZA6W.js.map +1 -0
- package/dist/{stream-json-SLMDKLXP.js → stream-json-X7UQFB4T.js} +11 -10
- package/dist/stream-json-X7UQFB4T.js.map +1 -0
- package/dist/{types-7AHBUbFm.d.ts → types-DLH-Ritr.d.ts} +18 -1
- package/dist/{vgd-7JV5KCNJ.js → vgd-CVLKBS7K.js} +6 -6
- package/dist/vgd-CVLKBS7K.js.map +1 -0
- package/package.json +1 -1
- package/dist/baseline-TG4ATZGZ.js +0 -8
- package/dist/chunk-2XQDMLKB.js.map +0 -1
- package/dist/chunk-3Q7QBWFW.js.map +0 -1
- package/dist/chunk-3V24O47U.js.map +0 -1
- package/dist/chunk-6ABXHZRN.js.map +0 -1
- package/dist/chunk-K3MZIVZW.js.map +0 -1
- package/dist/chunk-KCKYKDMS.js.map +0 -1
- package/dist/chunk-KNELIQJO.js.map +0 -1
- package/dist/chunk-LKVMI67M.js.map +0 -1
- package/dist/chunk-NDMDSPFX.js.map +0 -1
- package/dist/chunk-OFUC6RYN.js.map +0 -1
- package/dist/chunk-OOIG3RUM.js.map +0 -1
- package/dist/chunk-RNP3SMTV.js.map +0 -1
- package/dist/chunk-WGUL45AV.js.map +0 -1
- package/dist/interactive-372NLI5C.js.map +0 -1
- package/dist/load-I333TGNI.js +0 -8
- package/dist/resolve-gguf-VPL4YQ6J.js +0 -8
- package/dist/session-ITPYQ5XI.js +0 -11
- package/dist/stream-json-SLMDKLXP.js.map +0 -1
- package/dist/vgd-7JV5KCNJ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,46 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
2
|
+
import { sha256Hex, generateKeypair, dssePae, DSSE_PAYLOAD_TYPE, keyId, registerBuild, readGlobal, applyGlobalOptions, ProgressBar, printLogo, fetchCatalog, resolveProviders, runBuild } from './chunk-FPEOIS7K.js';
|
|
3
|
+
export { runBuild } from './chunk-FPEOIS7K.js';
|
|
4
|
+
import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-MAUJTPQW.js';
|
|
5
|
+
import { loadAdvancedScanHook, baselineCommand } from './chunk-HYRAILGM.js';
|
|
6
|
+
import { runCodeSession } from './chunk-R6ZRVVZT.js';
|
|
7
|
+
import { summarizeDiffs, ScriptedProvider } from './chunk-KXSKFQMI.js';
|
|
8
|
+
import { disableColor, info, c, json, out } from './chunk-CT5BS56U.js';
|
|
9
|
+
import { VGD_PROTOCOL_VERSION, startVgdServer } from './chunk-77LYGXBI.js';
|
|
6
10
|
import './chunk-5I4VSBWQ.js';
|
|
7
11
|
import './chunk-IS7VTH2Q.js';
|
|
8
|
-
import { CONTEXT_POLICY_VERSION, computeFcsReport, renderFcsReportMarkdown, createTrajectoryCollector, runAgent } from './chunk-J4RFRKZH.js';
|
|
9
12
|
import { gatherSystemMemory } from './chunk-6UQMXIAG.js';
|
|
10
|
-
import { readOrchestratorState, writeOrchestratorState, parseMode, setDefaultMode, recommendMode, activePin, resolveMode, providerForBackend, QUALIFIED_PACKS, pinPack, unpinPack, buildOrchestratorStatus } from './chunk-
|
|
13
|
+
import { readOrchestratorState, writeOrchestratorState, parseMode, setDefaultMode, recommendMode, activePin, resolveMode, providerForBackend, QUALIFIED_PACKS, pinPack, unpinPack, buildOrchestratorStatus } from './chunk-PVZBYZZR.js';
|
|
11
14
|
import { fmt, estimateModelBytes } from './chunk-7N4Y3E47.js';
|
|
12
15
|
import './chunk-IZDH67DX.js';
|
|
13
|
-
import './chunk-
|
|
16
|
+
import './chunk-HK3AWUXH.js';
|
|
14
17
|
import { vgdIsRunning, vgdRequest, vgdSocketPath } from './chunk-PMYWZRRS.js';
|
|
15
18
|
import { defaultProcessEndpoint, startProcessHostServer, resolveInferenceIsolation } from './chunk-PXHNTC6D.js';
|
|
16
19
|
import { clearHostSessionPool, acquireHostSession, generateOnSession, listHostSessions, hostSessionPoolSize } from './chunk-K7REHDQS.js';
|
|
17
20
|
import { buildIdentifierTrieFromGraph } from './chunk-JIBOJTGS.js';
|
|
18
|
-
import './chunk-
|
|
19
|
-
import {
|
|
20
|
-
import { ensurePackage, ensureUnavailableMessage
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, loadConfig, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols } from './chunk-
|
|
25
|
-
import {
|
|
21
|
+
import './chunk-KKRSQQ3A.js';
|
|
22
|
+
import { buildModelInstallPlan } from './chunk-YCJIIGLP.js';
|
|
23
|
+
import { ensurePackage, ensureUnavailableMessage } from './chunk-KUIBP3LU.js';
|
|
24
|
+
import { serveStdio, exportGraph, GraphSource, createServer, formatForExt } from './chunk-LJP2EPKM.js';
|
|
25
|
+
import { resolveDsn, resolveIngestHost, dashHostForIngestHost, resolveCliInvocation, availableRegionIds, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, CliError, ExitCode, parseDsn as parseDsn$1, uploadScanArtifact, ingestHostForRegionId, dsnCommand, pushCommand, NPX_INVOCATION, refreshIfStale, driftCount, countTokens, shortestPath, pathDisconnect, testsToRun, detectRunner, ASSISTANTS, detectAssistants, usageError, detectServeLaunch, installAssistant, writeNavigationConfig, uninstallAssistant, coveringTests, FREE_PACK, readScanArtifact, buildGraph, writeSnapshot, probeFreshness, discover, assistantById, SMALL_REPO_FILES, publishPrivateLibrary, assessDocQuality, symbolsFromApi, fetchHostedDocsCached, selectForBudget, hostedBase, readStoredCredentials, projectCredentialsPath, homeCredentialsPath, SKIP_DIRS, SKIP_FILES } from './chunk-YKVH2PGF.js';
|
|
26
|
+
import { inventory, enrichOnline, ECOSYSTEMS, catalogPath, libDir, loadCatalog, driftFor, addLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface } from './chunk-6AXHLQBV.js';
|
|
27
|
+
import { writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, loadConfig, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols } from './chunk-T3AYRS7J.js';
|
|
28
|
+
import { recordCliCall, CLI_TOOL_ALIASES, savingsLedgerPath, clearSavings, readSavings, readUsage, readModelSavings, CAPSULE_RANKING_VERSION, SAVINGS_TOOLS, sanitizeClient } from './chunk-ZBTY6VV4.js';
|
|
29
|
+
import { ensureDir, pathExists, readJsonFile, writeTextFile, writeJsonFile } from './chunk-CRAMOEBE.js';
|
|
26
30
|
import { resolveOne } from './chunk-J7LKEB2R.js';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import { resolvedGrammarFiles, grammarSetVersion } from './chunk-
|
|
31
|
+
import { embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, countPending, indexFor, impactOf, modelCacheInfo, clearModelCache } from './chunk-6UK6QPTR.js';
|
|
32
|
+
import { discoverModels } from './chunk-3SDV6ADQ.js';
|
|
33
|
+
import { listCachedWeights, ensureWeightCached, catalogIntegrityReport, weightStoreDir } from './chunk-GYSOQH5C.js';
|
|
34
|
+
import { resolvedGrammarFiles, grammarSetVersion } from './chunk-ON25BX6T.js';
|
|
31
35
|
import './chunk-RXP66R2E.js';
|
|
32
|
-
import { resolveGraphPath, renderReport, loadGraph, writeArtifacts, vibgrateDir, SCHEMA_VERSION } from './chunk-
|
|
33
|
-
import { cacheDir, stableStringify } from './chunk-
|
|
36
|
+
import { resolveGraphPath, renderReport, loadGraph, writeArtifacts, vibgrateDir, SCHEMA_VERSION } from './chunk-B3YUO3NW.js';
|
|
37
|
+
import { cacheDir, stableStringify } from './chunk-ZKNB4YH4.js';
|
|
34
38
|
import './chunk-BWPBB45M.js';
|
|
35
39
|
import { canonicalize, hashString, hashBytes } from './chunk-JFGYT6BI.js';
|
|
36
40
|
import './chunk-BPF3YX2U.js';
|
|
37
41
|
import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-GI6W53LM.js';
|
|
38
|
-
import { ensureDir, pathExists, readJsonFile, writeTextFile, writeJsonFile } from './chunk-CRAMOEBE.js';
|
|
39
42
|
import './chunk-DGUM43GV.js';
|
|
40
43
|
import * as fs8 from 'fs';
|
|
41
44
|
import fs8__default, { realpathSync } from 'fs';
|
|
42
|
-
import * as
|
|
43
|
-
import
|
|
45
|
+
import * as path37 from 'path';
|
|
46
|
+
import path37__default from 'path';
|
|
44
47
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
45
48
|
import { Command, CommanderError, Option } from 'commander';
|
|
46
49
|
import * as os from 'os';
|
|
@@ -49,7 +52,7 @@ import { randomUUID } from 'crypto';
|
|
|
49
52
|
import { execSync, spawn, spawnSync, execFileSync } from 'child_process';
|
|
50
53
|
import * as readline from 'readline';
|
|
51
54
|
import chalk7 from 'chalk';
|
|
52
|
-
import * as
|
|
55
|
+
import * as fs21 from 'fs/promises';
|
|
53
56
|
import semver2 from 'semver';
|
|
54
57
|
|
|
55
58
|
function registerStatus(program) {
|
|
@@ -59,10 +62,10 @@ function registerStatus(program) {
|
|
|
59
62
|
applyGlobalOptions(cmd);
|
|
60
63
|
}
|
|
61
64
|
async function runStatus(global) {
|
|
62
|
-
const root2 =
|
|
65
|
+
const root2 = path37.resolve(global.cwd ?? ".");
|
|
63
66
|
const graphPath = resolveGraphPath(root2, global.graph);
|
|
64
67
|
const graph = loadGraph(root2, graphPath);
|
|
65
|
-
const hasCache = fs8.existsSync(
|
|
68
|
+
const hasCache = fs8.existsSync(path37.join(cacheDir(root2), "parse-cache.json"));
|
|
66
69
|
let stale = null;
|
|
67
70
|
let staleExact = false;
|
|
68
71
|
if (graph) {
|
|
@@ -82,8 +85,8 @@ async function runStatus(global) {
|
|
|
82
85
|
}
|
|
83
86
|
if (global.json) {
|
|
84
87
|
json({
|
|
85
|
-
root:
|
|
86
|
-
graphPath:
|
|
88
|
+
root: path37.relative(process.cwd(), root2) || ".",
|
|
89
|
+
graphPath: path37.relative(root2, graphPath),
|
|
87
90
|
built: graph !== null,
|
|
88
91
|
generatedAt: graph?.generatedAt ?? null,
|
|
89
92
|
counts: graph?.meta.counts ?? null,
|
|
@@ -98,11 +101,11 @@ async function runStatus(global) {
|
|
|
98
101
|
return;
|
|
99
102
|
}
|
|
100
103
|
if (!graph) {
|
|
101
|
-
info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(
|
|
104
|
+
info(`${c.cyan("vg")} \xB7 no map yet at ${c.dim(path37.relative(root2, graphPath))}`);
|
|
102
105
|
info(` run ${c.bold("vg")} to build one`);
|
|
103
106
|
return;
|
|
104
107
|
}
|
|
105
|
-
info(`${c.cyan("vg")} \xB7 ${
|
|
108
|
+
info(`${c.cyan("vg")} \xB7 ${path37.relative(root2, graphPath)}`);
|
|
106
109
|
info(` generated ${graph.generatedAt}`);
|
|
107
110
|
info(
|
|
108
111
|
` nodes ${c.bold(String(graph.meta.counts.nodes))} edges ${c.bold(
|
|
@@ -119,7 +122,7 @@ async function runStatus(global) {
|
|
|
119
122
|
if (vibgrateDir(root2)) ;
|
|
120
123
|
}
|
|
121
124
|
function rootOf(global) {
|
|
122
|
-
return
|
|
125
|
+
return path37.resolve(global.cwd ?? ".");
|
|
123
126
|
}
|
|
124
127
|
function requireGraph(global) {
|
|
125
128
|
const root2 = rootOf(global);
|
|
@@ -402,6 +405,19 @@ function registerPath(program) {
|
|
|
402
405
|
);
|
|
403
406
|
}
|
|
404
407
|
if (!result) {
|
|
408
|
+
const disc = pathDisconnect(graph, ra.node.id, rb.node.id);
|
|
409
|
+
if (global.json) {
|
|
410
|
+
json(disc);
|
|
411
|
+
throw new CliError(
|
|
412
|
+
`no path between ${ra.node.qualifiedName} and ${rb.node.qualifiedName}`,
|
|
413
|
+
ExitCode.NOT_FOUND
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
info(`${c.cyan("vg path")} \xB7 no path between ${c.bold(disc.from.name)} and ${c.bold(disc.to.name)}`);
|
|
417
|
+
printNeighborhood("from", disc.from);
|
|
418
|
+
printNeighborhood("to", disc.to);
|
|
419
|
+
info(c.dim(` ${disc.hint}`));
|
|
420
|
+
info(c.dim(` try: vg show ${disc.from.name} \xB7 vg impact ${disc.from.name} \xB7 vg show ${disc.to.name}`));
|
|
405
421
|
throw new CliError(
|
|
406
422
|
`no path between ${ra.node.qualifiedName} and ${rb.node.qualifiedName}`,
|
|
407
423
|
ExitCode.NOT_FOUND
|
|
@@ -418,6 +434,14 @@ function registerPath(program) {
|
|
|
418
434
|
});
|
|
419
435
|
applyGlobalOptions(cmd);
|
|
420
436
|
}
|
|
437
|
+
function printNeighborhood(label, n) {
|
|
438
|
+
const parts = [];
|
|
439
|
+
if (n.calls.length) parts.push(`calls ${n.calls.join(", ")}`);
|
|
440
|
+
if (n.calledBy.length) parts.push(`called by ${n.calledBy.join(", ")}`);
|
|
441
|
+
if (n.imports.length) parts.push(`imports ${n.imports.join(", ")}`);
|
|
442
|
+
if (n.importedBy.length) parts.push(`imported by ${n.importedBy.join(", ")}`);
|
|
443
|
+
info(` ${c.dim(label)} ${c.bold(n.name)}${parts.length ? c.dim(` \xB7 ${parts.join(" \xB7 ")}`) : c.dim(" \xB7 (no call/import neighbors)")}`);
|
|
444
|
+
}
|
|
421
445
|
|
|
422
446
|
// src/commands/tree.ts
|
|
423
447
|
function registerTree(program) {
|
|
@@ -531,12 +555,12 @@ function registerInsights(program) {
|
|
|
531
555
|
}
|
|
532
556
|
});
|
|
533
557
|
applyGlobalOptions(areas);
|
|
534
|
-
const oddities = program.command("oddities").description("surprising cross-area links (architectural smells)").option("-n, --limit <n>", "how many to show", "20").action(function(opts) {
|
|
558
|
+
const oddities = program.command("oddities").description("surprising cross-area links (architectural smells)").option("-n, --limit <n>", "how many to show", "20").option("--all", "include framework/runtime externals (default: filter them out)").action(function(opts) {
|
|
535
559
|
const global = readGlobal(this);
|
|
536
560
|
const { graph } = requireGraph(global);
|
|
537
561
|
const limit = Number(opts.limit) || 20;
|
|
538
562
|
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
539
|
-
const list = graph.edges.filter((e) => typeof e.surprise === "number" && e.surprise > 0).sort((a, b) => (b.surprise ?? 0) - (a.surprise ?? 0) || a.id.localeCompare(b.id)).slice(0, limit);
|
|
563
|
+
const list = graph.edges.filter((e) => typeof e.surprise === "number" && e.surprise > 0).filter((e) => opts.all || !isFrameworkOddity(byId.get(e.src), byId.get(e.dst), e.kind)).sort((a, b) => (b.surprise ?? 0) - (a.surprise ?? 0) || a.id.localeCompare(b.id)).slice(0, limit);
|
|
540
564
|
if (global.json) {
|
|
541
565
|
json(
|
|
542
566
|
list.map((e) => ({
|
|
@@ -549,7 +573,9 @@ function registerInsights(program) {
|
|
|
549
573
|
return;
|
|
550
574
|
}
|
|
551
575
|
if (!list.length) {
|
|
552
|
-
info(
|
|
576
|
+
info(
|
|
577
|
+
`${c.cyan("vg oddities")} \xB7 none found` + (opts.all ? " (no cross-area links, or only one area)" : " (no app-level surprises; try --all for framework links)")
|
|
578
|
+
);
|
|
553
579
|
return;
|
|
554
580
|
}
|
|
555
581
|
info(`${c.cyan("vg oddities")} \xB7 top ${list.length} surprising links`);
|
|
@@ -561,6 +587,70 @@ function registerInsights(program) {
|
|
|
561
587
|
});
|
|
562
588
|
applyGlobalOptions(oddities);
|
|
563
589
|
}
|
|
590
|
+
var FRAMEWORK_EXTERNALS = /* @__PURE__ */ new Set([
|
|
591
|
+
"react",
|
|
592
|
+
"react-dom",
|
|
593
|
+
"react-native",
|
|
594
|
+
"vue",
|
|
595
|
+
"vue-router",
|
|
596
|
+
"svelte",
|
|
597
|
+
"svelte/store",
|
|
598
|
+
"next",
|
|
599
|
+
"next/link",
|
|
600
|
+
"next/router",
|
|
601
|
+
"next/navigation",
|
|
602
|
+
"nuxt",
|
|
603
|
+
"angular",
|
|
604
|
+
"@angular/core",
|
|
605
|
+
"@angular/common",
|
|
606
|
+
"preact",
|
|
607
|
+
"solid-js",
|
|
608
|
+
"express",
|
|
609
|
+
"fastify",
|
|
610
|
+
"koa",
|
|
611
|
+
"hono",
|
|
612
|
+
"rxjs",
|
|
613
|
+
"lodash",
|
|
614
|
+
"lodash-es",
|
|
615
|
+
"underscore",
|
|
616
|
+
"jquery",
|
|
617
|
+
"axios",
|
|
618
|
+
"node:fs",
|
|
619
|
+
"node:path",
|
|
620
|
+
"node:url",
|
|
621
|
+
"node:http",
|
|
622
|
+
"node:https",
|
|
623
|
+
"fs",
|
|
624
|
+
"path",
|
|
625
|
+
"url",
|
|
626
|
+
"http",
|
|
627
|
+
"https",
|
|
628
|
+
"crypto",
|
|
629
|
+
"util",
|
|
630
|
+
"stream",
|
|
631
|
+
"events",
|
|
632
|
+
"assert",
|
|
633
|
+
"os",
|
|
634
|
+
"child_process"
|
|
635
|
+
]);
|
|
636
|
+
function isFrameworkOddity(from, to, kind) {
|
|
637
|
+
if (kind !== "import") return false;
|
|
638
|
+
for (const n of [from, to]) {
|
|
639
|
+
if (n?.kind === "external" && isFrameworkName(n.qualifiedName || n.name)) return true;
|
|
640
|
+
}
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
function isFrameworkName(name) {
|
|
644
|
+
if (!name) return false;
|
|
645
|
+
if (FRAMEWORK_EXTERNALS.has(name)) return true;
|
|
646
|
+
const base = name.startsWith("@") ? name.split("/").slice(0, 2).join("/") : name.split("/")[0];
|
|
647
|
+
if (FRAMEWORK_EXTERNALS.has(base)) return true;
|
|
648
|
+
if (base.startsWith("react-") || base.startsWith("@types/react")) return true;
|
|
649
|
+
if (base.startsWith("@vue/") || base.startsWith("@angular/") || base.startsWith("@sveltejs/")) {
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
564
654
|
function nodeSummary(n) {
|
|
565
655
|
return {
|
|
566
656
|
id: n.id,
|
|
@@ -743,8 +833,8 @@ function pad2(s, n) {
|
|
|
743
833
|
}
|
|
744
834
|
var SCHEMA_VERSION2 = "1";
|
|
745
835
|
var OFFSET_FILE = "stats-share.json";
|
|
746
|
-
var INSTALL_ID_DIR =
|
|
747
|
-
var INSTALL_ID_FILE =
|
|
836
|
+
var INSTALL_ID_DIR = path37.join(os.homedir(), ".vibgrate");
|
|
837
|
+
var INSTALL_ID_FILE = path37.join(INSTALL_ID_DIR, "install-id");
|
|
748
838
|
var SEND_TIMEOUT_MS = 4e3;
|
|
749
839
|
function telemetryOptOut(env = process.env) {
|
|
750
840
|
const dnt = (env.DO_NOT_TRACK ?? "").trim().toLowerCase();
|
|
@@ -796,10 +886,10 @@ function statsEndpoint() {
|
|
|
796
886
|
return `https://${resolveIngestHost()}/v1/ingest/cli-mcp-usage`;
|
|
797
887
|
}
|
|
798
888
|
function offsetPath(root2) {
|
|
799
|
-
return
|
|
889
|
+
return path37.join(cacheDir(root2), OFFSET_FILE);
|
|
800
890
|
}
|
|
801
891
|
function ledgerFilePath(root2) {
|
|
802
|
-
return
|
|
892
|
+
return path37.join(cacheDir(root2), "savings.jsonl");
|
|
803
893
|
}
|
|
804
894
|
function readOffset(root2) {
|
|
805
895
|
try {
|
|
@@ -970,7 +1060,7 @@ var PUBLISH_INTERVAL_MS = 2e3;
|
|
|
970
1060
|
var KEEPALIVE_MS = 1e4;
|
|
971
1061
|
var STALE_MS = 6e4;
|
|
972
1062
|
function liveStatsDir(root2) {
|
|
973
|
-
return
|
|
1063
|
+
return path37.join(cacheDir(root2), "serve-live");
|
|
974
1064
|
}
|
|
975
1065
|
function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid, signal) => process.kill(pid, signal), selfPid = process.pid) {
|
|
976
1066
|
let entries;
|
|
@@ -984,7 +1074,7 @@ function reapOtherVersionServers(dir, keepVersion, now = Date.now(), kill = (pid
|
|
|
984
1074
|
if (!/^serve-\d+\.json$/.test(name)) continue;
|
|
985
1075
|
let parsed;
|
|
986
1076
|
try {
|
|
987
|
-
parsed = JSON.parse(fs8.readFileSync(
|
|
1077
|
+
parsed = JSON.parse(fs8.readFileSync(path37.join(dir, name), "utf8"));
|
|
988
1078
|
} catch {
|
|
989
1079
|
continue;
|
|
990
1080
|
}
|
|
@@ -1006,7 +1096,7 @@ var LiveStatsBus = class {
|
|
|
1006
1096
|
this.dir = dir;
|
|
1007
1097
|
this.stats = stats;
|
|
1008
1098
|
this.pid = pid;
|
|
1009
|
-
this.file =
|
|
1099
|
+
this.file = path37.join(dir, `serve-${this.pid}.json`);
|
|
1010
1100
|
}
|
|
1011
1101
|
dir;
|
|
1012
1102
|
stats;
|
|
@@ -1059,7 +1149,7 @@ var LiveStatsBus = class {
|
|
|
1059
1149
|
const out2 = [];
|
|
1060
1150
|
for (const name of entries.sort()) {
|
|
1061
1151
|
if (!/^serve-\d+\.json$/.test(name)) continue;
|
|
1062
|
-
const file =
|
|
1152
|
+
const file = path37.join(this.dir, name);
|
|
1063
1153
|
let parsed;
|
|
1064
1154
|
try {
|
|
1065
1155
|
parsed = JSON.parse(fs8.readFileSync(file, "utf8"));
|
|
@@ -1487,8 +1577,8 @@ function registerServe(program) {
|
|
|
1487
1577
|
await serveHttp(graphPath, opts.host ?? "127.0.0.1", Number(opts.port) || 7437, serveOpts, freshness, () => display?.start());
|
|
1488
1578
|
} else {
|
|
1489
1579
|
info(c.dim(`vg \xB7 MCP server on stdio (read-only, ${freshness}). Connect your assistant to this process.`));
|
|
1490
|
-
await serveStdio(graphPath, serveOpts);
|
|
1491
1580
|
display?.start();
|
|
1581
|
+
await serveStdio(graphPath, serveOpts);
|
|
1492
1582
|
}
|
|
1493
1583
|
});
|
|
1494
1584
|
applyGlobalOptions(cmd);
|
|
@@ -1503,13 +1593,22 @@ async function ensureServableGraph(root2, graphPath, global, refresh, opts = {})
|
|
|
1503
1593
|
{ ...global, json: false }
|
|
1504
1594
|
);
|
|
1505
1595
|
} else {
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1596
|
+
const kick = refreshIfStale(root2, { inline: opts.inline, graphPath }).then((refreshed) => {
|
|
1597
|
+
if (refreshed.status === "refreshed") {
|
|
1598
|
+
const n = driftCount(refreshed.drift);
|
|
1599
|
+
info(
|
|
1600
|
+
c.dim(
|
|
1601
|
+
`vg \xB7 map refreshed in background \u2014 ${n} file(s) drifted (${(refreshed.ms / 1e3).toFixed(2)}s)`
|
|
1602
|
+
)
|
|
1603
|
+
);
|
|
1604
|
+
} else if (refreshed.status === "error") {
|
|
1605
|
+
info(c.yellow(`vg \xB7 map refresh failed (${refreshed.message}) \u2014 serving the last built map`));
|
|
1606
|
+
}
|
|
1607
|
+
}).catch((err) => {
|
|
1608
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1609
|
+
info(c.yellow(`vg \xB7 map refresh failed (${msg}) \u2014 serving the last built map`));
|
|
1610
|
+
});
|
|
1611
|
+
if (opts.awaitStaleRefresh) await kick;
|
|
1513
1612
|
}
|
|
1514
1613
|
}
|
|
1515
1614
|
if (!fs8.existsSync(graphPath)) {
|
|
@@ -1574,7 +1673,7 @@ async function serveHttp(graphPath, host, port, opts, freshness, onReady) {
|
|
|
1574
1673
|
info(c.red(`vg serve: request error: ${err.message}`));
|
|
1575
1674
|
}
|
|
1576
1675
|
});
|
|
1577
|
-
await new Promise((
|
|
1676
|
+
await new Promise((resolve20) => httpServer.listen(port, host, resolve20));
|
|
1578
1677
|
info(c.dim(`vg \xB7 MCP server on http://${host}:${port}/mcp (read-only, local, ${freshness})`));
|
|
1579
1678
|
onReady?.();
|
|
1580
1679
|
await new Promise(() => {
|
|
@@ -1788,7 +1887,7 @@ function endOfLine(text, line) {
|
|
|
1788
1887
|
}
|
|
1789
1888
|
var CACHE_VERSION = "vg-lsp-scan-cache/2";
|
|
1790
1889
|
function cachePath(root2) {
|
|
1791
|
-
return
|
|
1890
|
+
return path37.join(cacheDir(root2), "lsp-scan.json");
|
|
1792
1891
|
}
|
|
1793
1892
|
function manifestHash(root2) {
|
|
1794
1893
|
const files = [];
|
|
@@ -1800,7 +1899,7 @@ function manifestHash(root2) {
|
|
|
1800
1899
|
return;
|
|
1801
1900
|
}
|
|
1802
1901
|
for (const entry of entries) {
|
|
1803
|
-
const abs =
|
|
1902
|
+
const abs = path37.join(dir, entry.name);
|
|
1804
1903
|
if (entry.isDirectory()) {
|
|
1805
1904
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
1806
1905
|
walk2(abs);
|
|
@@ -1810,7 +1909,7 @@ function manifestHash(root2) {
|
|
|
1810
1909
|
const base = entry.name.toLowerCase();
|
|
1811
1910
|
if (!isManifest(abs) && !SKIP_FILES.has(base)) continue;
|
|
1812
1911
|
try {
|
|
1813
|
-
const rel =
|
|
1912
|
+
const rel = path37.relative(root2, abs).split(path37.sep).join("/");
|
|
1814
1913
|
files.push({ rel, hash: hashBytes(fs8.readFileSync(abs)) });
|
|
1815
1914
|
} catch {
|
|
1816
1915
|
}
|
|
@@ -2456,12 +2555,12 @@ function uriToPath(uri) {
|
|
|
2456
2555
|
}
|
|
2457
2556
|
}
|
|
2458
2557
|
function projectForFile(root2, a, filePath) {
|
|
2459
|
-
const dir =
|
|
2558
|
+
const dir = path37.dirname(path37.resolve(filePath));
|
|
2460
2559
|
let best;
|
|
2461
2560
|
let bestLen = -1;
|
|
2462
2561
|
for (const proj of a.projects ?? []) {
|
|
2463
|
-
const projDir =
|
|
2464
|
-
if ((dir === projDir || dir.startsWith(projDir +
|
|
2562
|
+
const projDir = path37.resolve(root2, proj.path);
|
|
2563
|
+
if ((dir === projDir || dir.startsWith(projDir + path37.sep)) && projDir.length > bestLen) {
|
|
2465
2564
|
best = proj;
|
|
2466
2565
|
bestLen = projDir.length;
|
|
2467
2566
|
}
|
|
@@ -2469,7 +2568,7 @@ function projectForFile(root2, a, filePath) {
|
|
|
2469
2568
|
return best;
|
|
2470
2569
|
}
|
|
2471
2570
|
function sameProject(location, projectPath) {
|
|
2472
|
-
return
|
|
2571
|
+
return path37.normalize(location) === path37.normalize(projectPath);
|
|
2473
2572
|
}
|
|
2474
2573
|
function hasReleaseDates(a) {
|
|
2475
2574
|
for (const proj of a.projects ?? []) {
|
|
@@ -2795,7 +2894,7 @@ function registerShare(program) {
|
|
|
2795
2894
|
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) {
|
|
2796
2895
|
const global = readGlobal(this);
|
|
2797
2896
|
const root2 = rootOf(global);
|
|
2798
|
-
const gitDir =
|
|
2897
|
+
const gitDir = path37.join(root2, ".git");
|
|
2799
2898
|
if (!fs8.existsSync(gitDir)) {
|
|
2800
2899
|
throw new CliError("not a git repository \u2014 run `vg share` inside a git repo", ExitCode.USAGE_ERROR);
|
|
2801
2900
|
}
|
|
@@ -2817,15 +2916,15 @@ function registerShare(program) {
|
|
|
2817
2916
|
applyGlobalOptions(cmd);
|
|
2818
2917
|
}
|
|
2819
2918
|
function writeVibgrateGitignore(root2, reports) {
|
|
2820
|
-
const dir =
|
|
2919
|
+
const dir = path37.join(root2, ".vibgrate");
|
|
2821
2920
|
fs8.mkdirSync(dir, { recursive: true });
|
|
2822
2921
|
const lines = ["# Managed by `vg share` \u2014 keep graph.json committed, ignore the rest", "cache/", "facts.jsonl"];
|
|
2823
2922
|
if (!reports) lines.push("graph.html", "GRAPH_REPORT.md");
|
|
2824
|
-
fs8.writeFileSync(
|
|
2923
|
+
fs8.writeFileSync(path37.join(dir, ".gitignore"), `${lines.join("\n")}
|
|
2825
2924
|
`);
|
|
2826
2925
|
}
|
|
2827
2926
|
function writeGitAttributes(root2) {
|
|
2828
|
-
const file =
|
|
2927
|
+
const file = path37.join(root2, ".gitattributes");
|
|
2829
2928
|
const line = ".vibgrate/graph.json merge=vg";
|
|
2830
2929
|
let content = fs8.existsSync(file) ? fs8.readFileSync(file, "utf8") : "";
|
|
2831
2930
|
if (!content.split("\n").some((l) => l.trim() === line)) {
|
|
@@ -2843,7 +2942,7 @@ function configureMergeDriver(root2) {
|
|
|
2843
2942
|
function installPreCommitHook(root2) {
|
|
2844
2943
|
const hooksDir = hookDir(root2);
|
|
2845
2944
|
fs8.mkdirSync(hooksDir, { recursive: true });
|
|
2846
|
-
const file =
|
|
2945
|
+
const file = path37.join(hooksDir, "pre-commit");
|
|
2847
2946
|
const block = [
|
|
2848
2947
|
HOOK_BEGIN,
|
|
2849
2948
|
"if command -v vg >/dev/null 2>&1; then",
|
|
@@ -2865,14 +2964,14 @@ ${content}`;
|
|
|
2865
2964
|
fs8.chmodSync(file, 493);
|
|
2866
2965
|
}
|
|
2867
2966
|
function undo(root2) {
|
|
2868
|
-
const hookFile =
|
|
2967
|
+
const hookFile = path37.join(hookDir(root2), "pre-commit");
|
|
2869
2968
|
if (fs8.existsSync(hookFile)) {
|
|
2870
2969
|
const re = new RegExp(`\\n*${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}\\n*`);
|
|
2871
2970
|
const next2 = fs8.readFileSync(hookFile, "utf8").replace(re, "\n");
|
|
2872
2971
|
if (next2.trim() === "#!/bin/sh") fs8.rmSync(hookFile);
|
|
2873
2972
|
else fs8.writeFileSync(hookFile, next2);
|
|
2874
2973
|
}
|
|
2875
|
-
const attr =
|
|
2974
|
+
const attr = path37.join(root2, ".gitattributes");
|
|
2876
2975
|
if (fs8.existsSync(attr)) {
|
|
2877
2976
|
const next2 = fs8.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
|
|
2878
2977
|
fs8.writeFileSync(attr, next2);
|
|
@@ -2885,10 +2984,10 @@ function undo(root2) {
|
|
|
2885
2984
|
function hookDir(root2) {
|
|
2886
2985
|
try {
|
|
2887
2986
|
const configured = git(root2, ["config", "--get", "core.hooksPath"]).trim();
|
|
2888
|
-
if (configured) return
|
|
2987
|
+
if (configured) return path37.resolve(root2, configured);
|
|
2889
2988
|
} catch {
|
|
2890
2989
|
}
|
|
2891
|
-
return
|
|
2990
|
+
return path37.join(root2, ".git", "hooks");
|
|
2892
2991
|
}
|
|
2893
2992
|
function git(root2, args) {
|
|
2894
2993
|
return execFileSync("git", args, { cwd: root2, encoding: "utf8" });
|
|
@@ -2896,6 +2995,111 @@ function git(root2, args) {
|
|
|
2896
2995
|
function escapeRe(s) {
|
|
2897
2996
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2898
2997
|
}
|
|
2998
|
+
var DEFAULT_DEBOUNCE_MS = 400;
|
|
2999
|
+
var SKIP_NAME = /* @__PURE__ */ new Set([
|
|
3000
|
+
".git",
|
|
3001
|
+
"node_modules",
|
|
3002
|
+
".vibgrate",
|
|
3003
|
+
"dist",
|
|
3004
|
+
"build",
|
|
3005
|
+
"out",
|
|
3006
|
+
"coverage",
|
|
3007
|
+
".next",
|
|
3008
|
+
"target",
|
|
3009
|
+
"__pycache__",
|
|
3010
|
+
".venv",
|
|
3011
|
+
"venv"
|
|
3012
|
+
]);
|
|
3013
|
+
function registerWatch(program) {
|
|
3014
|
+
const cmd = program.command("watch").description("rebuild the code map when files change (debounced)").argument("[paths...]", "folders to watch (default: current folder)").option("--debounce <ms>", "settle time after a change before rebuild", String(DEFAULT_DEBOUNCE_MS)).option("--no-html", "do not write graph.html on each rebuild").option("--no-report", "do not write GRAPH_REPORT.md on each rebuild").option("--fast", "skip precise tsc resolve on rebuilds (heuristic only)").action(async function(paths, opts) {
|
|
3015
|
+
const global = readGlobal(this);
|
|
3016
|
+
const root2 = rootOf(global);
|
|
3017
|
+
const debounceMs = Math.max(50, Number(opts.debounce) || DEFAULT_DEBOUNCE_MS);
|
|
3018
|
+
const watchRoots = (paths.length ? paths : ["."]).map((p) => path37.resolve(root2, p));
|
|
3019
|
+
for (const w of watchRoots) {
|
|
3020
|
+
if (!fs8.existsSync(w)) {
|
|
3021
|
+
throw new CliError(`watch path not found: ${w}`, ExitCode.USAGE_ERROR);
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
let building = false;
|
|
3025
|
+
let pending = false;
|
|
3026
|
+
let timer = null;
|
|
3027
|
+
const rebuild = async (reason) => {
|
|
3028
|
+
if (building) {
|
|
3029
|
+
pending = true;
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
building = true;
|
|
3033
|
+
try {
|
|
3034
|
+
info(c.dim(`vg watch \xB7 rebuild (${reason})`));
|
|
3035
|
+
const result = await buildGraph({
|
|
3036
|
+
root: root2,
|
|
3037
|
+
paths: paths.length ? paths : void 0,
|
|
3038
|
+
fast: opts.fast === true,
|
|
3039
|
+
noGround: false
|
|
3040
|
+
});
|
|
3041
|
+
writeArtifacts(result.graph, {
|
|
3042
|
+
root: root2,
|
|
3043
|
+
html: opts.html !== false,
|
|
3044
|
+
report: opts.report !== false,
|
|
3045
|
+
graphPath: global.graph
|
|
3046
|
+
});
|
|
3047
|
+
writeSnapshot(root2, result.graph.provenance.corpusHash, result.fileStats);
|
|
3048
|
+
const { counts } = result.graph.meta;
|
|
3049
|
+
info(
|
|
3050
|
+
`${c.cyan("vg watch")} \xB7 ${counts.nodes} nodes \xB7 ${counts.edges} edges \xB7 ${(result.timing.totalMs / 1e3).toFixed(2)}s` + (result.statHits ? c.dim(` \xB7 ${result.statHits} mtime hits`) : "")
|
|
3051
|
+
);
|
|
3052
|
+
} catch (err) {
|
|
3053
|
+
info(c.yellow(`vg watch \xB7 rebuild failed: ${err.message}`));
|
|
3054
|
+
} finally {
|
|
3055
|
+
building = false;
|
|
3056
|
+
if (pending) {
|
|
3057
|
+
pending = false;
|
|
3058
|
+
void rebuild("queued changes");
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
};
|
|
3062
|
+
const schedule = (label) => {
|
|
3063
|
+
if (timer) clearTimeout(timer);
|
|
3064
|
+
timer = setTimeout(() => {
|
|
3065
|
+
timer = null;
|
|
3066
|
+
void rebuild(label);
|
|
3067
|
+
}, debounceMs);
|
|
3068
|
+
};
|
|
3069
|
+
await rebuild("initial");
|
|
3070
|
+
const watchers = [];
|
|
3071
|
+
for (const w of watchRoots) {
|
|
3072
|
+
try {
|
|
3073
|
+
const watcher = fs8.watch(w, { recursive: true }, (_event, filename) => {
|
|
3074
|
+
if (!filename) {
|
|
3075
|
+
schedule("change");
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
const parts = filename.split(path37.sep);
|
|
3079
|
+
if (parts.some((p) => SKIP_NAME.has(p))) return;
|
|
3080
|
+
if (filename.includes(`${path37.sep}.vibgrate${path37.sep}`) || filename.startsWith(".vibgrate")) {
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
schedule(filename);
|
|
3084
|
+
});
|
|
3085
|
+
watchers.push(watcher);
|
|
3086
|
+
} catch (err) {
|
|
3087
|
+
throw new CliError(`cannot watch ${w}: ${err.message}`, ExitCode.ERROR);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
info(c.dim(`vg watch \xB7 watching ${watchRoots.map((p) => path37.relative(root2, p) || ".").join(", ")} (debounce ${debounceMs}ms) \xB7 Ctrl+C to stop`));
|
|
3091
|
+
await new Promise((resolve20) => {
|
|
3092
|
+
const stop = () => {
|
|
3093
|
+
for (const w of watchers) w.close();
|
|
3094
|
+
if (timer) clearTimeout(timer);
|
|
3095
|
+
resolve20();
|
|
3096
|
+
};
|
|
3097
|
+
process.once("SIGINT", stop);
|
|
3098
|
+
process.once("SIGTERM", stop);
|
|
3099
|
+
});
|
|
3100
|
+
});
|
|
3101
|
+
applyGlobalOptions(cmd);
|
|
3102
|
+
}
|
|
2899
3103
|
function registerTests(program) {
|
|
2900
3104
|
const cmd = program.command("tests").description("which tests cover a node (call/coverage linkage)").argument("<name>", "node to inspect").option("--missing", "show untested nodes nearby instead").option("--run", "print the command to run exactly these tests").option("--exec", "run that command").option("--pick <n>", "pick the nth candidate when ambiguous").action(function(name, opts) {
|
|
2901
3105
|
const global = readGlobal(this);
|
|
@@ -2951,8 +3155,17 @@ function registerFacts(program) {
|
|
|
2951
3155
|
const { node: node2, candidates } = resolveOne(graph, name, opts.pick ? Number(opts.pick) : void 0);
|
|
2952
3156
|
if (!node2) throw ambiguityError(`"${name}" ${candidates.length ? "is ambiguous" : "not found"}`, candidates);
|
|
2953
3157
|
if (!graph.facts) {
|
|
2954
|
-
if (global.json)
|
|
2955
|
-
|
|
3158
|
+
if (global.json) {
|
|
3159
|
+
json({
|
|
3160
|
+
node: node2.qualifiedName,
|
|
3161
|
+
facts: [],
|
|
3162
|
+
note: "map has no facts \u2014 rebuild with a current vg (facts ship on every build)"
|
|
3163
|
+
});
|
|
3164
|
+
} else {
|
|
3165
|
+
info(
|
|
3166
|
+
`${c.cyan("vg facts")} \xB7 none in this map \u2014 rebuild with ${c.bold("vg")} (facts ship on every build)`
|
|
3167
|
+
);
|
|
3168
|
+
}
|
|
2956
3169
|
return;
|
|
2957
3170
|
}
|
|
2958
3171
|
const facts = graph.facts.filter((f) => f.subjectIds.includes(node2.id));
|
|
@@ -3207,7 +3420,7 @@ function normalizeStandards(raw) {
|
|
|
3207
3420
|
}
|
|
3208
3421
|
function loadStandards(root2) {
|
|
3209
3422
|
for (const rel of STANDARDS_FILES) {
|
|
3210
|
-
const p =
|
|
3423
|
+
const p = path37__default.join(root2, rel);
|
|
3211
3424
|
let text;
|
|
3212
3425
|
try {
|
|
3213
3426
|
text = fs8__default.readFileSync(p, "utf8");
|
|
@@ -3330,166 +3543,6 @@ function toEstimateJson(e) {
|
|
|
3330
3543
|
guessed: e.guessed
|
|
3331
3544
|
};
|
|
3332
3545
|
}
|
|
3333
|
-
|
|
3334
|
-
// src/runtime/model-install-plan.ts
|
|
3335
|
-
var MODEL_INSTALL_PLAN_SCHEMA_VERSION = "model-install-plan/0";
|
|
3336
|
-
function runtimeDepsForBackend(backend) {
|
|
3337
|
-
const b = backend.toLowerCase();
|
|
3338
|
-
if (b === "llama.cpp" || b === "llama-cpp" || b === "vibgrate") {
|
|
3339
|
-
return [
|
|
3340
|
-
{
|
|
3341
|
-
id: "node-llama-cpp",
|
|
3342
|
-
kind: "npm-runtime",
|
|
3343
|
-
spec: "node-llama-cpp@^3",
|
|
3344
|
-
reason: "in-process llama.cpp binding for the first-party / llama-cpp provider"
|
|
3345
|
-
}
|
|
3346
|
-
];
|
|
3347
|
-
}
|
|
3348
|
-
if (b === "ollama") {
|
|
3349
|
-
return [
|
|
3350
|
-
{
|
|
3351
|
-
id: "ollama",
|
|
3352
|
-
kind: "native-binary",
|
|
3353
|
-
binary: "ollama",
|
|
3354
|
-
reason: "Ollama on PATH (install from https://ollama.com \u2014 third-party apps are not auto-installed)"
|
|
3355
|
-
}
|
|
3356
|
-
];
|
|
3357
|
-
}
|
|
3358
|
-
return [];
|
|
3359
|
-
}
|
|
3360
|
-
function weightsChannelForBackend(backend, opts) {
|
|
3361
|
-
const b = backend.toLowerCase();
|
|
3362
|
-
if (b === "ollama") return "ollama";
|
|
3363
|
-
if (b === "llama.cpp" || b === "llama-cpp" || b === "vibgrate") {
|
|
3364
|
-
if (opts?.downloadUrl || opts?.weightsRef && lookupCatalog(opts.weightsRef)) return "vibgrate";
|
|
3365
|
-
return "local-path";
|
|
3366
|
-
}
|
|
3367
|
-
if (b === "lm-studio" || b === "lmstudio" || b === "foundry-local") return "manual";
|
|
3368
|
-
return "manual";
|
|
3369
|
-
}
|
|
3370
|
-
function weightsInstalled(ref, installedNames) {
|
|
3371
|
-
const want = ref.toLowerCase();
|
|
3372
|
-
return installedNames.some((n) => {
|
|
3373
|
-
const have = n.toLowerCase();
|
|
3374
|
-
return have === want || have.includes(want) || want.includes(have);
|
|
3375
|
-
});
|
|
3376
|
-
}
|
|
3377
|
-
function buildModelInstallPlan(input) {
|
|
3378
|
-
const hasBinary2 = input.hasBinary ?? (() => false);
|
|
3379
|
-
const pkgInstalled = input.isPackageInstalled ?? isPackageInstalled;
|
|
3380
|
-
const installedNames = input.installedNames ?? [];
|
|
3381
|
-
const offline = !!input.offline;
|
|
3382
|
-
const backend = input.backend;
|
|
3383
|
-
const provider = providerLabel(backend);
|
|
3384
|
-
const runtimeDeps = runtimeDepsForBackend(backend).map((dep) => {
|
|
3385
|
-
if (dep.kind === "npm-runtime" && dep.spec) {
|
|
3386
|
-
return { ...dep, status: pkgInstalled(dep.spec) ? "satisfied" : "missing" };
|
|
3387
|
-
}
|
|
3388
|
-
if (dep.kind === "native-binary" && dep.binary) {
|
|
3389
|
-
return { ...dep, status: hasBinary2(dep.binary) ? "satisfied" : "unmanaged" };
|
|
3390
|
-
}
|
|
3391
|
-
return { ...dep, status: "unmanaged" };
|
|
3392
|
-
});
|
|
3393
|
-
const channel = weightsChannelForBackend(backend, {
|
|
3394
|
-
downloadUrl: input.downloadUrl,
|
|
3395
|
-
weightsRef: input.weightsRef
|
|
3396
|
-
});
|
|
3397
|
-
const weightCached = (input.isWeightCached ?? isWeightCached)(input.weightsRef);
|
|
3398
|
-
const catalog = lookupCatalog(input.weightsRef);
|
|
3399
|
-
const downloadUrl = input.downloadUrl ?? catalog?.url;
|
|
3400
|
-
let weightsStatus = "missing";
|
|
3401
|
-
if (channel === "ollama") {
|
|
3402
|
-
weightsStatus = weightsInstalled(input.weightsRef, installedNames) ? "satisfied" : "missing";
|
|
3403
|
-
} else if (channel === "vibgrate") {
|
|
3404
|
-
weightsStatus = weightCached || weightsInstalled(input.weightsRef, installedNames) || !!input.modelPath ? "satisfied" : "missing";
|
|
3405
|
-
} else if (channel === "local-path") {
|
|
3406
|
-
weightsStatus = weightsInstalled(input.weightsRef, installedNames) || !!input.modelPath || weightCached ? "satisfied" : "manual";
|
|
3407
|
-
} else {
|
|
3408
|
-
weightsStatus = weightsInstalled(input.weightsRef, installedNames) ? "satisfied" : "manual";
|
|
3409
|
-
}
|
|
3410
|
-
const alreadySatisfied = [];
|
|
3411
|
-
const willInstall = [];
|
|
3412
|
-
const willDownload = [];
|
|
3413
|
-
const blocked = [];
|
|
3414
|
-
for (const dep of runtimeDeps) {
|
|
3415
|
-
if (dep.status === "satisfied") {
|
|
3416
|
-
alreadySatisfied.push(dep.id);
|
|
3417
|
-
continue;
|
|
3418
|
-
}
|
|
3419
|
-
if (dep.kind === "npm-runtime" && dep.spec && dep.status === "missing") {
|
|
3420
|
-
if (offline) {
|
|
3421
|
-
blocked.push({ id: dep.id, reason: `${dep.spec} needed but --local/offline forbids install` });
|
|
3422
|
-
} else {
|
|
3423
|
-
willInstall.push(dep.spec);
|
|
3424
|
-
}
|
|
3425
|
-
continue;
|
|
3426
|
-
}
|
|
3427
|
-
if (dep.kind === "native-binary" && dep.status === "unmanaged") {
|
|
3428
|
-
blocked.push({
|
|
3429
|
-
id: dep.id,
|
|
3430
|
-
reason: dep.reason
|
|
3431
|
-
});
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
if (weightsStatus === "satisfied") {
|
|
3435
|
-
alreadySatisfied.push(`weights:${input.weightsRef}`);
|
|
3436
|
-
} else if (weightsStatus === "missing" && (channel === "ollama" || channel === "vibgrate")) {
|
|
3437
|
-
if (offline) {
|
|
3438
|
-
blocked.push({ id: `weights:${input.weightsRef}`, reason: "weights missing and --local/offline forbids download" });
|
|
3439
|
-
} else if (channel === "ollama" && runtimeDeps.some((d) => d.id === "ollama" && d.status === "unmanaged")) {
|
|
3440
|
-
willDownload.push(input.weightsRef);
|
|
3441
|
-
} else if (channel === "vibgrate" && !downloadUrl) {
|
|
3442
|
-
blocked.push({
|
|
3443
|
-
id: `weights:${input.weightsRef}`,
|
|
3444
|
-
reason: `no first-party download URL for ${input.weightsRef} \u2014 place a gguf in the weight store or pass --model-path`
|
|
3445
|
-
});
|
|
3446
|
-
} else {
|
|
3447
|
-
willDownload.push(input.weightsRef);
|
|
3448
|
-
}
|
|
3449
|
-
} else if (weightsStatus === "manual" || weightsStatus === "missing") {
|
|
3450
|
-
blocked.push({
|
|
3451
|
-
id: `weights:${input.weightsRef}`,
|
|
3452
|
-
reason: channel === "local-path" ? `point --model-path at a local gguf for ${input.weightsRef}, or run install when a first-party URL is catalogued` : `install or link weights for ${input.weightsRef} via the backend app`
|
|
3453
|
-
});
|
|
3454
|
-
}
|
|
3455
|
-
const effectiveWillInstall = offline ? [] : willInstall;
|
|
3456
|
-
const effectiveWillDownload = offline ? [] : willDownload;
|
|
3457
|
-
const offlineBlocked = offline && blocked.some((b) => /offline|forbids/i.test(b.reason));
|
|
3458
|
-
const allRuntimeOk = runtimeDeps.every((d) => d.status === "satisfied");
|
|
3459
|
-
const fullyReady = allRuntimeOk && weightsStatus === "satisfied" && blocked.length === 0;
|
|
3460
|
-
return {
|
|
3461
|
-
schemaVersion: MODEL_INSTALL_PLAN_SCHEMA_VERSION,
|
|
3462
|
-
provider,
|
|
3463
|
-
backend,
|
|
3464
|
-
model: input.weightsRef,
|
|
3465
|
-
mode: input.mode,
|
|
3466
|
-
packId: input.packId,
|
|
3467
|
-
license: input.license,
|
|
3468
|
-
promise: input.promise,
|
|
3469
|
-
fit: input.fit,
|
|
3470
|
-
runtimeDeps,
|
|
3471
|
-
weights: {
|
|
3472
|
-
channel,
|
|
3473
|
-
ref: input.weightsRef,
|
|
3474
|
-
status: weightsStatus,
|
|
3475
|
-
downloadUrl: channel === "vibgrate" ? downloadUrl : void 0
|
|
3476
|
-
},
|
|
3477
|
-
alreadySatisfied,
|
|
3478
|
-
willInstall: effectiveWillInstall,
|
|
3479
|
-
willDownload: effectiveWillDownload,
|
|
3480
|
-
blocked,
|
|
3481
|
-
offlineBlocked,
|
|
3482
|
-
ready: fullyReady
|
|
3483
|
-
};
|
|
3484
|
-
}
|
|
3485
|
-
function providerLabel(backend) {
|
|
3486
|
-
const b = backend.toLowerCase();
|
|
3487
|
-
if (b === "llama.cpp" || b === "llama-cpp") return "llama-cpp";
|
|
3488
|
-
if (b === "vibgrate") return "vibgrate";
|
|
3489
|
-
if (b === "lm-studio" || b === "lmstudio") return "lmstudio";
|
|
3490
|
-
if (b === "foundry-local") return "foundry-local";
|
|
3491
|
-
return b === "ollama" ? "ollama" : backend;
|
|
3492
|
-
}
|
|
3493
3546
|
async function executeModelInstallPlan(plan, options = {}) {
|
|
3494
3547
|
const installedDeps = [];
|
|
3495
3548
|
const pulledWeights = [];
|
|
@@ -4083,8 +4136,8 @@ async function runHostBench(options = {}) {
|
|
|
4083
4136
|
}
|
|
4084
4137
|
async function runArmSimulate(input) {
|
|
4085
4138
|
const { arm, lib, modelPath, turns, trie, env, live } = input;
|
|
4086
|
-
const
|
|
4087
|
-
const session = await acquireHostSession(lib,
|
|
4139
|
+
const path39 = `${modelPath}#${arm.id}`;
|
|
4140
|
+
const session = await acquireHostSession(lib, path39);
|
|
4088
4141
|
const system = "You are a coding agent with a Task Capsule.";
|
|
4089
4142
|
const capsule = "function readConfig(): Config { return load(); }";
|
|
4090
4143
|
let last = null;
|
|
@@ -5026,7 +5079,7 @@ function registerModels(program) {
|
|
|
5026
5079
|
);
|
|
5027
5080
|
});
|
|
5028
5081
|
applyGlobalOptions(modeCmd);
|
|
5029
|
-
const
|
|
5082
|
+
const resolve20 = 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) {
|
|
5030
5083
|
const global = readGlobal(this);
|
|
5031
5084
|
const root2 = rootOf(global);
|
|
5032
5085
|
const sys = gatherSystemMemory();
|
|
@@ -5058,7 +5111,7 @@ function registerModels(program) {
|
|
|
5058
5111
|
info(c.yellow(" will not fit \u2014 choose a lower mode or free memory before loading"));
|
|
5059
5112
|
}
|
|
5060
5113
|
});
|
|
5061
|
-
applyGlobalOptions(
|
|
5114
|
+
applyGlobalOptions(resolve20);
|
|
5062
5115
|
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) {
|
|
5063
5116
|
const global = readGlobal(this);
|
|
5064
5117
|
const root2 = rootOf(global);
|
|
@@ -5396,8 +5449,8 @@ function registerModels(program) {
|
|
|
5396
5449
|
}
|
|
5397
5450
|
});
|
|
5398
5451
|
if (opts.out) {
|
|
5399
|
-
const outPath =
|
|
5400
|
-
fs8.mkdirSync(
|
|
5452
|
+
const outPath = path37.resolve(opts.out);
|
|
5453
|
+
fs8.mkdirSync(path37.dirname(outPath), { recursive: true });
|
|
5401
5454
|
fs8.writeFileSync(outPath, `${JSON.stringify(report, null, 2)}
|
|
5402
5455
|
`);
|
|
5403
5456
|
if (!global.json) info(c.dim(` wrote ${outPath}`));
|
|
@@ -5508,11 +5561,11 @@ function fitColor(label) {
|
|
|
5508
5561
|
return label;
|
|
5509
5562
|
}
|
|
5510
5563
|
function confirmYesNo(question) {
|
|
5511
|
-
return new Promise((
|
|
5564
|
+
return new Promise((resolve20) => {
|
|
5512
5565
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
5513
5566
|
rl.question(`${question} [y/N] `, (answer) => {
|
|
5514
5567
|
rl.close();
|
|
5515
|
-
|
|
5568
|
+
resolve20(/^y(es)?$/i.test(answer.trim()));
|
|
5516
5569
|
});
|
|
5517
5570
|
});
|
|
5518
5571
|
}
|
|
@@ -5538,7 +5591,7 @@ function printBackends(backends) {
|
|
|
5538
5591
|
}
|
|
5539
5592
|
}
|
|
5540
5593
|
function codeConfigPath(root2) {
|
|
5541
|
-
return
|
|
5594
|
+
return path37.join(root2, ".vibgrate", "code.json");
|
|
5542
5595
|
}
|
|
5543
5596
|
function loadCodeConfig(root2) {
|
|
5544
5597
|
try {
|
|
@@ -5620,7 +5673,7 @@ function discoverMcpServers(root2, ownServers) {
|
|
|
5620
5673
|
const servers = {};
|
|
5621
5674
|
const sources = [];
|
|
5622
5675
|
for (const rel of MCP_CONFIG_FILES) {
|
|
5623
|
-
const found = readMcpServersFile(
|
|
5676
|
+
const found = readMcpServersFile(path37.join(root2, rel));
|
|
5624
5677
|
const names = Object.keys(found);
|
|
5625
5678
|
if (names.length) {
|
|
5626
5679
|
sources.push(rel);
|
|
@@ -5643,11 +5696,13 @@ function registerCode(program) {
|
|
|
5643
5696
|
let provider = opts.provider ?? config.provider;
|
|
5644
5697
|
let model = opts.model ?? config.model;
|
|
5645
5698
|
const modeFlag = opts.mode ?? config.modelProfile?.mode;
|
|
5646
|
-
|
|
5699
|
+
let codeModeActive = false;
|
|
5700
|
+
const customSelection = !!(opts.provider || opts.model || opts.modelPath || config.provider || config.model);
|
|
5701
|
+
if (!customSelection && (modeFlag || !provider && !model)) {
|
|
5647
5702
|
try {
|
|
5648
|
-
const { parseMode: parseMode2, resolveMode: resolveMode2, readOrchestratorState: readOrchestratorState2, activePin: activePin2
|
|
5703
|
+
const { parseMode: parseMode2, resolveMode: resolveMode2, readOrchestratorState: readOrchestratorState2, activePin: activePin2 } = await import('./model-orchestrator-4VSYP4J4.js');
|
|
5649
5704
|
const { gatherSystemMemory: gatherSystemMemory2 } = await import('./local-runtime-5O2NN3GA.js');
|
|
5650
|
-
const { loadGraph: loadGraph2 } = await import('./load-
|
|
5705
|
+
const { loadGraph: loadGraph2 } = await import('./load-QPOWQD7C.js');
|
|
5651
5706
|
const state = readOrchestratorState2();
|
|
5652
5707
|
const mode = parseMode2(modeFlag) ?? state.defaultMode ?? void 0;
|
|
5653
5708
|
const pin = mode ? activePin2(mode, state) : null;
|
|
@@ -5676,26 +5731,31 @@ function registerCode(program) {
|
|
|
5676
5731
|
ExitCode.ERROR
|
|
5677
5732
|
);
|
|
5678
5733
|
}
|
|
5679
|
-
const { resolveGgufPath } = await import('./resolve-gguf-
|
|
5734
|
+
const { resolveGgufPath } = await import('./resolve-gguf-Y6FH3CNB.js');
|
|
5735
|
+
const primaryRef = resolved.pack.primary.backend === "llama.cpp" ? resolved.pack.primary.weightsRef : resolved.underlying.weightsRef;
|
|
5680
5736
|
const gguf = resolveGgufPath({
|
|
5681
|
-
modelRef:
|
|
5737
|
+
modelRef: primaryRef,
|
|
5682
5738
|
modelPath: opts.modelPath
|
|
5683
5739
|
}) ?? resolveGgufPath({
|
|
5684
|
-
modelRef: resolved.
|
|
5740
|
+
modelRef: resolved.underlying.weightsRef,
|
|
5741
|
+
modelPath: opts.modelPath
|
|
5685
5742
|
});
|
|
5686
|
-
if (gguf && !opts.
|
|
5743
|
+
if (!gguf && !opts.mock) {
|
|
5744
|
+
throw new CliError(
|
|
5745
|
+
`Code Mode ${resolved.mode} uses the Vibgrate model manager \u2014 weights not installed. Run \`vg models install ${resolved.mode}\` then retry. (Custom Ollama/LM Studio: pass --provider explicitly.)`,
|
|
5746
|
+
ExitCode.NOT_FOUND
|
|
5747
|
+
);
|
|
5748
|
+
}
|
|
5749
|
+
if (gguf) {
|
|
5750
|
+
codeModeActive = true;
|
|
5687
5751
|
provider = "llama-cpp";
|
|
5688
|
-
model = model ?? gguf.ref ??
|
|
5752
|
+
model = model ?? gguf.ref ?? primaryRef;
|
|
5689
5753
|
opts.modelPath = gguf.path;
|
|
5690
5754
|
if (!global.json && !global.quiet && !opts.streamJson) {
|
|
5691
5755
|
info(
|
|
5692
|
-
`${c.cyan("vg code")} \xB7 Code Mode ${c.bold(resolved.mode)} \u2192
|
|
5756
|
+
`${c.cyan("vg code")} \xB7 Code Mode ${c.bold(resolved.mode)} \u2192 Vibgrate manager ${c.dim(gguf.path)} ${c.dim(`(${resolved.fit.label})`)}`
|
|
5693
5757
|
);
|
|
5694
5758
|
}
|
|
5695
|
-
} else {
|
|
5696
|
-
const ollamaFb = resolved.underlying.backend === "ollama" ? resolved.underlying : resolved.pack.fallback?.find((f) => f.backend === "ollama") ?? resolved.underlying;
|
|
5697
|
-
provider = provider ?? providerForBackend2(ollamaFb.backend);
|
|
5698
|
-
model = model ?? ollamaFb.weightsRef;
|
|
5699
5759
|
}
|
|
5700
5760
|
if (!config.modelProfile?.capsuleBudgetTokens) {
|
|
5701
5761
|
config.modelProfile = {
|
|
@@ -5709,11 +5769,6 @@ function registerCode(program) {
|
|
|
5709
5769
|
} else if (!config.modelProfile?.mode) {
|
|
5710
5770
|
config.modelProfile = { ...config.modelProfile, mode: resolved.mode };
|
|
5711
5771
|
}
|
|
5712
|
-
if (!global.json && !global.quiet && !opts.streamJson && provider !== "llama-cpp") {
|
|
5713
|
-
info(
|
|
5714
|
-
`${c.cyan("vg code")} \xB7 Code Mode ${c.bold(resolved.mode)} \u2192 ${resolved.underlying.weightsRef} ${c.dim(`(${resolved.fit.label})`)}`
|
|
5715
|
-
);
|
|
5716
|
-
}
|
|
5717
5772
|
} catch (e) {
|
|
5718
5773
|
if (e instanceof CliError) throw e;
|
|
5719
5774
|
if (!provider && !model && !opts.mock) throw e;
|
|
@@ -5731,7 +5786,7 @@ function registerCode(program) {
|
|
|
5731
5786
|
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
5732
5787
|
throw usageError('say what to change, e.g. `vg code "add a --timeout flag to the scan command"` (guided mode needs an interactive terminal)');
|
|
5733
5788
|
}
|
|
5734
|
-
const { runInteractive } = await import('./interactive-
|
|
5789
|
+
const { runInteractive } = await import('./interactive-SMHVURYK.js');
|
|
5735
5790
|
await runInteractive(
|
|
5736
5791
|
rootOf(global),
|
|
5737
5792
|
global,
|
|
@@ -5775,28 +5830,52 @@ function registerCode(program) {
|
|
|
5775
5830
|
model,
|
|
5776
5831
|
modelPath: opts.modelPath,
|
|
5777
5832
|
local: global.local,
|
|
5778
|
-
consent: opts.yes,
|
|
5779
|
-
mockReply
|
|
5833
|
+
consent: opts.yes || codeModeActive || customSelection,
|
|
5834
|
+
mockReply,
|
|
5835
|
+
codeMode: codeModeActive,
|
|
5836
|
+
preferEmbedded: codeModeActive || void 0
|
|
5780
5837
|
},
|
|
5781
5838
|
{}
|
|
5782
5839
|
);
|
|
5840
|
+
if (!opts.mock && route.providers[0]) {
|
|
5841
|
+
const { ensureManagerRuntime } = await import('./model-manager-PN7HEDXD.js');
|
|
5842
|
+
const ensure = await ensureManagerRuntime({
|
|
5843
|
+
providerId: route.providers[0].id,
|
|
5844
|
+
model: route.providers[0].model,
|
|
5845
|
+
offline: !!global.local,
|
|
5846
|
+
// Code Mode / explicit custom selection / --yes count as consent for
|
|
5847
|
+
// npm runtime deps (and ollama pull when the binary is already present).
|
|
5848
|
+
consent: !!(opts.yes || codeModeActive || customSelection || process.stdin.isTTY),
|
|
5849
|
+
onProgress: (line) => {
|
|
5850
|
+
if (!global.json && !global.quiet && !opts.streamJson) info(c.dim(` ${line}`));
|
|
5851
|
+
}
|
|
5852
|
+
});
|
|
5853
|
+
if (!ensure.ok) {
|
|
5854
|
+
throw new CliError(ensure.error ?? "model manager runtime not ready", ExitCode.ERROR);
|
|
5855
|
+
}
|
|
5856
|
+
if (!global.json && !global.quiet && !opts.streamJson && (ensure.installed.length || ensure.pulled.length)) {
|
|
5857
|
+
for (const s of ensure.installed) info(c.dim(` installed ${s}`));
|
|
5858
|
+
for (const s of ensure.pulled) info(c.dim(` pulled ${s}`));
|
|
5859
|
+
}
|
|
5860
|
+
}
|
|
5783
5861
|
if (!global.json && !global.quiet) {
|
|
5784
5862
|
info(`${c.cyan("vg code")} \xB7 ${c.dim(route.reason)}`);
|
|
5863
|
+
info(`${c.cyan("vg code")} \xB7 manager ${c.bold(route.managerLine)}`);
|
|
5785
5864
|
}
|
|
5786
5865
|
if (opts.streamJson && !opts.mock) {
|
|
5787
5866
|
const primarySlug = route.providers[0]?.model.includes("/") ? route.providers[0].model.split("/")[0] : route.providers[0]?.id;
|
|
5788
|
-
const { runCodeStreamJson } = await import('./stream-json-
|
|
5789
|
-
const { nodeCodeFs } = await import('./session-
|
|
5867
|
+
const { runCodeStreamJson } = await import('./stream-json-X7UQFB4T.js');
|
|
5868
|
+
const { nodeCodeFs } = await import('./session-W3646AOV.js');
|
|
5790
5869
|
const readline5 = await import('readline');
|
|
5791
5870
|
const child = await import('child_process');
|
|
5792
5871
|
const { loadOrDiscoverFederation } = await import('./federation-SZWZIFZ7.js');
|
|
5793
5872
|
const { resolveExecutionEnv } = await import('./execution-env-ZU45JZ4G.js');
|
|
5794
5873
|
const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-TFBKCNJG.js');
|
|
5795
|
-
const { startCodeRuntimeSession } = await import('./runtime-session-
|
|
5796
|
-
const { resolveGraphBackend } = await import('./graph-backend-
|
|
5874
|
+
const { startCodeRuntimeSession } = await import('./runtime-session-4AMZIAAG.js');
|
|
5875
|
+
const { resolveGraphBackend } = await import('./graph-backend-UTOL3SHE.js');
|
|
5797
5876
|
const { detectGitRef } = await import('./git-ref-XDXB6JP5.js');
|
|
5798
5877
|
const { repositoryIdFromRoot } = await import('./paths-2RAH3GME.js');
|
|
5799
|
-
const { vgdRequest: vgdRequest2 } = await import('./vgd-
|
|
5878
|
+
const { vgdRequest: vgdRequest2 } = await import('./vgd-CVLKBS7K.js');
|
|
5800
5879
|
const federation = loadOrDiscoverFederation(root2);
|
|
5801
5880
|
const modelProfile = mergeModelExecutionProfile(
|
|
5802
5881
|
resolveModelExecutionProfile({
|
|
@@ -5885,8 +5964,8 @@ ${res.stderr}` : ""), exitCode: res.status ?? 1 };
|
|
|
5885
5964
|
if (!autonomous && !tty) {
|
|
5886
5965
|
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).");
|
|
5887
5966
|
}
|
|
5888
|
-
const { agentTask } = await import('./interactive-
|
|
5889
|
-
const { nodeCodeFs } = await import('./session-
|
|
5967
|
+
const { agentTask } = await import('./interactive-SMHVURYK.js');
|
|
5968
|
+
const { nodeCodeFs } = await import('./session-W3646AOV.js');
|
|
5890
5969
|
const { TtyPrompter } = await import('./ui-Q6DJ3GCU.js');
|
|
5891
5970
|
let priorSummary;
|
|
5892
5971
|
if (opts.continue) {
|
|
@@ -5908,11 +5987,11 @@ ${res.stderr}` : ""), exitCode: res.status ?? 1 };
|
|
|
5908
5987
|
const { loadFederation } = await import('./federation-SZWZIFZ7.js');
|
|
5909
5988
|
const { resolveExecutionEnv } = await import('./execution-env-ZU45JZ4G.js');
|
|
5910
5989
|
const { resolveModelExecutionProfile, mergeModelExecutionProfile } = await import('./model-execution-profile-TFBKCNJG.js');
|
|
5911
|
-
const { startCodeRuntimeSession } = await import('./runtime-session-
|
|
5912
|
-
const { resolveGraphBackend } = await import('./graph-backend-
|
|
5990
|
+
const { startCodeRuntimeSession } = await import('./runtime-session-4AMZIAAG.js');
|
|
5991
|
+
const { resolveGraphBackend } = await import('./graph-backend-UTOL3SHE.js');
|
|
5913
5992
|
const { detectGitRef } = await import('./git-ref-XDXB6JP5.js');
|
|
5914
5993
|
const { repositoryIdFromRoot } = await import('./paths-2RAH3GME.js');
|
|
5915
|
-
const { vgdRequest: vgdRequest2 } = await import('./vgd-
|
|
5994
|
+
const { vgdRequest: vgdRequest2 } = await import('./vgd-CVLKBS7K.js');
|
|
5916
5995
|
const federation = loadFederation(root2);
|
|
5917
5996
|
const modelProfile = mergeModelExecutionProfile(
|
|
5918
5997
|
resolveModelExecutionProfile({
|
|
@@ -6056,11 +6135,11 @@ function resolveSecurityTierFlag(flag, fromConfig, auto) {
|
|
|
6056
6135
|
return auto ? "L1" : "L0";
|
|
6057
6136
|
}
|
|
6058
6137
|
function confirm(question) {
|
|
6059
|
-
return new Promise((
|
|
6138
|
+
return new Promise((resolve20) => {
|
|
6060
6139
|
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
6061
6140
|
rl.question(`${question} [y/N] `, (answer) => {
|
|
6062
6141
|
rl.close();
|
|
6063
|
-
|
|
6142
|
+
resolve20(/^y(es)?$/i.test(answer.trim()));
|
|
6064
6143
|
});
|
|
6065
6144
|
});
|
|
6066
6145
|
}
|
|
@@ -6217,7 +6296,7 @@ async function addCmd(root2, rest, opts, asJson) {
|
|
|
6217
6296
|
}
|
|
6218
6297
|
function readPackageVersion(root2) {
|
|
6219
6298
|
try {
|
|
6220
|
-
const pkg = JSON.parse(fs8__default.readFileSync(
|
|
6299
|
+
const pkg = JSON.parse(fs8__default.readFileSync(path37__default.join(root2, "package.json"), "utf8"));
|
|
6221
6300
|
return typeof pkg.version === "string" ? pkg.version : void 0;
|
|
6222
6301
|
} catch {
|
|
6223
6302
|
return void 0;
|
|
@@ -6240,8 +6319,8 @@ async function publishCmd(root2, rest, opts, global, asJson) {
|
|
|
6240
6319
|
if (!parsed) throw new CliError("publishing a private library requires a DSN \u2014 run `vibgrate login` or set VIBGRATE_DSN", ExitCode.USAGE_ERROR);
|
|
6241
6320
|
const version = (opts.version || readPackageVersion(root2) || "").trim();
|
|
6242
6321
|
if (!version) throw usageError("a --version is required (or run from a package whose package.json has a version)");
|
|
6243
|
-
const readme = readOptionalFile(opts.readme ?
|
|
6244
|
-
const dts = opts.dts ? readOptionalFile(
|
|
6322
|
+
const readme = readOptionalFile(opts.readme ? path37__default.resolve(opts.readme) : path37__default.join(root2, "README.md"));
|
|
6323
|
+
const dts = opts.dts ? readOptionalFile(path37__default.resolve(opts.dts)) : void 0;
|
|
6245
6324
|
if (!readme && !dts) throw usageError("nothing to publish \u2014 no README.md found and no --dts given");
|
|
6246
6325
|
const result = await publishPrivateLibrary(
|
|
6247
6326
|
{ name, version, readme, dts, language: opts.language },
|
|
@@ -6354,7 +6433,7 @@ async function showCmd(root2, name, budget, asJson, opts = {}) {
|
|
|
6354
6433
|
out(doc);
|
|
6355
6434
|
}
|
|
6356
6435
|
function registerExport(program) {
|
|
6357
|
-
const cmd = program.command("export").description("export the map (format inferred: json|ndjson|graphml|dot|cypher|sql|md|html|cdx.json|spdx.json)").argument("[file]", "target file (or - for stdout)", "map.json").action(function(file) {
|
|
6436
|
+
const cmd = program.command("export").description("export the map (format inferred: json|ndjson|graphml|dot|cypher|sql|md|html|cdx.json|spdx.json)").argument("[file]", "target file (or - for stdout)", "map.json").option("--compact", "compact JSON (no pretty-print; auto for large maps)").option("--slim", "drop heavy fields (area member lists, grounding) for smaller exports").action(function(file, opts) {
|
|
6358
6437
|
const global = readGlobal(this);
|
|
6359
6438
|
const { graph } = requireGraph(global);
|
|
6360
6439
|
const root2 = rootOf(global);
|
|
@@ -6365,13 +6444,15 @@ function registerExport(program) {
|
|
|
6365
6444
|
graph,
|
|
6366
6445
|
deps: needsDeps ? inventory(root2).records : void 0,
|
|
6367
6446
|
models: needsDeps && !global.local ? discoverModels() : void 0,
|
|
6368
|
-
generatedAt: graph.generatedAt
|
|
6447
|
+
generatedAt: graph.generatedAt,
|
|
6448
|
+
compact: opts.compact === true ? true : opts.compact === false ? false : void 0,
|
|
6449
|
+
slim: opts.slim === true
|
|
6369
6450
|
});
|
|
6370
6451
|
if (file === "-") {
|
|
6371
6452
|
out(content.trimEnd());
|
|
6372
6453
|
return;
|
|
6373
6454
|
}
|
|
6374
|
-
fs8.mkdirSync(
|
|
6455
|
+
fs8.mkdirSync(path37.dirname(path37.resolve(file)), { recursive: true });
|
|
6375
6456
|
fs8.writeFileSync(file, content);
|
|
6376
6457
|
info(`${c.green("\u2714")} wrote ${file} ${c.dim(`(${format})`)}`);
|
|
6377
6458
|
});
|
|
@@ -6382,37 +6463,37 @@ function detectFormat(file) {
|
|
|
6382
6463
|
if (lower.endsWith(".cdx.json")) return "cyclonedx";
|
|
6383
6464
|
if (lower.endsWith(".spdx.json")) return "spdx";
|
|
6384
6465
|
if (file === "-") return "json";
|
|
6385
|
-
return formatForExt(
|
|
6466
|
+
return formatForExt(path37.extname(file));
|
|
6386
6467
|
}
|
|
6387
6468
|
function registerBundle(program) {
|
|
6388
6469
|
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) {
|
|
6389
6470
|
const global = readGlobal(this);
|
|
6390
6471
|
const root2 = rootOf(global);
|
|
6391
|
-
const outDir =
|
|
6472
|
+
const outDir = path37.resolve(root2, opts.out ?? "vg-bundle");
|
|
6392
6473
|
let grammarFiles;
|
|
6393
6474
|
try {
|
|
6394
6475
|
grammarFiles = resolvedGrammarFiles();
|
|
6395
6476
|
} catch {
|
|
6396
6477
|
throw new CliError("no grammars found to bundle (run a build first)", ExitCode.ERROR);
|
|
6397
6478
|
}
|
|
6398
|
-
fs8.mkdirSync(
|
|
6479
|
+
fs8.mkdirSync(path37.join(outDir, "grammars"), { recursive: true });
|
|
6399
6480
|
let grammarCount = 0;
|
|
6400
6481
|
for (const { fileName, absPath } of grammarFiles) {
|
|
6401
|
-
fs8.copyFileSync(absPath,
|
|
6482
|
+
fs8.copyFileSync(absPath, path37.join(outDir, "grammars", fileName));
|
|
6402
6483
|
grammarCount++;
|
|
6403
6484
|
}
|
|
6404
6485
|
const included = [`grammars/ (${grammarCount} .wasm)`];
|
|
6405
6486
|
const graphSrc = resolveGraphPath(root2, global.graph);
|
|
6406
6487
|
if (fs8.existsSync(graphSrc)) {
|
|
6407
|
-
fs8.copyFileSync(graphSrc,
|
|
6488
|
+
fs8.copyFileSync(graphSrc, path37.join(outDir, "graph.json"));
|
|
6408
6489
|
included.push("graph.json");
|
|
6409
6490
|
}
|
|
6410
6491
|
const cat = catalogPath(root2);
|
|
6411
6492
|
if (fs8.existsSync(cat)) {
|
|
6412
|
-
fs8.copyFileSync(cat,
|
|
6493
|
+
fs8.copyFileSync(cat, path37.join(outDir, "vibgrate.lib.json"));
|
|
6413
6494
|
included.push("vibgrate.lib.json");
|
|
6414
6495
|
if (fs8.existsSync(libDir(root2))) {
|
|
6415
|
-
fs8.cpSync(libDir(root2),
|
|
6496
|
+
fs8.cpSync(libDir(root2), path37.join(outDir, "lib"), { recursive: true });
|
|
6416
6497
|
included.push("lib/");
|
|
6417
6498
|
}
|
|
6418
6499
|
}
|
|
@@ -6424,15 +6505,15 @@ function registerBundle(program) {
|
|
|
6424
6505
|
included,
|
|
6425
6506
|
usage: "Run `vg build --grammars <this dir>/grammars` to build fully offline."
|
|
6426
6507
|
};
|
|
6427
|
-
fs8.writeFileSync(
|
|
6508
|
+
fs8.writeFileSync(path37.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
|
|
6428
6509
|
`);
|
|
6429
6510
|
if (global.json) {
|
|
6430
|
-
json({ out:
|
|
6511
|
+
json({ out: path37.relative(root2, outDir), ...manifest });
|
|
6431
6512
|
return;
|
|
6432
6513
|
}
|
|
6433
|
-
info(`${c.cyan("vg bundle")} \xB7 wrote ${
|
|
6514
|
+
info(`${c.cyan("vg bundle")} \xB7 wrote ${path37.relative(root2, outDir)}/`);
|
|
6434
6515
|
for (const i of included) info(` ${c.green("\u2714")} ${i}`);
|
|
6435
|
-
info(c.dim(` offline: vg build --grammars "${
|
|
6516
|
+
info(c.dim(` offline: vg build --grammars "${path37.relative(root2, outDir)}/grammars"`));
|
|
6436
6517
|
});
|
|
6437
6518
|
applyGlobalOptions(cmd);
|
|
6438
6519
|
}
|
|
@@ -6450,7 +6531,7 @@ async function runDoctor(global) {
|
|
|
6450
6531
|
const root2 = rootOf(global);
|
|
6451
6532
|
const local = global.local === true;
|
|
6452
6533
|
const graphPath = resolveGraphPath(root2, global.graph);
|
|
6453
|
-
const configFile = CONFIG_BASENAMES.find((f) => fs8.existsSync(
|
|
6534
|
+
const configFile = CONFIG_BASENAMES.find((f) => fs8.existsSync(path37.join(root2, f))) ?? null;
|
|
6454
6535
|
const graph = loadGraph(root2, graphPath);
|
|
6455
6536
|
let staleFiles = null;
|
|
6456
6537
|
if (graph) {
|
|
@@ -6476,13 +6557,13 @@ async function runDoctor(global) {
|
|
|
6476
6557
|
root: root2,
|
|
6477
6558
|
configFile,
|
|
6478
6559
|
map: {
|
|
6479
|
-
path:
|
|
6560
|
+
path: path37.relative(root2, graphPath),
|
|
6480
6561
|
built: graph !== null,
|
|
6481
6562
|
generatedAt: graph?.generatedAt ?? null,
|
|
6482
6563
|
staleFiles
|
|
6483
6564
|
},
|
|
6484
6565
|
libCatalog: {
|
|
6485
|
-
path:
|
|
6566
|
+
path: path37.relative(root2, catalogPath(root2)),
|
|
6486
6567
|
present: fs8.existsSync(catalogPath(root2)),
|
|
6487
6568
|
libraries: libCount
|
|
6488
6569
|
},
|
|
@@ -6540,7 +6621,7 @@ async function runDoctor(global) {
|
|
|
6540
6621
|
);
|
|
6541
6622
|
info(
|
|
6542
6623
|
` host pool ${li.hostPool.size} warm session(s)` + (li.hostPool.sessions[0] ? c.dim(
|
|
6543
|
-
` \xB7 last ${
|
|
6624
|
+
` \xB7 last ${path37.basename(li.hostPool.sessions[0].modelPath)} kv=${li.hostPool.sessions[0].kvBlocks}`
|
|
6544
6625
|
) : c.dim(" \xB7 none (load via vg code / vgd host-load)"))
|
|
6545
6626
|
);
|
|
6546
6627
|
if (li.dynamicOnToken || li.dynamicCustomSampler) {
|
|
@@ -6676,7 +6757,7 @@ function registerDaemon(program) {
|
|
|
6676
6757
|
const register = cmd.command("register").description("register the current repository with a running vgd").argument("[root]", "repository root (default: cwd)").action(async function(rootArg) {
|
|
6677
6758
|
const global = readGlobal(this);
|
|
6678
6759
|
const socketPath = socketOf(this);
|
|
6679
|
-
const root2 =
|
|
6760
|
+
const root2 = path37.resolve(rootArg ?? rootOf(global));
|
|
6680
6761
|
if (!await vgdIsRunning({ socketPath })) {
|
|
6681
6762
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
6682
6763
|
}
|
|
@@ -6712,7 +6793,7 @@ function registerDaemon(program) {
|
|
|
6712
6793
|
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) {
|
|
6713
6794
|
const global = readGlobal(this);
|
|
6714
6795
|
const socketPath = socketOf(this);
|
|
6715
|
-
const primary =
|
|
6796
|
+
const primary = path37.resolve(rootArg ?? rootOf(global));
|
|
6716
6797
|
if (!await vgdIsRunning({ socketPath })) {
|
|
6717
6798
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon start\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
6718
6799
|
}
|
|
@@ -6740,11 +6821,11 @@ function registerDaemon(program) {
|
|
|
6740
6821
|
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) {
|
|
6741
6822
|
const global = readGlobal(this);
|
|
6742
6823
|
const socketPath = socketOf(this);
|
|
6743
|
-
const root2 =
|
|
6824
|
+
const root2 = path37.resolve(rootArg ?? rootOf(global));
|
|
6744
6825
|
if (!await vgdIsRunning({ socketPath })) {
|
|
6745
6826
|
throw new CliError(`vgd is not running \u2014 start it with \`vg daemon ensure\` (${socketPath})`, ExitCode.NOT_FOUND);
|
|
6746
6827
|
}
|
|
6747
|
-
const { loadGraph: loadGraph2 } = await import('./load-
|
|
6828
|
+
const { loadGraph: loadGraph2 } = await import('./load-QPOWQD7C.js');
|
|
6748
6829
|
const { detectGitRef } = await import('./git-ref-XDXB6JP5.js');
|
|
6749
6830
|
const { repositoryIdFromRoot } = await import('./paths-2RAH3GME.js');
|
|
6750
6831
|
const opts = this.opts();
|
|
@@ -6860,7 +6941,7 @@ function socketOf(cmd) {
|
|
|
6860
6941
|
let c2 = cmd;
|
|
6861
6942
|
while (c2) {
|
|
6862
6943
|
const opts = c2.opts();
|
|
6863
|
-
if (opts.socket) return
|
|
6944
|
+
if (opts.socket) return path37.resolve(opts.socket);
|
|
6864
6945
|
c2 = c2.parent;
|
|
6865
6946
|
}
|
|
6866
6947
|
return vgdSocketPath();
|
|
@@ -7077,11 +7158,11 @@ function registerLlmHost(program) {
|
|
|
7077
7158
|
applyGlobalOptions(cmd);
|
|
7078
7159
|
}
|
|
7079
7160
|
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) => {
|
|
7080
|
-
const rootDir =
|
|
7081
|
-
const vibgrateDir2 =
|
|
7161
|
+
const rootDir = path37.resolve(targetPath);
|
|
7162
|
+
const vibgrateDir2 = path37.join(rootDir, ".vibgrate");
|
|
7082
7163
|
await ensureDir(vibgrateDir2);
|
|
7083
7164
|
console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold(".vibgrate/")} directory`);
|
|
7084
|
-
const configPath =
|
|
7165
|
+
const configPath = path37.join(rootDir, "vibgrate.config.ts");
|
|
7085
7166
|
if (await pathExists(configPath)) {
|
|
7086
7167
|
console.log(chalk7.dim(" vibgrate.config.ts already exists, skipping"));
|
|
7087
7168
|
} else {
|
|
@@ -7089,7 +7170,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
|
|
|
7089
7170
|
console.log(chalk7.green("\u2714") + ` Created ${chalk7.bold("vibgrate.config.ts")}`);
|
|
7090
7171
|
}
|
|
7091
7172
|
if (opts.baseline) {
|
|
7092
|
-
const { runBaseline } = await import('./baseline-
|
|
7173
|
+
const { runBaseline } = await import('./baseline-ENCOSJYQ.js');
|
|
7093
7174
|
await runBaseline(rootDir);
|
|
7094
7175
|
}
|
|
7095
7176
|
console.log("");
|
|
@@ -7192,16 +7273,16 @@ function collectPackageImports(graph, ecosystem, pkg) {
|
|
|
7192
7273
|
};
|
|
7193
7274
|
}
|
|
7194
7275
|
async function fileReferencesIdentifier(rootDir, relFile, identifier, readFile3) {
|
|
7195
|
-
const content = await readFile3(
|
|
7276
|
+
const content = await readFile3(path37.join(rootDir, relFile));
|
|
7196
7277
|
if (!content) return false;
|
|
7197
7278
|
const escaped = identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7198
7279
|
return new RegExp(`\\b${escaped}\\b`).test(content);
|
|
7199
7280
|
}
|
|
7200
7281
|
async function defaultReadFile(absPath) {
|
|
7201
7282
|
try {
|
|
7202
|
-
const stat2 = await
|
|
7283
|
+
const stat2 = await fs21.stat(absPath);
|
|
7203
7284
|
if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
|
|
7204
|
-
return await
|
|
7285
|
+
return await fs21.readFile(absPath, "utf8");
|
|
7205
7286
|
} catch {
|
|
7206
7287
|
return null;
|
|
7207
7288
|
}
|
|
@@ -7386,7 +7467,7 @@ var AI_ASSISTANT_DETECTORS = [
|
|
|
7386
7467
|
async function detectAiAssistant(rootDir) {
|
|
7387
7468
|
for (const detector of AI_ASSISTANT_DETECTORS) {
|
|
7388
7469
|
for (const file of detector.files) {
|
|
7389
|
-
if (await pathExists$1(
|
|
7470
|
+
if (await pathExists$1(path37.join(rootDir, file))) {
|
|
7390
7471
|
return detector.name;
|
|
7391
7472
|
}
|
|
7392
7473
|
}
|
|
@@ -7579,7 +7660,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
|
|
|
7579
7660
|
collectExcludes,
|
|
7580
7661
|
[]
|
|
7581
7662
|
).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) => {
|
|
7582
|
-
const rootDir =
|
|
7663
|
+
const rootDir = path37.resolve(targetPath);
|
|
7583
7664
|
if (!await pathExists$1(rootDir)) {
|
|
7584
7665
|
console.error(chalk7.red(`Path does not exist: ${rootDir}`));
|
|
7585
7666
|
process.exit(1);
|
|
@@ -7587,7 +7668,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
|
|
|
7587
7668
|
const hasDsn = !!resolveDsn(opts.dsn);
|
|
7588
7669
|
const willPush = !opts.offline && (opts.push || hasDsn);
|
|
7589
7670
|
const noLocalArtifacts = opts.localArtifacts === false;
|
|
7590
|
-
const isFirstRun = !await pathExists$1(
|
|
7671
|
+
const isFirstRun = !await pathExists$1(path37.join(rootDir, ".vibgrate", "scan_result.json"));
|
|
7591
7672
|
let pinnedRegion;
|
|
7592
7673
|
let planTier;
|
|
7593
7674
|
let upgradeUrl;
|
|
@@ -7866,11 +7947,11 @@ function scanStaleness(rootDir, artifactPath) {
|
|
|
7866
7947
|
scanned++;
|
|
7867
7948
|
if (scanned > MAX_ENTRIES) break;
|
|
7868
7949
|
if (e.isDirectory()) {
|
|
7869
|
-
if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(
|
|
7950
|
+
if (!SKIP_DIRS2.has(e.name) && !e.name.startsWith(".")) walk2(path37.join(dir, e.name), depth + 1);
|
|
7870
7951
|
continue;
|
|
7871
7952
|
}
|
|
7872
7953
|
if (!WATCHED_FILES.has(e.name) && !WATCHED_EXT.test(e.name)) continue;
|
|
7873
|
-
const abs =
|
|
7954
|
+
const abs = path37.join(dir, e.name);
|
|
7874
7955
|
let mtimeMs;
|
|
7875
7956
|
try {
|
|
7876
7957
|
mtimeMs = fs8.statSync(abs).mtimeMs;
|
|
@@ -7879,7 +7960,7 @@ function scanStaleness(rootDir, artifactPath) {
|
|
|
7879
7960
|
}
|
|
7880
7961
|
if (mtimeMs > newest) {
|
|
7881
7962
|
newest = mtimeMs;
|
|
7882
|
-
newestChanged =
|
|
7963
|
+
newestChanged = path37.relative(rootDir, abs) || e.name;
|
|
7883
7964
|
}
|
|
7884
7965
|
}
|
|
7885
7966
|
};
|
|
@@ -8016,13 +8097,13 @@ function analyzeTree(root2, packages) {
|
|
|
8016
8097
|
if (filesSeen >= MAX_FILES) return;
|
|
8017
8098
|
if (entry.isDirectory()) {
|
|
8018
8099
|
if (SKIP_DIRS3.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
8019
|
-
walk2(
|
|
8100
|
+
walk2(path37.join(dir, entry.name), depth + 1);
|
|
8020
8101
|
continue;
|
|
8021
8102
|
}
|
|
8022
|
-
const fileEco = EXT_ECOSYSTEM[
|
|
8103
|
+
const fileEco = EXT_ECOSYSTEM[path37.extname(entry.name)];
|
|
8023
8104
|
if (!fileEco || fileEco === "unknown") continue;
|
|
8024
8105
|
filesSeen++;
|
|
8025
|
-
const full =
|
|
8106
|
+
const full = path37.join(dir, entry.name);
|
|
8026
8107
|
let content;
|
|
8027
8108
|
try {
|
|
8028
8109
|
if (fs8.statSync(full).size > MAX_FILE_BYTES2) continue;
|
|
@@ -8337,7 +8418,7 @@ function applyPlan(rootDir, upgrades, opts = {}) {
|
|
|
8337
8418
|
}
|
|
8338
8419
|
const outcomes = effective.map((t) => {
|
|
8339
8420
|
const c2 = pmCommandFor(u.ecosystem, u.package, u.to, opts.packageManager, { workspaceRoot: t.isWorkspaceRoot });
|
|
8340
|
-
return { t, res: run(c2,
|
|
8421
|
+
return { t, res: run(c2, path37.join(rootDir, t.dir)) };
|
|
8341
8422
|
});
|
|
8342
8423
|
const failures = outcomes.filter((o) => !o.res.ok);
|
|
8343
8424
|
if (failures.length === 0) {
|
|
@@ -8366,8 +8447,8 @@ function applyPlan(rootDir, upgrades, opts = {}) {
|
|
|
8366
8447
|
return results;
|
|
8367
8448
|
}
|
|
8368
8449
|
var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
|
|
8369
|
-
var CACHE_DIR =
|
|
8370
|
-
var CACHE_FILE =
|
|
8450
|
+
var CACHE_DIR = path37.join(os.homedir(), ".vibgrate");
|
|
8451
|
+
var CACHE_FILE = path37.join(CACHE_DIR, "update-check.json");
|
|
8371
8452
|
async function fetchLatestVersion() {
|
|
8372
8453
|
try {
|
|
8373
8454
|
const controller = new AbortController();
|
|
@@ -8394,8 +8475,8 @@ async function fetchLatestVersion() {
|
|
|
8394
8475
|
}
|
|
8395
8476
|
async function writeCache(data) {
|
|
8396
8477
|
try {
|
|
8397
|
-
await
|
|
8398
|
-
await
|
|
8478
|
+
await fs21.mkdir(CACHE_DIR, { recursive: true });
|
|
8479
|
+
await fs21.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
|
|
8399
8480
|
} catch {
|
|
8400
8481
|
}
|
|
8401
8482
|
}
|
|
@@ -8436,14 +8517,14 @@ async function findGlobalInstall(pkg = PACKAGE_NAME, run = defaultRunner) {
|
|
|
8436
8517
|
pm: "yarn",
|
|
8437
8518
|
root: () => {
|
|
8438
8519
|
const dir = tryRun("yarn global dir");
|
|
8439
|
-
return dir ?
|
|
8520
|
+
return dir ? path37.join(dir, "node_modules") : null;
|
|
8440
8521
|
}
|
|
8441
8522
|
},
|
|
8442
|
-
{ pm: "bun", root: () =>
|
|
8523
|
+
{ pm: "bun", root: () => path37.join(os.homedir(), ".bun", "install", "global", "node_modules") }
|
|
8443
8524
|
];
|
|
8444
8525
|
for (const probe of probes) {
|
|
8445
8526
|
const root2 = probe.root();
|
|
8446
|
-
if (root2 && await pathExists(
|
|
8527
|
+
if (root2 && await pathExists(path37.join(root2, pkg))) return probe.pm;
|
|
8447
8528
|
}
|
|
8448
8529
|
return null;
|
|
8449
8530
|
}
|
|
@@ -8462,15 +8543,15 @@ function getGlobalUpdateCommand(pm, pkg, version) {
|
|
|
8462
8543
|
}
|
|
8463
8544
|
}
|
|
8464
8545
|
async function detectPackageManager(cwd) {
|
|
8465
|
-
if (await pathExists(
|
|
8466
|
-
if (await pathExists(
|
|
8467
|
-
if (await pathExists(
|
|
8546
|
+
if (await pathExists(path37.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
8547
|
+
if (await pathExists(path37.join(cwd, "bun.lockb"))) return "bun";
|
|
8548
|
+
if (await pathExists(path37.join(cwd, "yarn.lock"))) return "yarn";
|
|
8468
8549
|
return "npm";
|
|
8469
8550
|
}
|
|
8470
8551
|
async function detectWorkspaceRoot(cwd) {
|
|
8471
|
-
if (await pathExists(
|
|
8552
|
+
if (await pathExists(path37.join(cwd, "pnpm-workspace.yaml"))) return true;
|
|
8472
8553
|
try {
|
|
8473
|
-
const pkgPath =
|
|
8554
|
+
const pkgPath = path37.join(cwd, "package.json");
|
|
8474
8555
|
const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
|
|
8475
8556
|
const pkg = JSON.parse(raw);
|
|
8476
8557
|
return pkg.workspaces != null;
|
|
@@ -8495,7 +8576,7 @@ function getInstallCommand(pm, pkg, version, isDev, opts = {}) {
|
|
|
8495
8576
|
}
|
|
8496
8577
|
async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
|
|
8497
8578
|
try {
|
|
8498
|
-
const pkgPath =
|
|
8579
|
+
const pkgPath = path37.join(cwd, "package.json");
|
|
8499
8580
|
const raw = await (await import('fs/promises')).readFile(pkgPath, "utf-8");
|
|
8500
8581
|
const parsed = JSON.parse(raw);
|
|
8501
8582
|
if (parsed.devDependencies?.[pkg]) return "dev";
|
|
@@ -8507,11 +8588,11 @@ async function getLocalDependencyState(cwd, pkg = PACKAGE_NAME) {
|
|
|
8507
8588
|
async function confirmWorkspaceRoot(pm) {
|
|
8508
8589
|
if (!(process.stdin.isTTY && process.stdout.isTTY)) return false;
|
|
8509
8590
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8510
|
-
return new Promise((
|
|
8591
|
+
return new Promise((resolve20) => {
|
|
8511
8592
|
rl.question(chalk7.yellow(`Update the ${pm} workspace root with -w? [y/N]: `), (ans) => {
|
|
8512
8593
|
rl.close();
|
|
8513
8594
|
const t = ans.trim().toLowerCase();
|
|
8514
|
-
|
|
8595
|
+
resolve20(t === "y" || t === "yes");
|
|
8515
8596
|
});
|
|
8516
8597
|
});
|
|
8517
8598
|
}
|
|
@@ -8643,13 +8724,13 @@ function collectCandidates(artifact) {
|
|
|
8643
8724
|
return out2;
|
|
8644
8725
|
}
|
|
8645
8726
|
var defaultFixScanner = async (rootDir) => {
|
|
8646
|
-
const scratch =
|
|
8727
|
+
const scratch = path37.join(os.tmpdir(), `vg-fix-scan-${process.pid}.json`);
|
|
8647
8728
|
const scanOpts = { vibgrateVersion: VERSION, format: "json", out: scratch, quiet: true, concurrency: 8 };
|
|
8648
8729
|
const advanced = await loadAdvancedScanHook();
|
|
8649
8730
|
return runCoreScan(rootDir, scanOpts, advanced);
|
|
8650
8731
|
};
|
|
8651
8732
|
async function loadArtifact(rootDir, inFile, scan = defaultFixScanner) {
|
|
8652
|
-
const artifactPath =
|
|
8733
|
+
const artifactPath = path37.isAbsolute(inFile) ? inFile : path37.join(rootDir, inFile);
|
|
8653
8734
|
if (await pathExists(artifactPath)) {
|
|
8654
8735
|
const staleness = scanStaleness(rootDir, artifactPath);
|
|
8655
8736
|
if (!staleness.stale) {
|
|
@@ -8676,7 +8757,7 @@ async function repositoryIdentity(rootDir, override) {
|
|
|
8676
8757
|
}
|
|
8677
8758
|
}
|
|
8678
8759
|
var fixCommand = new Command("fix").description("Get ranked, risk-tiered upgrade plans from the hosted planner and optionally apply them (prompts before changing files; --yes applies non-interactively, --dry-run previews, --no-apply only prints). Requires login/DSN.").argument("[path]", "Path to analyse", ".").option("--in <file>", "Scan artifact to read", ".vibgrate/scan_result.json").option("--format <format>", "Output format (text|json|md)", "text").option("--dsn <dsn>", 'DSN token (or use VIBGRATE_DSN env / "vg login")').option("--region <region>", "Override data residency region (us, eu)").option("--repository-name <name>", "Override the repository name recorded for this plan").option("--plan <tier>", "Apply a specific plan non-interactively (safe|balanced|aggressive)").option("--yes", "Apply the recommended plan without prompting").option("--dry-run", "Show what would change without applying").option("--no-apply", "Only print the plans; never modify the project").option("--fail-on-vulns <severity>", "Exit non-zero if the recommended plan leaves an advisory at/above this severity unresolved (low|moderate|high|critical)").action(async (targetPath, opts) => {
|
|
8679
|
-
const rootDir =
|
|
8760
|
+
const rootDir = path37.resolve(targetPath);
|
|
8680
8761
|
if (!await pathExists(rootDir)) {
|
|
8681
8762
|
console.error(chalk7.red(`Path does not exist: ${rootDir}`));
|
|
8682
8763
|
process.exit(1);
|
|
@@ -8837,7 +8918,7 @@ function emit(report, format) {
|
|
|
8837
8918
|
}
|
|
8838
8919
|
}
|
|
8839
8920
|
function relProjectDir(rootDir, projectPath) {
|
|
8840
|
-
const rel =
|
|
8921
|
+
const rel = path37.isAbsolute(projectPath) ? path37.relative(rootDir, projectPath) : projectPath;
|
|
8841
8922
|
return rel === "" ? "." : rel;
|
|
8842
8923
|
}
|
|
8843
8924
|
async function buildTargetResolver(rootDir, artifact) {
|
|
@@ -8878,14 +8959,14 @@ function promptPlanSelection(response) {
|
|
|
8878
8959
|
const defaultIdx = plans.findIndex((p) => p.tier === response.recommended);
|
|
8879
8960
|
const def = defaultIdx >= 0 ? defaultIdx + 1 : 1;
|
|
8880
8961
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8881
|
-
return new Promise((
|
|
8962
|
+
return new Promise((resolve20) => {
|
|
8882
8963
|
rl.question(`Plan [1-${plans.length}, default ${def}, q to cancel]: `, (ans) => {
|
|
8883
8964
|
rl.close();
|
|
8884
8965
|
const t = ans.trim().toLowerCase();
|
|
8885
|
-
if (t === "q" || t === "quit") return
|
|
8966
|
+
if (t === "q" || t === "quit") return resolve20(null);
|
|
8886
8967
|
const n = t === "" ? def : Number.parseInt(t, 10);
|
|
8887
|
-
if (!Number.isInteger(n) || n < 1 || n > plans.length) return
|
|
8888
|
-
|
|
8968
|
+
if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve20(null);
|
|
8969
|
+
resolve20(plans[n - 1].tier);
|
|
8889
8970
|
});
|
|
8890
8971
|
});
|
|
8891
8972
|
}
|
|
@@ -9672,7 +9753,7 @@ function formatMarkdown(artifact) {
|
|
|
9672
9753
|
|
|
9673
9754
|
// src/reporting/commands/report.ts
|
|
9674
9755
|
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) => {
|
|
9675
|
-
const artifactPath =
|
|
9756
|
+
const artifactPath = path37.resolve(opts.in);
|
|
9676
9757
|
if (!await pathExists(artifactPath)) {
|
|
9677
9758
|
console.error(chalk7.red(`Artifact not found: ${artifactPath}`));
|
|
9678
9759
|
console.error(chalk7.dim('Run "vibgrate scan" first to generate a scan artifact.'));
|
|
@@ -9718,10 +9799,10 @@ function openUrl(url) {
|
|
|
9718
9799
|
}
|
|
9719
9800
|
|
|
9720
9801
|
// src/reporting/commands/login.ts
|
|
9721
|
-
var delay = (ms) => new Promise((
|
|
9802
|
+
var delay = (ms) => new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
9722
9803
|
function isInside(dir, file) {
|
|
9723
|
-
const rel =
|
|
9724
|
-
return !!rel && !rel.startsWith("..") && !
|
|
9804
|
+
const rel = path37.relative(dir, file);
|
|
9805
|
+
return !!rel && !rel.startsWith("..") && !path37.isAbsolute(rel);
|
|
9725
9806
|
}
|
|
9726
9807
|
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(
|
|
9727
9808
|
"--local",
|
|
@@ -9976,7 +10057,7 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
|
|
|
9976
10057
|
try {
|
|
9977
10058
|
const statements = [];
|
|
9978
10059
|
if (opts.from) {
|
|
9979
|
-
const fromPath =
|
|
10060
|
+
const fromPath = path37.resolve(opts.from);
|
|
9980
10061
|
if (!await pathExists(fromPath)) {
|
|
9981
10062
|
process.stderr.write(chalk7.red(`Statements file not found: ${fromPath}
|
|
9982
10063
|
`));
|
|
@@ -9994,9 +10075,9 @@ var vexCommand = new Command("vex").description("Generate an OpenVEX document (e
|
|
|
9994
10075
|
});
|
|
9995
10076
|
const json2 = JSON.stringify(doc, null, 2);
|
|
9996
10077
|
if (opts.out) {
|
|
9997
|
-
await writeTextFile(
|
|
10078
|
+
await writeTextFile(path37.resolve(opts.out), json2 + "\n");
|
|
9998
10079
|
process.stderr.write(
|
|
9999
|
-
chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${
|
|
10080
|
+
chalk7.green("\u2714") + ` Wrote OpenVEX document (${doc.statements.length} statement(s)) to ${path37.resolve(opts.out)}
|
|
10000
10081
|
`
|
|
10001
10082
|
);
|
|
10002
10083
|
} else {
|
|
@@ -10179,7 +10260,7 @@ function formatDeltaText(base, current) {
|
|
|
10179
10260
|
return lines.join("\n");
|
|
10180
10261
|
}
|
|
10181
10262
|
async function readArtifactOrExit(filePath) {
|
|
10182
|
-
const absolutePath =
|
|
10263
|
+
const absolutePath = path37.resolve(filePath);
|
|
10183
10264
|
if (!await pathExists(absolutePath)) {
|
|
10184
10265
|
console.error(chalk7.red(`Artifact not found: ${absolutePath}`));
|
|
10185
10266
|
process.exit(1);
|
|
@@ -10196,7 +10277,7 @@ var exportCommand = new Command("export").description("Export scan artifact as S
|
|
|
10196
10277
|
const sbom = format === "cyclonedx" ? toCycloneDx(artifact) : toSpdx(artifact);
|
|
10197
10278
|
const body = JSON.stringify(sbom, null, 2);
|
|
10198
10279
|
if (opts.out) {
|
|
10199
|
-
await writeTextFile(
|
|
10280
|
+
await writeTextFile(path37.resolve(opts.out), body);
|
|
10200
10281
|
console.log(chalk7.green("\u2714") + ` SBOM written to ${opts.out}`);
|
|
10201
10282
|
} else {
|
|
10202
10283
|
console.log(body);
|
|
@@ -10207,7 +10288,7 @@ var deltaCommand = new Command("delta").description("Show SBOM delta between two
|
|
|
10207
10288
|
const current = await readArtifactOrExit(opts.to);
|
|
10208
10289
|
const report = formatDeltaText(base, current);
|
|
10209
10290
|
if (opts.out) {
|
|
10210
|
-
await writeTextFile(
|
|
10291
|
+
await writeTextFile(path37.resolve(opts.out), report);
|
|
10211
10292
|
console.log(chalk7.green("\u2714") + ` SBOM delta report written to ${opts.out}`);
|
|
10212
10293
|
} else {
|
|
10213
10294
|
console.log(report);
|
|
@@ -10338,20 +10419,20 @@ function resolveRegime(id) {
|
|
|
10338
10419
|
return regime;
|
|
10339
10420
|
}
|
|
10340
10421
|
function evidenceDir(root2) {
|
|
10341
|
-
return
|
|
10422
|
+
return path37.join(root2, ".vibgrate", "evidence");
|
|
10342
10423
|
}
|
|
10343
10424
|
function orgPath(root2) {
|
|
10344
|
-
return
|
|
10425
|
+
return path37.join(evidenceDir(root2), "org.json");
|
|
10345
10426
|
}
|
|
10346
10427
|
function productsPath(root2) {
|
|
10347
|
-
return
|
|
10428
|
+
return path37.join(evidenceDir(root2), "products.json");
|
|
10348
10429
|
}
|
|
10349
10430
|
function releasesDir(root2) {
|
|
10350
|
-
return
|
|
10431
|
+
return path37.join(evidenceDir(root2), "releases");
|
|
10351
10432
|
}
|
|
10352
10433
|
function releasePath(root2, productId, version) {
|
|
10353
10434
|
const safe = `${productId}@${version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
|
|
10354
|
-
return
|
|
10435
|
+
return path37.join(releasesDir(root2), `${safe}.json`);
|
|
10355
10436
|
}
|
|
10356
10437
|
var DEFAULT_ORG = {
|
|
10357
10438
|
responsiblePersons: [],
|
|
@@ -10382,7 +10463,7 @@ async function freezeRelease(root2, release) {
|
|
|
10382
10463
|
const p = releasePath(root2, release.productId, release.version);
|
|
10383
10464
|
if (await pathExists(p)) {
|
|
10384
10465
|
throw new CliError(
|
|
10385
|
-
`release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${
|
|
10466
|
+
`release ${release.productId}@${release.version} is already frozen and manifests are immutable \u2014 delete ${path37.relative(root2, p)} only if it was frozen in error`,
|
|
10386
10467
|
ExitCode.USAGE_ERROR
|
|
10387
10468
|
);
|
|
10388
10469
|
}
|
|
@@ -10396,7 +10477,7 @@ async function loadReleases(root2, productId) {
|
|
|
10396
10477
|
const files = (await readdir(dir)).filter((f) => f.endsWith(".json")).sort();
|
|
10397
10478
|
const releases = [];
|
|
10398
10479
|
for (const f of files) {
|
|
10399
|
-
const rel = await readJsonFile(
|
|
10480
|
+
const rel = await readJsonFile(path37.join(dir, f));
|
|
10400
10481
|
if (!productId || rel.productId === productId) releases.push(rel);
|
|
10401
10482
|
}
|
|
10402
10483
|
return releases;
|
|
@@ -11091,12 +11172,12 @@ function verifyEvidenceEnvelope(env, opts = {}) {
|
|
|
11091
11172
|
var DEFAULT_KEY = "attest-key.pem";
|
|
11092
11173
|
function resolveSigningKey(root2, explicit) {
|
|
11093
11174
|
const chosen = process.env.VG_ATTEST_KEY;
|
|
11094
|
-
const keyPath = chosen ?
|
|
11175
|
+
const keyPath = chosen ? path37.resolve(chosen) : path37.join(root2, ".vibgrate", DEFAULT_KEY);
|
|
11095
11176
|
let minted = false;
|
|
11096
11177
|
if (!fs8.existsSync(keyPath)) {
|
|
11097
11178
|
if (chosen) throw new CliError(`signing key not found: ${chosen}`, ExitCode.USAGE_ERROR);
|
|
11098
11179
|
const kp = generateKeypair();
|
|
11099
|
-
fs8.mkdirSync(
|
|
11180
|
+
fs8.mkdirSync(path37.dirname(keyPath), { recursive: true });
|
|
11100
11181
|
fs8.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
|
|
11101
11182
|
fs8.writeFileSync(`${keyPath}.pub`, kp.publicPem);
|
|
11102
11183
|
minted = true;
|
|
@@ -11114,16 +11195,16 @@ function resolveSigningKey(root2, explicit) {
|
|
|
11114
11195
|
}
|
|
11115
11196
|
function writeBundle(input) {
|
|
11116
11197
|
const dir = input.outDir;
|
|
11117
|
-
fs8.mkdirSync(
|
|
11118
|
-
const write = (rel, data) => fs8.writeFileSync(
|
|
11198
|
+
fs8.mkdirSync(path37.join(dir, "inputs", "releases"), { recursive: true });
|
|
11199
|
+
const write = (rel, data) => fs8.writeFileSync(path37.join(dir, rel), `${JSON.stringify(data, null, 2)}
|
|
11119
11200
|
`);
|
|
11120
11201
|
write("result.json", input.result);
|
|
11121
|
-
write(
|
|
11202
|
+
write(path37.join("inputs", "advisory.json"), input.advisory);
|
|
11122
11203
|
for (const rel of input.releases) {
|
|
11123
11204
|
const safe = `${rel.productId}@${rel.version}`.replace(/[^A-Za-z0-9._@-]/g, "_");
|
|
11124
|
-
write(
|
|
11205
|
+
write(path37.join("inputs", "releases", `${safe}.json`), rel);
|
|
11125
11206
|
}
|
|
11126
|
-
write(
|
|
11207
|
+
write(path37.join("inputs", "datapack.lock"), { dataPackVersion: input.result.meta.dataPackVersion, kernelVersion: input.result.meta.kernelVersion });
|
|
11127
11208
|
write("provenance.json", {
|
|
11128
11209
|
method: "deterministic",
|
|
11129
11210
|
modelDrafted: [],
|
|
@@ -11139,13 +11220,13 @@ function writeBundle(input) {
|
|
|
11139
11220
|
disclaimer: input.regime.disclaimer
|
|
11140
11221
|
});
|
|
11141
11222
|
if (input.envelope) {
|
|
11142
|
-
fs8.writeFileSync(
|
|
11223
|
+
fs8.writeFileSync(path37.join(dir, "evidence.intoto.jsonl"), `${JSON.stringify(input.envelope)}
|
|
11143
11224
|
`);
|
|
11144
11225
|
}
|
|
11145
11226
|
if (input.timestampToken) {
|
|
11146
|
-
fs8.writeFileSync(
|
|
11227
|
+
fs8.writeFileSync(path37.join(dir, "timestamp.tsr"), input.timestampToken);
|
|
11147
11228
|
}
|
|
11148
|
-
fs8.writeFileSync(
|
|
11229
|
+
fs8.writeFileSync(path37.join(dir, "VERIFY.md"), verifyDoc(input));
|
|
11149
11230
|
return dir;
|
|
11150
11231
|
}
|
|
11151
11232
|
function verifyDoc(input) {
|
|
@@ -11206,13 +11287,13 @@ function undeterminedFields(result, regime) {
|
|
|
11206
11287
|
return gaps.filter((g) => regime.submission.requires.some((r) => g.startsWith(r)) || g.startsWith("exposure") || g.startsWith("member"));
|
|
11207
11288
|
}
|
|
11208
11289
|
async function recordDrill(root2, record) {
|
|
11209
|
-
const dir =
|
|
11210
|
-
const p =
|
|
11290
|
+
const dir = path37.join(evidenceDir(root2), "drills");
|
|
11291
|
+
const p = path37.join(dir, `${record.drillId}.json`);
|
|
11211
11292
|
await writeJsonFile(p, record);
|
|
11212
11293
|
return p;
|
|
11213
11294
|
}
|
|
11214
11295
|
async function hasRecentDrill(root2, asOf) {
|
|
11215
|
-
const dir =
|
|
11296
|
+
const dir = path37.join(evidenceDir(root2), "drills");
|
|
11216
11297
|
if (!await pathExists(dir)) return void 0;
|
|
11217
11298
|
const { readdir } = await import('fs/promises');
|
|
11218
11299
|
const { readJsonFile: readJsonFile2 } = await import('./fs-O5IQYXHO.js');
|
|
@@ -11220,7 +11301,7 @@ async function hasRecentDrill(root2, asOf) {
|
|
|
11220
11301
|
if (files.length === 0) return void 0;
|
|
11221
11302
|
const cutoff = new Date(new Date(asOf).getTime() - 90 * 24 * 3600 * 1e3).toISOString();
|
|
11222
11303
|
for (const f of files) {
|
|
11223
|
-
const rec = await readJsonFile2(
|
|
11304
|
+
const rec = await readJsonFile2(path37.join(dir, f));
|
|
11224
11305
|
if (rec.ranAt >= cutoff) return true;
|
|
11225
11306
|
}
|
|
11226
11307
|
return false;
|
|
@@ -11300,7 +11381,7 @@ function formatRegimeList() {
|
|
|
11300
11381
|
|
|
11301
11382
|
// src/reporting/commands/evidence/index.ts
|
|
11302
11383
|
function root(opts) {
|
|
11303
|
-
return
|
|
11384
|
+
return path37.resolve(opts.cwd ?? process.cwd());
|
|
11304
11385
|
}
|
|
11305
11386
|
function slug(name) {
|
|
11306
11387
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "product";
|
|
@@ -11388,7 +11469,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
|
|
|
11388
11469
|
const release = await buildRelease({
|
|
11389
11470
|
productId: product.id,
|
|
11390
11471
|
version,
|
|
11391
|
-
from:
|
|
11472
|
+
from: path37.resolve(rootDir, opts.from),
|
|
11392
11473
|
shipDate: opts.shipDate,
|
|
11393
11474
|
buildId: opts.buildId,
|
|
11394
11475
|
artefactDigest: opts.digest,
|
|
@@ -11396,7 +11477,7 @@ var releaseCmd = new Command("release").description("Freeze a shipped release in
|
|
|
11396
11477
|
frozenAt: nowIso()
|
|
11397
11478
|
});
|
|
11398
11479
|
const p = await freezeRelease(rootDir, release);
|
|
11399
|
-
console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${
|
|
11480
|
+
console.log(chalk7.green("\u2714") + ` froze ${chalk7.bold(`${product.id}@${version}`)} \u2014 ${release.components.length} components, immutable at ${path37.relative(rootDir, p)}`);
|
|
11400
11481
|
});
|
|
11401
11482
|
async function runExposure(rootDir, vuln, opts) {
|
|
11402
11483
|
const org = await loadOrg(rootDir);
|
|
@@ -11448,7 +11529,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
|
|
|
11448
11529
|
console.log("\n" + buildPack(result, regime, org, stage));
|
|
11449
11530
|
}
|
|
11450
11531
|
if (opts.bundle) {
|
|
11451
|
-
const dir =
|
|
11532
|
+
const dir = path37.resolve(rootDir, opts.bundle, `evidence-${result.meta.evidenceId}`);
|
|
11452
11533
|
let envelope;
|
|
11453
11534
|
if (opts.sign !== false) {
|
|
11454
11535
|
const { key: key2, minted } = resolveSigningKey(rootDir);
|
|
@@ -11456,7 +11537,7 @@ var exposureCmd = new Command("exposure").description("Which shipped products co
|
|
|
11456
11537
|
envelope = signEvidenceStatement(buildEvidenceStatement(result, VERSION), key2);
|
|
11457
11538
|
}
|
|
11458
11539
|
writeBundle({ outDir: dir, result, advisory, releases, regime, envelope, timestampToken, cliVersion: VERSION });
|
|
11459
|
-
console.error(chalk7.green("\u2714") + ` evidence bundle written to ${
|
|
11540
|
+
console.error(chalk7.green("\u2714") + ` evidence bundle written to ${path37.relative(rootDir, dir)}${envelope ? " (signed)" : " (unsigned)"}${timestampToken ? " \xB7 RFC 3161" : ""}`);
|
|
11460
11541
|
}
|
|
11461
11542
|
process.exitCode = exposureExit(result.overallStatus);
|
|
11462
11543
|
});
|
|
@@ -11488,7 +11569,7 @@ var packCmd = new Command("pack").description("Build the submission pack a human
|
|
|
11488
11569
|
const stage = opts.stage ?? regime.clocks[0]?.stage ?? "early-warning";
|
|
11489
11570
|
const md = buildPack(result, regime, org, stage);
|
|
11490
11571
|
if (opts.out) {
|
|
11491
|
-
fs8.writeFileSync(
|
|
11572
|
+
fs8.writeFileSync(path37.resolve(rootDir, opts.out), md);
|
|
11492
11573
|
console.error(chalk7.green("\u2714") + ` pack written to ${opts.out}`);
|
|
11493
11574
|
} else {
|
|
11494
11575
|
console.log(md);
|
|
@@ -11530,18 +11611,18 @@ var drillCmd = new Command("drill").description("Timed dry-run of the determinat
|
|
|
11530
11611
|
}
|
|
11531
11612
|
});
|
|
11532
11613
|
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) => {
|
|
11533
|
-
const abs =
|
|
11534
|
-
const envPath = fs8.statSync(abs).isDirectory() ?
|
|
11614
|
+
const abs = path37.resolve(bundlePath);
|
|
11615
|
+
const envPath = fs8.statSync(abs).isDirectory() ? path37.join(abs, "evidence.intoto.jsonl") : abs;
|
|
11535
11616
|
if (!fs8.existsSync(envPath)) throw new CliError(`no evidence.intoto.jsonl at ${bundlePath}`, ExitCode.NOT_FOUND);
|
|
11536
11617
|
const envelope = JSON.parse(fs8.readFileSync(envPath, "utf8").trim().split("\n")[0]);
|
|
11537
|
-
const resultPath =
|
|
11618
|
+
const resultPath = path37.join(path37.dirname(envPath), "result.json");
|
|
11538
11619
|
const result = fs8.existsSync(resultPath) ? JSON.parse(fs8.readFileSync(resultPath, "utf8")) : void 0;
|
|
11539
|
-
const publicKeyPem = opts.pub ? fs8.readFileSync(
|
|
11620
|
+
const publicKeyPem = opts.pub ? fs8.readFileSync(path37.resolve(opts.pub), "utf8") : void 0;
|
|
11540
11621
|
const v = verifyEvidenceEnvelope(envelope, { publicKeyPem, result });
|
|
11541
11622
|
const color = v.status === "verified" ? chalk7.green : v.status === "failed" ? chalk7.red : chalk7.yellow;
|
|
11542
11623
|
console.log(" " + color(v.status.toUpperCase()) + ` ${v.reason}`);
|
|
11543
11624
|
if (v.evidenceId) console.log(" " + chalk7.dim(`evidence ${v.evidenceId} \xB7 regime ${v.regime} \xB7 advisory ${v.advisoryId} \xB7 ${v.overallStatus}`));
|
|
11544
|
-
const tsrPath =
|
|
11625
|
+
const tsrPath = path37.join(path37.dirname(envPath), "timestamp.tsr");
|
|
11545
11626
|
if (fs8.existsSync(tsrPath) && result) {
|
|
11546
11627
|
const t = verifyTimestamp(fs8.readFileSync(tsrPath), exposureSubjectDigest(result));
|
|
11547
11628
|
const tcolor = t.imprintMatches ? chalk7.green : chalk7.red;
|
|
@@ -11610,12 +11691,12 @@ var exportCmd = new Command("export").description("Air-gap bundle of all evidenc
|
|
|
11610
11691
|
const releases = [];
|
|
11611
11692
|
for (const list of releasesByProduct.values()) releases.push(...list);
|
|
11612
11693
|
const report = computeReadiness({ regime, org, products, releasesByProduct, recentDrill: await hasRecentDrill(rootDir, today()) });
|
|
11613
|
-
const dir =
|
|
11614
|
-
await writeJsonFile(
|
|
11615
|
-
await writeJsonFile(
|
|
11616
|
-
for (const r of releases) await writeJsonFile(
|
|
11617
|
-
await writeJsonFile(
|
|
11618
|
-
console.error(chalk7.green("\u2714") + ` exported evidence state to ${
|
|
11694
|
+
const dir = path37.resolve(rootDir, opts.out);
|
|
11695
|
+
await writeJsonFile(path37.join(dir, "org.json"), org);
|
|
11696
|
+
await writeJsonFile(path37.join(dir, "products.json"), products);
|
|
11697
|
+
for (const r of releases) await writeJsonFile(path37.join(dir, "releases", `${r.productId}@${r.version}.json`.replace(/[^A-Za-z0-9._@-]/g, "_")), r);
|
|
11698
|
+
await writeJsonFile(path37.join(dir, "readiness.json"), report);
|
|
11699
|
+
console.error(chalk7.green("\u2714") + ` exported evidence state to ${path37.relative(rootDir, dir)} (${products.length} products, ${releases.length} frozen releases)`);
|
|
11619
11700
|
});
|
|
11620
11701
|
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) => {
|
|
11621
11702
|
const rootDir = root(opts);
|
|
@@ -11641,8 +11722,8 @@ var pushCmd = new Command("push").description("Push the product registry (and an
|
|
|
11641
11722
|
}));
|
|
11642
11723
|
let exposure;
|
|
11643
11724
|
if (opts.result) {
|
|
11644
|
-
const raw =
|
|
11645
|
-
const resultPath = fs8.existsSync(raw) && fs8.statSync(raw).isDirectory() ?
|
|
11725
|
+
const raw = path37.resolve(rootDir, opts.result);
|
|
11726
|
+
const resultPath = fs8.existsSync(raw) && fs8.statSync(raw).isDirectory() ? path37.join(raw, "result.json") : raw;
|
|
11646
11727
|
if (!fs8.existsSync(resultPath)) throw new CliError(`no result.json at ${opts.result}`, ExitCode.NOT_FOUND);
|
|
11647
11728
|
exposure = JSON.parse(fs8.readFileSync(resultPath, "utf8"));
|
|
11648
11729
|
}
|
|
@@ -11708,6 +11789,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11708
11789
|
"install",
|
|
11709
11790
|
"uninstall",
|
|
11710
11791
|
"share",
|
|
11792
|
+
"watch",
|
|
11711
11793
|
"help",
|
|
11712
11794
|
// Drift-reporting verbs (merged from the Vibgrate CLI).
|
|
11713
11795
|
"init",
|
|
@@ -11748,6 +11830,7 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
|
|
|
11748
11830
|
registerLsp(program);
|
|
11749
11831
|
registerInstall(program);
|
|
11750
11832
|
registerShare(program);
|
|
11833
|
+
registerWatch(program);
|
|
11751
11834
|
registerTests(program);
|
|
11752
11835
|
registerFacts(program);
|
|
11753
11836
|
registerGuide(program);
|
|
@@ -11832,7 +11915,7 @@ function dispatch(argv, cwd) {
|
|
|
11832
11915
|
}
|
|
11833
11916
|
const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
|
|
11834
11917
|
if (looksLikeQuestion) return ["ask", ...args];
|
|
11835
|
-
if (fs8.existsSync(
|
|
11918
|
+
if (fs8.existsSync(path37.resolve(cwd, first))) {
|
|
11836
11919
|
return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
|
|
11837
11920
|
}
|
|
11838
11921
|
const moved = MOVED_COMMANDS[first];
|
|
@@ -11877,9 +11960,9 @@ async function main(argv = process.argv) {
|
|
|
11877
11960
|
}
|
|
11878
11961
|
function readCwd(raw) {
|
|
11879
11962
|
const i = raw.findIndex((a) => a === "-C" || a === "--cwd");
|
|
11880
|
-
if (i >= 0 && raw[i + 1]) return
|
|
11963
|
+
if (i >= 0 && raw[i + 1]) return path37.resolve(raw[i + 1]);
|
|
11881
11964
|
const eq = raw.find((a) => a.startsWith("--cwd="));
|
|
11882
|
-
if (eq) return
|
|
11965
|
+
if (eq) return path37.resolve(eq.slice("--cwd=".length));
|
|
11883
11966
|
return process.cwd();
|
|
11884
11967
|
}
|
|
11885
11968
|
function handleError(err) {
|