@vibgrate/cli 2026.703.7 → 2026.704.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { resolveDsn, resolveIngestHost, dashHostForIngestHost, resolveCliInvocation, availableRegionIds, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, inventory, uploadScanArtifact, dsnCommand, pushCommand, ExitCode, CliError, NPX_INVOCATION, verifyDeterminism, refreshIfStale, driftCount, embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, countPending, resolveOne, GraphIndex, shortestPath, renderReport, impactOf, testsToRun, detectRunner, defaultGraphPath, serveStdio, ASSISTANTS, usageError, loadGraph, detectServeLaunch, installAssistant, uninstallAssistant, buildGraph, serializeGraph, coveringTests, FREE_PACK, readScanArtifact, enrichOnline, ECOSYSTEMS, discoverModels, readSavings, exportGraph, catalogPath, libDir, stableStringify, writeArtifacts, writeSnapshot, UsageError, cacheDir, probeFreshness, discover, vibgrateDir, modelCacheInfo, clearModelCache, GraphSource, createServer, assistantById, loadCatalog, driftFor, addLibrary, parseDsn as parseDsn$1, publishPrivateLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface, assessDocQuality, symbolsFromApi, fetchHostedDocs, selectForBudget, formatForExt, renderHtml, isModelReady } from './chunk-WGXDYBAN.js';
2
+ import { resolveDsn, resolveIngestHost, dashHostForIngestHost, resolveCliInvocation, availableRegionIds, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, inventory, uploadScanArtifact, dsnCommand, pushCommand, ExitCode, CliError, NPX_INVOCATION, verifyDeterminism, refreshIfStale, driftCount, embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, countPending, resolveOne, GraphIndex, shortestPath, renderReport, impactOf, testsToRun, detectRunner, defaultGraphPath, serveStdio, ASSISTANTS, usageError, loadGraph, detectServeLaunch, installAssistant, uninstallAssistant, coveringTests, FREE_PACK, readScanArtifact, enrichOnline, ECOSYSTEMS, discoverModels, readSavings, exportGraph, catalogPath, libDir, stableStringify, buildGraph, writeArtifacts, writeSnapshot, UsageError, ResourceLimitError, cacheDir, probeFreshness, discover, vibgrateDir, modelCacheInfo, clearModelCache, GraphSource, createServer, assistantById, serializeGraph, resolveLimits, loadCatalog, driftFor, addLibrary, parseDsn as parseDsn$1, publishPrivateLibrary, resolveLib, libId, resolveVersion, readDoc, localPackageDocs, localApiSurface, assessDocQuality, symbolsFromApi, fetchHostedDocs, selectForBudget, formatForExt, renderHtml, isModelReady } from './chunk-YODVLV37.js';
3
3
  import { resolvedGrammarFiles, grammarSetVersion } from './chunk-X5YT263H.js';
4
- import { loadAdvancedScanHook, baselineCommand } from './chunk-ZNVLRKWK.js';
5
- import { ensureDir, pathExists, writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, readJsonFile, writeTextFile, prepareCompressedUpload, titleBox, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, brandProgressBar } from './chunk-QWS7M7DG.js';
4
+ import { loadAdvancedScanHook, baselineCommand } from './chunk-W4ANUENJ.js';
5
+ import { ensureDir, pathExists, writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, readJsonFile, writeTextFile, prepareCompressedUpload, titleBox, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, brandProgressBar } from './chunk-RJHYTD62.js';
6
6
  import './chunk-RXP66R2E.js';
7
- import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-UPPWLMVD.js';
7
+ import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-GI6W53LM.js';
8
8
  import * as fs4 from 'fs';
9
9
  import fs4__default, { realpathSync } from 'fs';
10
10
  import * as path9 from 'path';
@@ -156,6 +156,7 @@ async function runBuild(paths, opts, global) {
156
156
  } catch (err) {
157
157
  bar?.done();
158
158
  if (err instanceof UsageError) throw usageError(err.message);
159
+ if (err instanceof ResourceLimitError) throw new CliError(err.message, ExitCode.ERROR);
159
160
  throw err;
160
161
  }
161
162
  bar?.done();
@@ -192,7 +193,8 @@ async function runBuild(paths, opts, global) {
192
193
  scip: result.scip,
193
194
  artifacts: written,
194
195
  corpusHash: result.graph.provenance.corpusHash,
195
- timingMs: result.timing.totalMs
196
+ timingMs: result.timing.totalMs,
197
+ warnings: result.warnings
196
198
  });
197
199
  return;
198
200
  }
@@ -1059,52 +1061,103 @@ function escapeRe(s) {
1059
1061
  }
1060
1062
  var PIN = "2020-01-01T00:00:00.000Z";
1061
1063
  function registerBenchmark(program) {
1062
- const cmd = program.command("benchmark").description("reproducible build + token-reduction benchmark (honest estimates)").option("--budget <n>", "token budget for vg answers", "2000").action(async function(opts) {
1064
+ const cmd = program.command("benchmark").description("reproducible build + memory + token-reduction benchmark (honest estimates)").option("--budget <n>", "token budget for vg answers", "2000").action(async function(opts) {
1063
1065
  const global = readGlobal(this);
1064
1066
  const root = rootOf(global);
1065
1067
  const budget = Number(opts.budget) || 2e3;
1066
- const t0 = now();
1067
- const cold = await buildGraph({ root, generatedAt: PIN, noCache: true });
1068
- const coldMs = now() - t0;
1069
- const t1 = now();
1070
- const warm = await buildGraph({ root, generatedAt: PIN });
1071
- const warmMs = now() - t1;
1072
- const a = serializeGraph(cold.graph);
1073
- const b = serializeGraph((await buildGraph({ root, generatedAt: PIN, noCache: true })).graph);
1074
- const deterministic = a === b;
1075
- const questions = deriveQuestions(cold.graph);
1076
- const fileSizes = fileSizeIndex(root);
1077
- const perQuestion = questions.map((q) => {
1078
- const vgTokens = queryGraph(cold.graph, q, { budget }).tokensEstimate;
1079
- const baseTokens = grepBaselineTokens(q, fileSizes);
1080
- return { question: q, vgTokens, baselineTokens: baseTokens, ratio: baseTokens > 0 ? round(baseTokens / Math.max(vgTokens, 1)) : 1 };
1081
- });
1082
- const totalVg = perQuestion.reduce((s, x) => s + x.vgTokens, 0);
1083
- const totalBase = perQuestion.reduce((s, x) => s + x.baselineTokens, 0);
1084
- const aggregateRatio = totalVg > 0 ? round(totalBase / totalVg) : 0;
1085
- const result = {
1086
- repo: { files: cold.totalFiles, nodes: cold.graph.meta.counts.nodes, edges: cold.graph.meta.counts.edges },
1087
- build: { coldMs: round(coldMs), incrementalMs: round(warmMs), reusedOnWarm: warm.reused },
1088
- determinism: { byteIdentical: deterministic },
1089
- tokenReduction: { questions: perQuestion, aggregateRatio, note: "estimates (~4 chars/token); scales with repo size" }
1090
- };
1068
+ const result = await runBenchmarkSuite(root, budget);
1091
1069
  if (global.json) {
1092
1070
  json(result);
1093
1071
  return;
1094
1072
  }
1095
- info(`${c.cyan("vg benchmark")} \xB7 ${result.repo.files} files \xB7 ${result.repo.nodes} nodes`);
1096
- info(` build cold ${result.build.coldMs.toFixed(0)}ms \xB7 incremental ${result.build.incrementalMs.toFixed(0)}ms (reused ${warm.reused})`);
1097
- info(` determinism ${deterministic ? c.green("byte-identical \u2713") : c.red("NON-DETERMINISTIC \u2717")}`);
1098
- if (perQuestion.length) {
1073
+ const { repo, build, throughput, memory, determinism, tokenReduction } = result;
1074
+ info(`${c.cyan("vg benchmark")} \xB7 ${repo.files} files \xB7 ${repo.nodes} nodes`);
1075
+ info(` build cold ${build.coldMs.toFixed(0)}ms \xB7 incremental ${build.incrementalMs.toFixed(0)}ms (reused ${build.reusedOnWarm})`);
1076
+ info(` speed ${throughput.filesPerSec.toFixed(0)} files/s \xB7 ${throughput.mbPerSec.toFixed(1)} MB/s (cold, ${mb2(throughput.corpusBytes).toFixed(1)} MB corpus)`);
1077
+ info(
1078
+ ` memory peak rss ${memory.peakRssMb.toFixed(0)} MB (baseline ${memory.baselineRssMb.toFixed(0)} MB) \xB7 peak heap ${memory.peakHeapMb.toFixed(0)} MB \xB7 graph retains ~${memory.retainedHeapMb.toFixed(0)} MB ${c.dim("(approximate)")}`
1079
+ );
1080
+ info(` graph ${mb2(memory.graphJsonBytes).toFixed(1)} MB serialized \xB7 ${memory.bytesPerNode.toFixed(0)} B/node`);
1081
+ info(` determinism ${determinism.byteIdentical ? c.green("byte-identical \u2713") : c.red("NON-DETERMINISTIC \u2717")}`);
1082
+ if (tokenReduction.questions.length) {
1099
1083
  info(` token reduction vs grep/read baseline (${c.dim("estimates")}):`);
1100
- for (const q of perQuestion) {
1084
+ for (const q of tokenReduction.questions) {
1101
1085
  info(` ${pad2(`${q.ratio.toFixed(1)}\xD7`, 6)} ${c.dim(`vg ${q.vgTokens} vs ~${q.baselineTokens}`)} "${q.question}"`);
1102
1086
  }
1103
- info(` ${c.bold(`aggregate \u2248 ${aggregateRatio.toFixed(1)}\xD7 fewer tokens`)} ${c.dim("(honest estimate, scales with repo size)")}`);
1087
+ info(` ${c.bold(`aggregate \u2248 ${tokenReduction.aggregateRatio.toFixed(1)}\xD7 fewer tokens`)} ${c.dim("(honest estimate, scales with repo size)")}`);
1104
1088
  }
1105
1089
  });
1106
1090
  applyGlobalOptions(cmd);
1107
1091
  }
1092
+ async function runBenchmarkSuite(root, budget) {
1093
+ const baseline = process.memoryUsage();
1094
+ const sampler = startMemorySampler();
1095
+ const t0 = now();
1096
+ const cold = await buildGraph({ root, generatedAt: PIN, noCache: true });
1097
+ const coldMs = now() - t0;
1098
+ const t1 = now();
1099
+ const warm = await buildGraph({ root, generatedAt: PIN });
1100
+ const warmMs = now() - t1;
1101
+ const a = serializeGraph(cold.graph);
1102
+ const b = serializeGraph((await buildGraph({ root, generatedAt: PIN, noCache: true })).graph);
1103
+ const peak = sampler.stop();
1104
+ const deterministic = a === b;
1105
+ const after = process.memoryUsage();
1106
+ const corpusBytes = cold.fileStats.reduce((s, f) => s + f.size, 0);
1107
+ const graphJsonBytes = Buffer.byteLength(a, "utf8");
1108
+ const nodes = cold.graph.meta.counts.nodes;
1109
+ const questions = deriveQuestions(cold.graph);
1110
+ const fileSizes = fileSizeIndex(root);
1111
+ const perQuestion = questions.map((q) => {
1112
+ const vgTokens = queryGraph(cold.graph, q, { budget }).tokensEstimate;
1113
+ const baseTokens = grepBaselineTokens(q, fileSizes);
1114
+ return { question: q, vgTokens, baselineTokens: baseTokens, ratio: baseTokens > 0 ? round(baseTokens / Math.max(vgTokens, 1)) : 1 };
1115
+ });
1116
+ const totalVg = perQuestion.reduce((s, x) => s + x.vgTokens, 0);
1117
+ const totalBase = perQuestion.reduce((s, x) => s + x.baselineTokens, 0);
1118
+ const aggregateRatio = totalVg > 0 ? round(totalBase / totalVg) : 0;
1119
+ return {
1120
+ repo: { files: cold.totalFiles, nodes, edges: cold.graph.meta.counts.edges },
1121
+ build: { coldMs: round(coldMs), incrementalMs: round(warmMs), reusedOnWarm: warm.reused },
1122
+ throughput: {
1123
+ corpusBytes,
1124
+ filesPerSec: coldMs > 0 ? round(cold.totalFiles / coldMs * 1e3) : 0,
1125
+ // 6-decimal precision: a small corpus at 3 decimals would round to 0.
1126
+ mbPerSec: coldMs > 0 ? round6(mb2(corpusBytes) / coldMs * 1e3) : 0
1127
+ },
1128
+ memory: {
1129
+ baselineRssMb: round(mb2(baseline.rss)),
1130
+ peakRssMb: round(mb2(Math.max(peak.rss, baseline.rss))),
1131
+ peakHeapMb: round(mb2(Math.max(peak.heapUsed, baseline.heapUsed))),
1132
+ // Heap growth across the run ≈ what the loaded graphs + caches retain.
1133
+ retainedHeapMb: round(Math.max(0, mb2(after.heapUsed - baseline.heapUsed))),
1134
+ graphJsonBytes,
1135
+ bytesPerNode: nodes > 0 ? round(graphJsonBytes / nodes) : 0,
1136
+ note: "sampled at 25ms + phase boundaries; GC timing makes these approximate"
1137
+ },
1138
+ limits: resolveLimits(),
1139
+ determinism: { byteIdentical: deterministic },
1140
+ tokenReduction: { questions: perQuestion, aggregateRatio, note: "estimates (~4 chars/token); scales with repo size" }
1141
+ };
1142
+ }
1143
+ function startMemorySampler() {
1144
+ let rss = 0;
1145
+ let heapUsed = 0;
1146
+ const sample = () => {
1147
+ const m = process.memoryUsage();
1148
+ if (m.rss > rss) rss = m.rss;
1149
+ if (m.heapUsed > heapUsed) heapUsed = m.heapUsed;
1150
+ };
1151
+ const timer = setInterval(sample, 25);
1152
+ timer.unref?.();
1153
+ return {
1154
+ stop: () => {
1155
+ clearInterval(timer);
1156
+ sample();
1157
+ return { rss, heapUsed };
1158
+ }
1159
+ };
1160
+ }
1108
1161
  function deriveQuestions(graph) {
1109
1162
  return graph.nodes.filter((n) => n.kind !== "file" && n.kind !== "external").sort((a, b) => b.importance - a.importance || a.qualifiedName.localeCompare(b.qualifiedName)).slice(0, 5).map((n) => n.name);
1110
1163
  }
@@ -1133,12 +1186,18 @@ function safeSize(abs) {
1133
1186
  return 0;
1134
1187
  }
1135
1188
  }
1189
+ function mb2(bytes) {
1190
+ return bytes / (1024 * 1024);
1191
+ }
1136
1192
  function now() {
1137
1193
  return Number(process.hrtime.bigint() / 1000n) / 1e3;
1138
1194
  }
1139
1195
  function round(x) {
1140
1196
  return Math.round(x * 1e3) / 1e3;
1141
1197
  }
1198
+ function round6(x) {
1199
+ return Math.round(x * 1e6) / 1e6;
1200
+ }
1142
1201
  function pad2(s, n) {
1143
1202
  return s.padStart(n, " ");
1144
1203
  }
@@ -1882,7 +1941,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
1882
1941
  console.log(chalk5.green("\u2714") + ` Created ${chalk5.bold("vibgrate.config.ts")}`);
1883
1942
  }
1884
1943
  if (opts.baseline) {
1885
- const { runBaseline } = await import('./baseline-HBRBXJHJ.js');
1944
+ const { runBaseline } = await import('./baseline-FESLZK5O.js');
1886
1945
  await runBaseline(rootDir);
1887
1946
  }
1888
1947
  console.log("");