@vibgrate/cli 2026.711.2 → 2026.715.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,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { resolveDsn, resolveIngestHost, dashHostForIngestHost, resolveCliInvocation, availableRegionIds, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, inventory, uploadScanArtifact, ingestHostForRegionId, dsnCommand, pushCommand, CliError, ExitCode, NPX_INVOCATION, refreshIfStale, driftCount, embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, recordCliCall, CLI_TOOL_ALIASES, countPending, resolveOne, indexFor, countTokens, shortestPath, renderReport, impactOf, testsToRun, detectRunner, defaultGraphPath, serveStdio, ASSISTANTS, usageError, loadGraph, detectServeLaunch, installAssistant, writeNavigationConfig, uninstallAssistant, coveringTests, FREE_PACK, readScanArtifact, enrichOnline, ECOSYSTEMS, discoverModels, readSavings, readUsage, exportGraph, catalogPath, libDir, stableStringify, buildGraph, writeArtifacts, writeSnapshot, UsageError, ResourceLimitError, epistemicBreakdown, 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, fetchHostedDocsCached, selectForBudget, formatForExt, verifyDeterminism, renderHtml, isModelReady } from './chunk-75ZJYYJE.js';
3
- import { resolvedGrammarFiles, grammarSetVersion, canonicalize } from './chunk-X5YT263H.js';
4
- import { loadAdvancedScanHook, baselineCommand } from './chunk-4IHO6VUL.js';
5
- import { ensureDir, pathExists, writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, readJsonFile, writeTextFile, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols, brandProgressBar, resolveHead, workingTreeDirty } from './chunk-NNU2PW2H.js';
2
+ import { resolveDsn, resolveIngestHost, dashHostForIngestHost, resolveCliInvocation, availableRegionIds, createWorkspaceDsn, writeStoredCredentials, credentialsPath, findGitRoot, ensureGitignored, gitignoreEntryForCredentials, clearStoredCredentials, inventory, uploadScanArtifact, ingestHostForRegionId, dsnCommand, pushCommand, CliError, ExitCode, NPX_INVOCATION, refreshIfStale, driftCount, embeddingsCached, resolveEmbedModel, loadEmbedder, getNodeEmbeddings, queryGraphSemantic, queryGraph, unavailableMessage, recordCliCall, CLI_TOOL_ALIASES, countPending, resolveOne, indexFor, countTokens, shortestPath, renderReport, impactOf, testsToRun, detectRunner, defaultGraphPath, serveStdio, ASSISTANTS, usageError, loadGraph, detectServeLaunch, installAssistant, writeNavigationConfig, uninstallAssistant, coveringTests, FREE_PACK, readScanArtifact, enrichOnline, ECOSYSTEMS, discoverModels, readSavings, readUsage, exportGraph, catalogPath, libDir, stableStringify, buildGraph, writeArtifacts, writeSnapshot, UsageError, ResourceLimitError, epistemicBreakdown, 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, fetchHostedDocsCached, selectForBudget, formatForExt, verifyDeterminism, renderHtml, isModelReady } from './chunk-D4BPWARI.js';
3
+ import { resolvedGrammarFiles, grammarSetVersion, canonicalize } from './chunk-VFO5UDAT.js';
4
+ import { loadAdvancedScanHook, baselineCommand } from './chunk-6DKWB2OI.js';
5
+ import { ensureDir, pathExists, writeDefaultConfig, parseDsn, detectVcs, computeRepoFingerprint, resolveRepositoryName, fetchScanPreflight, runCoreScan, VERSION, readJsonFile, writeTextFile, loadConfig, prepareCompressedUpload, computeDriftScore, titleBox, projectTypeToVulnEcosystem, driftBar, gitHistoryAvailable, buildVersionTimelines, findPackageAnyEcosystem, normalizeConstraint, findVersionCrossings, versionSatisfies, PROJECT_TYPE_TO_OSV_ECOSYSTEM, fetchRiskySymbols, brandProgressBar, resolveHead, workingTreeDirty } from './chunk-C5AVF7PT.js';
6
6
  import './chunk-RXP66R2E.js';
7
7
  import { pathExists as pathExists$1, parseExcludePatterns } from './chunk-GI6W53LM.js';
8
- import * as fs6 from 'fs';
9
- import fs6__default, { realpathSync } from 'fs';
8
+ import * as fs7 from 'fs';
9
+ import fs7__default, { realpathSync } from 'fs';
10
10
  import * as path from 'path';
11
11
  import path__default from 'path';
12
- import { fileURLToPath } from 'url';
12
+ import { fileURLToPath, pathToFileURL } from 'url';
13
13
  import { Command, CommanderError, Option } from 'commander';
14
14
  import { execSync, spawn, spawnSync, execFileSync, execFile } from 'child_process';
15
15
  import * as crypto from 'crypto';
16
16
  import { randomUUID } from 'crypto';
17
17
  import chalk8 from 'chalk';
18
18
  import * as os from 'os';
19
- import * as fs12 from 'fs/promises';
19
+ import * as fs13 from 'fs/promises';
20
20
  import * as readline from 'readline';
21
21
  import semver from 'semver';
22
22
 
@@ -178,14 +178,14 @@ async function signGraphAttestation(root, graph, opts) {
178
178
  const explicitKey = opts.key ?? process.env.VG_ATTEST_KEY;
179
179
  const keyPath = explicitKey ? path.resolve(explicitKey) : path.join(root, ".vibgrate", DEFAULT_KEY);
180
180
  let keyGeneratedAt;
181
- if (!fs6.existsSync(keyPath)) {
181
+ if (!fs7.existsSync(keyPath)) {
182
182
  if (explicitKey) {
183
183
  throw new CliError(`signing key not found: ${explicitKey}`, ExitCode.USAGE_ERROR);
184
184
  }
185
185
  const kp = generateKeypair();
186
- fs6.mkdirSync(path.dirname(keyPath), { recursive: true });
187
- fs6.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
188
- fs6.writeFileSync(`${keyPath}.pub`, kp.publicPem);
186
+ fs7.mkdirSync(path.dirname(keyPath), { recursive: true });
187
+ fs7.writeFileSync(keyPath, kp.privatePem, { mode: 384 });
188
+ fs7.writeFileSync(`${keyPath}.pub`, kp.publicPem);
189
189
  keyGeneratedAt = keyPath;
190
190
  notices.push(
191
191
  `minted a new Ed25519 signing key at ${rel(root, keyPath)} (keyid ${kp.keyid}) \u2014 keep it, add it to .gitignore, and reuse it to re-sign reproducibly`
@@ -193,7 +193,7 @@ async function signGraphAttestation(root, graph, opts) {
193
193
  }
194
194
  let privateKey;
195
195
  try {
196
- privateKey = crypto.createPrivateKey(fs6.readFileSync(keyPath, "utf8"));
196
+ privateKey = crypto.createPrivateKey(fs7.readFileSync(keyPath, "utf8"));
197
197
  } catch {
198
198
  throw new CliError(`could not read an Ed25519 private key from ${rel(root, keyPath)}`, ExitCode.USAGE_ERROR);
199
199
  }
@@ -207,8 +207,8 @@ async function signGraphAttestation(root, graph, opts) {
207
207
  const statement = buildStatement(graph, { commit });
208
208
  const envelope = signStatement(statement, privateKey);
209
209
  const outPath = opts.attestation ? path.resolve(opts.attestation) : path.join(root, ".vibgrate", DEFAULT_ATTESTATION);
210
- fs6.mkdirSync(path.dirname(outPath), { recursive: true });
211
- fs6.writeFileSync(outPath, serializeEnvelope(envelope));
210
+ fs7.mkdirSync(path.dirname(outPath), { recursive: true });
211
+ fs7.writeFileSync(outPath, serializeEnvelope(envelope));
212
212
  return {
213
213
  summary: {
214
214
  keyid: envelope.signatures[0]?.keyid ?? "",
@@ -223,7 +223,7 @@ async function signGraphAttestation(root, graph, opts) {
223
223
  }
224
224
  function verifyGraphAttestation(root, opts) {
225
225
  const bundlePath = opts.attestation ? path.resolve(opts.attestation) : path.join(root, ".vibgrate", DEFAULT_ATTESTATION);
226
- if (!fs6.existsSync(bundlePath)) {
226
+ if (!fs7.existsSync(bundlePath)) {
227
227
  if (opts.attestation || opts.pub) {
228
228
  throw new CliError(
229
229
  `no attestation at ${rel(root, bundlePath)} \u2014 sign one with \`vg build --attest\``,
@@ -232,8 +232,8 @@ function verifyGraphAttestation(root, opts) {
232
232
  }
233
233
  return { bundlePath, missing: true };
234
234
  }
235
- const envelope = parseEnvelope(fs6.readFileSync(bundlePath, "utf8"));
236
- const publicKeyPem = opts.pub ? fs6.readFileSync(path.resolve(opts.pub), "utf8") : void 0;
235
+ const envelope = parseEnvelope(fs7.readFileSync(bundlePath, "utf8"));
236
+ const publicKeyPem = opts.pub ? fs7.readFileSync(path.resolve(opts.pub), "utf8") : void 0;
237
237
  const graph = loadGraph(root) ?? void 0;
238
238
  return { bundlePath, missing: false, result: verifyEnvelope(envelope, { publicKeyPem, graph }) };
239
239
  }
@@ -245,15 +245,15 @@ async function gitCommitInfo(root) {
245
245
  return { sha, shortSha: sha.slice(0, 7), branch, dirty: dirty === true ? true : dirty === false ? false : void 0 };
246
246
  }
247
247
  function gitBranch(root) {
248
- return new Promise((resolve16) => {
248
+ return new Promise((resolve17) => {
249
249
  execFile(
250
250
  "git",
251
251
  ["rev-parse", "--abbrev-ref", "HEAD"],
252
252
  { cwd: root, timeout: 5e3, windowsHide: true, encoding: "utf8" },
253
253
  (err, stdout) => {
254
- if (err) return resolve16(void 0);
254
+ if (err) return resolve17(void 0);
255
255
  const name = String(stdout).trim();
256
- resolve16(name && name !== "HEAD" ? name : void 0);
256
+ resolve17(name && name !== "HEAD" ? name : void 0);
257
257
  }
258
258
  );
259
259
  });
@@ -584,8 +584,8 @@ function writeExport(graph, target) {
584
584
  ExitCode.USAGE_ERROR
585
585
  );
586
586
  }
587
- fs6.mkdirSync(path.dirname(path.resolve(target)), { recursive: true });
588
- fs6.writeFileSync(target, content);
587
+ fs7.mkdirSync(path.dirname(path.resolve(target)), { recursive: true });
588
+ fs7.writeFileSync(target, content);
589
589
  }
590
590
  function collect(value, prev) {
591
591
  return [...prev, value];
@@ -604,7 +604,7 @@ async function runStatus(global) {
604
604
  const root = path.resolve(global.cwd ?? ".");
605
605
  const graphPath = global.graph ?? defaultGraphPath(root);
606
606
  const graph = loadGraph(root, graphPath);
607
- const hasCache = fs6.existsSync(path.join(cacheDir(root), "parse-cache.json"));
607
+ const hasCache = fs7.existsSync(path.join(cacheDir(root), "parse-cache.json"));
608
608
  let stale = null;
609
609
  let staleExact = false;
610
610
  if (graph) {
@@ -1289,14 +1289,14 @@ var INSTALL_ID_FILE = path.join(INSTALL_ID_DIR, "install-id");
1289
1289
  var SEND_TIMEOUT_MS = 4e3;
1290
1290
  function installId() {
1291
1291
  try {
1292
- const existing = fs6.readFileSync(INSTALL_ID_FILE, "utf8").trim();
1292
+ const existing = fs7.readFileSync(INSTALL_ID_FILE, "utf8").trim();
1293
1293
  if (isUuid(existing)) return existing;
1294
1294
  } catch {
1295
1295
  }
1296
1296
  const id = randomUuid();
1297
1297
  try {
1298
- fs6.mkdirSync(INSTALL_ID_DIR, { recursive: true });
1299
- fs6.writeFileSync(INSTALL_ID_FILE, id + "\n", { mode: 384 });
1298
+ fs7.mkdirSync(INSTALL_ID_DIR, { recursive: true });
1299
+ fs7.writeFileSync(INSTALL_ID_FILE, id + "\n", { mode: 384 });
1300
1300
  } catch {
1301
1301
  }
1302
1302
  return id;
@@ -1320,7 +1320,7 @@ function ledgerFilePath(root) {
1320
1320
  }
1321
1321
  function readOffset(root) {
1322
1322
  try {
1323
- const raw = JSON.parse(fs6.readFileSync(offsetPath(root), "utf8"));
1323
+ const raw = JSON.parse(fs7.readFileSync(offsetPath(root), "utf8"));
1324
1324
  return typeof raw.offset === "number" && raw.offset >= 0 ? raw.offset : 0;
1325
1325
  } catch {
1326
1326
  return 0;
@@ -1328,8 +1328,8 @@ function readOffset(root) {
1328
1328
  }
1329
1329
  function writeOffset(root, offset) {
1330
1330
  try {
1331
- fs6.mkdirSync(cacheDir(root), { recursive: true });
1332
- fs6.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + "\n");
1331
+ fs7.mkdirSync(cacheDir(root), { recursive: true });
1332
+ fs7.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + "\n");
1333
1333
  } catch {
1334
1334
  }
1335
1335
  }
@@ -1337,7 +1337,7 @@ function buildBatch(root, fromOffset, id = installId()) {
1337
1337
  const file = ledgerFilePath(root);
1338
1338
  let size = 0;
1339
1339
  try {
1340
- size = fs6.statSync(file).size;
1340
+ size = fs7.statSync(file).size;
1341
1341
  } catch {
1342
1342
  return { batch: null, newOffset: 0 };
1343
1343
  }
@@ -1345,13 +1345,13 @@ function buildBatch(root, fromOffset, id = installId()) {
1345
1345
  if (start >= size) return { batch: null, newOffset: size };
1346
1346
  let text = "";
1347
1347
  try {
1348
- const fd = fs6.openSync(file, "r");
1348
+ const fd = fs7.openSync(file, "r");
1349
1349
  try {
1350
1350
  const buf = Buffer.alloc(size - start);
1351
- fs6.readSync(fd, buf, 0, buf.length, start);
1351
+ fs7.readSync(fd, buf, 0, buf.length, start);
1352
1352
  text = buf.toString("utf8");
1353
1353
  } finally {
1354
- fs6.closeSync(fd);
1354
+ fs7.closeSync(fd);
1355
1355
  }
1356
1356
  } catch {
1357
1357
  return { batch: null, newOffset: fromOffset };
@@ -1497,7 +1497,7 @@ function registerServe(program) {
1497
1497
  }
1498
1498
  async function ensureServableGraph(root, graphPath, global, refresh, opts = {}) {
1499
1499
  if (refresh) {
1500
- if (!fs6.existsSync(graphPath)) {
1500
+ if (!fs7.existsSync(graphPath)) {
1501
1501
  info(c.dim("vg \xB7 no map found \u2014 building it before serving\u2026"));
1502
1502
  await runBuild(
1503
1503
  [],
@@ -1514,7 +1514,7 @@ async function ensureServableGraph(root, graphPath, global, refresh, opts = {})
1514
1514
  }
1515
1515
  }
1516
1516
  }
1517
- if (!fs6.existsSync(graphPath)) {
1517
+ if (!fs7.existsSync(graphPath)) {
1518
1518
  throw new CliError(
1519
1519
  `no map found at ${graphPath} \u2014 run \`vg\` to build one first`,
1520
1520
  ExitCode.NOT_FOUND
@@ -1569,12 +1569,587 @@ async function serveHttp(graphPath, host, port, opts, freshness) {
1569
1569
  info(c.red(`vg serve: request error: ${err.message}`));
1570
1570
  }
1571
1571
  });
1572
- await new Promise((resolve16) => httpServer.listen(port, host, resolve16));
1572
+ await new Promise((resolve17) => httpServer.listen(port, host, resolve17));
1573
1573
  info(c.dim(`vg \xB7 MCP server on http://${host}:${port}/mcp (read-only, local, ${freshness})`));
1574
1574
  await new Promise(() => {
1575
1575
  });
1576
1576
  }
1577
1577
 
1578
+ // src/lsp/protocol.ts
1579
+ var ErrorCodes = {
1580
+ MethodNotFound: -32601,
1581
+ InternalError: -32603
1582
+ };
1583
+ var MessageReader = class {
1584
+ buf = Buffer.alloc(0);
1585
+ /** Feed a chunk; returns every complete message now available. */
1586
+ push(chunk) {
1587
+ this.buf = this.buf.length === 0 ? chunk : Buffer.concat([this.buf, chunk]);
1588
+ const out2 = [];
1589
+ for (; ; ) {
1590
+ const headerEnd = this.buf.indexOf("\r\n\r\n");
1591
+ if (headerEnd === -1) break;
1592
+ const header = this.buf.subarray(0, headerEnd).toString("ascii");
1593
+ const match = /content-length:\s*(\d+)/i.exec(header);
1594
+ if (!match) {
1595
+ this.buf = this.buf.subarray(headerEnd + 4);
1596
+ continue;
1597
+ }
1598
+ const length = Number(match[1]);
1599
+ const bodyStart = headerEnd + 4;
1600
+ if (this.buf.length < bodyStart + length) break;
1601
+ const body = this.buf.subarray(bodyStart, bodyStart + length).toString("utf8");
1602
+ this.buf = this.buf.subarray(bodyStart + length);
1603
+ try {
1604
+ out2.push(JSON.parse(body));
1605
+ } catch {
1606
+ }
1607
+ }
1608
+ return out2;
1609
+ }
1610
+ };
1611
+ var MessageWriter = class {
1612
+ constructor(out2) {
1613
+ this.out = out2;
1614
+ }
1615
+ out;
1616
+ write(msg) {
1617
+ const body = Buffer.from(JSON.stringify(msg), "utf8");
1618
+ this.out.write(`Content-Length: ${body.length}\r
1619
+ \r
1620
+ `);
1621
+ this.out.write(body);
1622
+ }
1623
+ };
1624
+ var Connection = class {
1625
+ reader = new MessageReader();
1626
+ writer;
1627
+ requests = /* @__PURE__ */ new Map();
1628
+ notifications = /* @__PURE__ */ new Map();
1629
+ constructor(input = process.stdin, output = process.stdout) {
1630
+ this.writer = new MessageWriter(output);
1631
+ input.on("data", (chunk) => {
1632
+ for (const msg of this.reader.push(chunk)) void this.dispatch(msg);
1633
+ });
1634
+ }
1635
+ onRequest(method, handler) {
1636
+ this.requests.set(method, handler);
1637
+ }
1638
+ onNotification(method, handler) {
1639
+ this.notifications.set(method, handler);
1640
+ }
1641
+ /** Push a server→client notification (diagnostics, `vibgrate/score`, …). */
1642
+ notify(method, params) {
1643
+ this.writer.write({ jsonrpc: "2.0", method, params });
1644
+ }
1645
+ async dispatch(msg) {
1646
+ if (!msg.method) return;
1647
+ const isRequest = msg.id !== void 0 && msg.id !== null;
1648
+ if (!isRequest) {
1649
+ const handler2 = this.notifications.get(msg.method);
1650
+ if (handler2) {
1651
+ try {
1652
+ await handler2(msg.method, msg.params);
1653
+ } catch {
1654
+ }
1655
+ }
1656
+ return;
1657
+ }
1658
+ const handler = this.requests.get(msg.method);
1659
+ if (!handler) {
1660
+ this.writer.write({
1661
+ jsonrpc: "2.0",
1662
+ id: msg.id,
1663
+ error: { code: ErrorCodes.MethodNotFound, message: `Unhandled method: ${msg.method}` }
1664
+ });
1665
+ return;
1666
+ }
1667
+ try {
1668
+ const result = await handler(msg.method, msg.params);
1669
+ this.writer.write({ jsonrpc: "2.0", id: msg.id, result: result ?? null });
1670
+ } catch (err) {
1671
+ this.writer.write({
1672
+ jsonrpc: "2.0",
1673
+ id: msg.id,
1674
+ error: {
1675
+ code: ErrorCodes.InternalError,
1676
+ message: err instanceof Error ? err.message : "Internal error"
1677
+ }
1678
+ });
1679
+ }
1680
+ }
1681
+ };
1682
+
1683
+ // src/lsp/manifest-positions.ts
1684
+ function manifestKind(filePath) {
1685
+ const base = (filePath.split(/[\\/]/).pop() ?? "").toLowerCase();
1686
+ if (base === "package.json") return "package.json";
1687
+ if (base === "go.mod") return "go.mod";
1688
+ if (base === "requirements.txt" || /^requirements.*\.txt$/.test(base)) return "requirements.txt";
1689
+ if (base === "pyproject.toml") return "pyproject.toml";
1690
+ if (base === "cargo.toml") return "Cargo.toml";
1691
+ if (base === "pom.xml") return "pom.xml";
1692
+ if (base === "build.gradle" || base === "build.gradle.kts") return "build.gradle";
1693
+ if (base === "gemfile") return "Gemfile";
1694
+ if (base === "composer.json") return "composer.json";
1695
+ if (base === "pubspec.yaml") return "pubspec.yaml";
1696
+ if (base === "mix.exs") return "mix.exs";
1697
+ if (base.endsWith(".csproj") || base.endsWith(".fsproj") || base.endsWith(".vbproj")) return "csproj";
1698
+ if (base === "dockerfile" || base.startsWith("dockerfile.")) return "Dockerfile";
1699
+ return "unknown";
1700
+ }
1701
+ function isManifest(filePath) {
1702
+ return manifestKind(filePath) !== "unknown";
1703
+ }
1704
+ function esc(s) {
1705
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1706
+ }
1707
+ function findPackageLine(text, pkg, kind) {
1708
+ const lines = text.split(/\r?\n/);
1709
+ const p = esc(pkg);
1710
+ const patterns = (() => {
1711
+ switch (kind) {
1712
+ case "package.json":
1713
+ case "composer.json":
1714
+ return [new RegExp(`^\\s*"${p}"\\s*:`)];
1715
+ case "go.mod":
1716
+ return [new RegExp(`^\\s*(?:require\\s+)?${p}\\s+v?\\d`)];
1717
+ case "requirements.txt":
1718
+ return [new RegExp(`^\\s*${p}\\s*(?:\\[[^\\]]*\\])?\\s*(?:[=<>!~]|$)`, "i")];
1719
+ case "pyproject.toml":
1720
+ case "Cargo.toml":
1721
+ return [
1722
+ new RegExp(`^\\s*${p}\\s*=`),
1723
+ new RegExp(`^\\s*"${p}\\s*(?:[=<>!~\\[]|")`)
1724
+ ];
1725
+ case "pom.xml":
1726
+ return [new RegExp(`<artifactId>\\s*${p}\\s*</artifactId>`)];
1727
+ case "build.gradle":
1728
+ return [new RegExp(`["']${p}(?:["':])`)];
1729
+ case "Gemfile":
1730
+ return [new RegExp(`^\\s*gem\\s+["']${p}["']`)];
1731
+ case "pubspec.yaml":
1732
+ return [new RegExp(`^\\s*${p}\\s*:`)];
1733
+ case "mix.exs":
1734
+ return [new RegExp(`\\{\\s*:${p}\\s*,`)];
1735
+ case "csproj":
1736
+ return [new RegExp(`Include\\s*=\\s*"${p}"`, "i")];
1737
+ case "Dockerfile":
1738
+ return [new RegExp(`^\\s*FROM\\s+.*${p}`, "i")];
1739
+ default:
1740
+ return [];
1741
+ }
1742
+ })();
1743
+ for (const re of patterns) {
1744
+ for (let i = 0; i < lines.length; i++) {
1745
+ if (re.test(lines[i])) return i;
1746
+ }
1747
+ }
1748
+ return -1;
1749
+ }
1750
+ function findRuntimeLine(text, kind) {
1751
+ const lines = text.split(/\r?\n/);
1752
+ const patterns = (() => {
1753
+ switch (kind) {
1754
+ case "package.json":
1755
+ return [/^\s*"node"\s*:/, /^\s*"engines"\s*:/];
1756
+ case "go.mod":
1757
+ return [/^\s*go\s+\d/];
1758
+ case "pyproject.toml":
1759
+ return [/^\s*(?:requires-python|python)\s*=/];
1760
+ case "pom.xml":
1761
+ return [/<(?:java\.version|maven\.compiler\.(?:source|target|release))>/];
1762
+ case "build.gradle":
1763
+ return [/(?:sourceCompatibility|targetCompatibility|JavaVersion)/];
1764
+ case "csproj":
1765
+ return [/<TargetFrameworks?>/i];
1766
+ case "Dockerfile":
1767
+ return [/^\s*FROM\s+/i];
1768
+ default:
1769
+ return [];
1770
+ }
1771
+ })();
1772
+ for (const re of patterns) {
1773
+ for (let i = 0; i < lines.length; i++) {
1774
+ if (re.test(lines[i])) return i;
1775
+ }
1776
+ }
1777
+ return -1;
1778
+ }
1779
+ function endOfLine(text, line) {
1780
+ const lines = text.split(/\r?\n/);
1781
+ return (lines[line] ?? "").length;
1782
+ }
1783
+
1784
+ // src/lsp/server.ts
1785
+ function bandForDependency(dep) {
1786
+ if (dep.drift === "major-behind") {
1787
+ return (dep.majorsBehind ?? 1) >= 2 ? "high" : "moderate";
1788
+ }
1789
+ if (dep.drift === "minor-behind") return "moderate";
1790
+ return "low";
1791
+ }
1792
+ function severityFor(level) {
1793
+ if (level === "note") return 3;
1794
+ return 2;
1795
+ }
1796
+ var DIAGNOSTIC_RULES = /* @__PURE__ */ new Set([
1797
+ "vibgrate/runtime-eol",
1798
+ "vibgrate/runtime-lag",
1799
+ "vibgrate/unmaintained",
1800
+ "vibgrate/abandoned",
1801
+ "vibgrate/license-change",
1802
+ "vibgrate/eol"
1803
+ ]);
1804
+ var VibgrateLanguageServer = class {
1805
+ constructor(opts, output = process.stdout) {
1806
+ this.opts = opts;
1807
+ this.conn = new Connection(process.stdin, output);
1808
+ this.register();
1809
+ }
1810
+ opts;
1811
+ conn;
1812
+ docs = /* @__PURE__ */ new Map();
1813
+ // uri → text
1814
+ artifact = null;
1815
+ scanning = false;
1816
+ queued = false;
1817
+ debounce = null;
1818
+ shuttingDown = false;
1819
+ register() {
1820
+ this.conn.onRequest("initialize", () => ({
1821
+ capabilities: {
1822
+ // 1 = Full sync. We only actually act on save, but full sync keeps our
1823
+ // buffer honest so hovers land on the text the user is looking at.
1824
+ textDocumentSync: 1,
1825
+ hoverProvider: true,
1826
+ codeLensProvider: { resolveProvider: false },
1827
+ executeCommandProvider: {
1828
+ commands: ["vibgrate.rescan", "vibgrate.explain", "vibgrate.routeFix"]
1829
+ }
1830
+ },
1831
+ serverInfo: { name: "Vibgrate", version: VERSION }
1832
+ }));
1833
+ this.conn.onNotification("initialized", () => this.scheduleScan(0));
1834
+ this.conn.onNotification("textDocument/didOpen", (_m, params) => {
1835
+ const p = params;
1836
+ const uri = p.textDocument?.uri;
1837
+ if (!uri || !isManifest(uriToPath(uri))) return;
1838
+ this.docs.set(uri, p.textDocument?.text ?? "");
1839
+ if (this.artifact) this.publishForDoc(uri);
1840
+ else this.scheduleScan(0);
1841
+ });
1842
+ this.conn.onNotification("textDocument/didChange", (_m, params) => {
1843
+ const p = params;
1844
+ const uri = p.textDocument?.uri;
1845
+ if (!uri || !this.docs.has(uri)) return;
1846
+ const full = p.contentChanges?.[p.contentChanges.length - 1]?.text;
1847
+ if (typeof full === "string") this.docs.set(uri, full);
1848
+ if (this.artifact) this.publishForDoc(uri);
1849
+ });
1850
+ this.conn.onNotification("textDocument/didSave", (_m, params) => {
1851
+ const p = params;
1852
+ const uri = p.textDocument?.uri;
1853
+ if (!uri || !this.docs.has(uri)) return;
1854
+ this.scheduleScan(400);
1855
+ });
1856
+ this.conn.onNotification("textDocument/didClose", (_m, params) => {
1857
+ const p = params;
1858
+ if (p.textDocument?.uri) this.docs.delete(p.textDocument.uri);
1859
+ });
1860
+ this.conn.onRequest("textDocument/hover", (_m, params) => this.onHover(params));
1861
+ this.conn.onRequest("textDocument/codeLens", (_m, params) => this.onCodeLens(params));
1862
+ this.conn.onRequest("workspace/executeCommand", (_m, params) => {
1863
+ const p = params;
1864
+ if (p.command === "vibgrate.rescan") {
1865
+ this.scheduleScan(0);
1866
+ return { ok: true };
1867
+ }
1868
+ return null;
1869
+ });
1870
+ this.conn.onRequest("shutdown", () => {
1871
+ this.shuttingDown = true;
1872
+ if (this.debounce) clearTimeout(this.debounce);
1873
+ return null;
1874
+ });
1875
+ this.conn.onNotification("exit", () => {
1876
+ process.exit(this.shuttingDown ? 0 : 1);
1877
+ });
1878
+ }
1879
+ // ── Scanning ─────────────────────────────────────────────────────────────
1880
+ scheduleScan(delayMs) {
1881
+ if (this.debounce) clearTimeout(this.debounce);
1882
+ this.debounce = setTimeout(() => void this.scan(), delayMs);
1883
+ }
1884
+ async scan() {
1885
+ if (this.scanning) {
1886
+ this.queued = true;
1887
+ return;
1888
+ }
1889
+ this.scanning = true;
1890
+ try {
1891
+ const scanOpts = {
1892
+ format: "json",
1893
+ concurrency: 8,
1894
+ offline: this.opts.offline,
1895
+ noLocalArtifacts: true,
1896
+ // an editor scan must not litter the repo
1897
+ noGraph: true,
1898
+ // the code map is not needed to score drift; skip the cost
1899
+ quiet: true,
1900
+ // no spinners, no artifact dump — an editor is not a terminal
1901
+ vibgrateVersion: VERSION
1902
+ };
1903
+ const advanced = await loadAdvancedScanHook();
1904
+ this.artifact = await runCoreScan(this.opts.root, scanOpts, advanced);
1905
+ this.publishScore();
1906
+ for (const uri of this.docs.keys()) this.publishForDoc(uri);
1907
+ } catch (err) {
1908
+ this.conn.notify("window/logMessage", {
1909
+ type: 3,
1910
+ message: `Vibgrate scan failed: ${err instanceof Error ? err.message : String(err)}`
1911
+ });
1912
+ this.conn.notify("vibgrate/status", { state: "error" });
1913
+ } finally {
1914
+ this.scanning = false;
1915
+ if (this.queued) {
1916
+ this.queued = false;
1917
+ this.scheduleScan(0);
1918
+ }
1919
+ }
1920
+ }
1921
+ // ── Publishing ───────────────────────────────────────────────────────────
1922
+ publishScore() {
1923
+ const a = this.artifact;
1924
+ if (!a) return;
1925
+ let behind = 0;
1926
+ let unmaintained = 0;
1927
+ let total = 0;
1928
+ for (const proj of a.projects ?? []) {
1929
+ for (const dep of proj.dependencies ?? []) {
1930
+ total++;
1931
+ if (dep.drift === "major-behind" || dep.drift === "minor-behind") behind++;
1932
+ }
1933
+ }
1934
+ const eol = (a.findings ?? []).filter(
1935
+ (f) => f.ruleId === "vibgrate/runtime-eol" || f.ruleId === "vibgrate/eol"
1936
+ ).length;
1937
+ unmaintained = (a.findings ?? []).filter(
1938
+ (f) => f.ruleId === "vibgrate/unmaintained" || f.ruleId === "vibgrate/abandoned"
1939
+ ).length;
1940
+ const band = a.drift.riskLevel ?? "low";
1941
+ const payload = {
1942
+ score: a.drift.score,
1943
+ band,
1944
+ // v3 §2.4: `estimated` means "no timestamps at all" — it is NOT an
1945
+ // offline marker. An air-gapped scan against a dated snapshot is Verified.
1946
+ mode: hasReleaseDates(a) ? "verified" : "estimated",
1947
+ methodology: a.drift.methodologyVersion ?? "unknown",
1948
+ scale: "0 best, 100 worst",
1949
+ counts: { behind, eol, unmaintained, total },
1950
+ rootPath: a.rootPath,
1951
+ scannedAt: a.timestamp
1952
+ };
1953
+ this.conn.notify("vibgrate/score", payload);
1954
+ }
1955
+ /** Decorations + (optionally) diagnostics for one open manifest. */
1956
+ publishForDoc(uri) {
1957
+ const a = this.artifact;
1958
+ const text = this.docs.get(uri);
1959
+ if (!a || text === void 0) return;
1960
+ const filePath = uriToPath(uri);
1961
+ const kind = manifestKind(filePath);
1962
+ const project = projectForFile(this.opts.root, a, filePath);
1963
+ const items = [];
1964
+ for (const dep of project?.dependencies ?? []) {
1965
+ if (dep.drift === "current" || dep.drift === "unknown") continue;
1966
+ const line = findPackageLine(text, dep.package, kind);
1967
+ if (line === -1) continue;
1968
+ items.push({
1969
+ line,
1970
+ endCol: endOfLine(text, line),
1971
+ text: inlineLabel(dep),
1972
+ band: bandForDependency(dep),
1973
+ package: dep.package
1974
+ });
1975
+ }
1976
+ this.conn.notify("vibgrate/inline", { uri, items });
1977
+ if (!this.opts.diagnostics) {
1978
+ this.conn.notify("textDocument/publishDiagnostics", { uri, diagnostics: [] });
1979
+ return;
1980
+ }
1981
+ const diagnostics = (a.findings ?? []).filter((f) => DIAGNOSTIC_RULES.has(f.ruleId)).filter((f) => project && sameProject(f.location, project.path)).map((f) => {
1982
+ const line = Math.max(0, findRuntimeLine(text, kind));
1983
+ return {
1984
+ range: {
1985
+ start: { line, character: 0 },
1986
+ end: { line, character: endOfLine(text, line) }
1987
+ },
1988
+ severity: severityFor(f.level),
1989
+ // never 1 — see file header
1990
+ source: "vibgrate",
1991
+ code: f.ruleId,
1992
+ message: f.message
1993
+ };
1994
+ });
1995
+ this.conn.notify("textDocument/publishDiagnostics", { uri, diagnostics });
1996
+ }
1997
+ // ── Requests ─────────────────────────────────────────────────────────────
1998
+ onHover(params) {
1999
+ const p = params;
2000
+ const uri = p.textDocument?.uri;
2001
+ const line = p.position?.line;
2002
+ const a = this.artifact;
2003
+ const text = uri ? this.docs.get(uri) : void 0;
2004
+ if (!uri || line === void 0 || !a || text === void 0) return null;
2005
+ const filePath = uriToPath(uri);
2006
+ const kind = manifestKind(filePath);
2007
+ const project = projectForFile(this.opts.root, a, filePath);
2008
+ const dep = (project?.dependencies ?? []).find(
2009
+ (d) => findPackageLine(text, d.package, kind) === line
2010
+ );
2011
+ if (!dep) return null;
2012
+ return {
2013
+ contents: { kind: "markdown", value: hoverMarkdown(dep) }
2014
+ };
2015
+ }
2016
+ onCodeLens(params) {
2017
+ const p = params;
2018
+ const uri = p.textDocument?.uri;
2019
+ const a = this.artifact;
2020
+ if (!uri || !a || !this.docs.has(uri)) return [];
2021
+ const behind = (a.projects ?? []).reduce(
2022
+ (n, proj) => n + (proj.dependencies ?? []).filter(
2023
+ (d) => d.drift === "major-behind" || d.drift === "minor-behind"
2024
+ ).length,
2025
+ 0
2026
+ );
2027
+ const eol = (a.findings ?? []).filter(
2028
+ (f) => f.ruleId === "vibgrate/runtime-eol" || f.ruleId === "vibgrate/eol"
2029
+ ).length;
2030
+ const mode = hasReleaseDates(a) ? "" : "~";
2031
+ const title = `Vibgrate \xB7 drift ${mode}${a.drift.score} (${a.drift.riskLevel}) \xB7 ${behind} behind \xB7 ${eol} EOL`;
2032
+ return [
2033
+ {
2034
+ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
2035
+ command: { title, command: "vibgrate.openPanel", arguments: [] }
2036
+ }
2037
+ ];
2038
+ }
2039
+ };
2040
+ function uriToPath(uri) {
2041
+ try {
2042
+ return fileURLToPath(uri);
2043
+ } catch {
2044
+ return uri;
2045
+ }
2046
+ }
2047
+ function projectForFile(root, a, filePath) {
2048
+ const dir = path.dirname(path.resolve(filePath));
2049
+ let best;
2050
+ let bestLen = -1;
2051
+ for (const proj of a.projects ?? []) {
2052
+ const projDir = path.resolve(root, proj.path);
2053
+ if ((dir === projDir || dir.startsWith(projDir + path.sep)) && projDir.length > bestLen) {
2054
+ best = proj;
2055
+ bestLen = projDir.length;
2056
+ }
2057
+ }
2058
+ return best;
2059
+ }
2060
+ function sameProject(location, projectPath) {
2061
+ return path.normalize(location) === path.normalize(projectPath);
2062
+ }
2063
+ function hasReleaseDates(a) {
2064
+ for (const proj of a.projects ?? []) {
2065
+ for (const dep of proj.dependencies ?? []) {
2066
+ if (dep.ageDays !== null && dep.ageDays !== void 0) return true;
2067
+ }
2068
+ }
2069
+ return false;
2070
+ }
2071
+ function inlineLabel(dep) {
2072
+ const bits = [];
2073
+ if (dep.drift === "major-behind") {
2074
+ const n = dep.majorsBehind ?? 1;
2075
+ bits.push(`${n} major behind`);
2076
+ } else if (dep.drift === "minor-behind") {
2077
+ bits.push("minor behind");
2078
+ }
2079
+ if (dep.latestStable) bits.push(dep.latestStable);
2080
+ if (dep.ageDays != null && dep.ageDays >= 1) {
2081
+ bits.push(`${Math.round(dep.ageDays).toLocaleString("en-US")}d stale`);
2082
+ }
2083
+ return bits.join(" \xB7 ");
2084
+ }
2085
+ function hoverMarkdown(dep) {
2086
+ const lines = [];
2087
+ lines.push(`**${dep.package}**`);
2088
+ lines.push("");
2089
+ const yours = dep.resolvedVersion ?? dep.currentSpec;
2090
+ if (dep.latestStable && dep.latestStable !== yours) {
2091
+ lines.push(`| | |`);
2092
+ lines.push(`|---|---|`);
2093
+ lines.push(`| yours | \`${yours}\` |`);
2094
+ lines.push(`| latest | \`${dep.latestStable}\` |`);
2095
+ if (dep.majorsBehind) lines.push(`| majors behind | ${dep.majorsBehind} |`);
2096
+ if (dep.ageDays != null && dep.ageDays >= 1) {
2097
+ lines.push(`| age | ${Math.round(dep.ageDays).toLocaleString("en-US")} days |`);
2098
+ }
2099
+ if (dep.libyears != null && dep.libyears >= 0.01) {
2100
+ lines.push(`| libyears | ${dep.libyears.toFixed(2)} |`);
2101
+ }
2102
+ const license = dep.license?.spdxId ?? dep.license?.raw;
2103
+ if (license) lines.push(`| license | ${license} |`);
2104
+ } else {
2105
+ lines.push(`\`${yours}\` \u2014 current.`);
2106
+ }
2107
+ lines.push("");
2108
+ lines.push("$(shield) Resolved locally from your lockfile. No source uploaded.");
2109
+ return lines.join("\n");
2110
+ }
2111
+ function startLanguageServer(opts) {
2112
+ if (!fs7.existsSync(opts.root)) {
2113
+ process.stderr.write(`vg lsp: root does not exist: ${opts.root}
2114
+ `);
2115
+ process.exit(1);
2116
+ }
2117
+ const realWrite = process.stdout.write.bind(process.stdout);
2118
+ const protocolOut = {
2119
+ write(chunk) {
2120
+ return realWrite(chunk);
2121
+ }
2122
+ };
2123
+ process.stdout.write = ((chunk, ...rest) => process.stderr.write(chunk, ...rest));
2124
+ process.stderr.write(
2125
+ `vg lsp ${VERSION} \u2014 serving ${pathToFileURL(opts.root).href}${opts.offline ? " (offline)" : ""}
2126
+ `
2127
+ );
2128
+ new VibgrateLanguageServer(opts, protocolOut);
2129
+ }
2130
+
2131
+ // src/commands/lsp.ts
2132
+ function registerLsp(program) {
2133
+ const cmd = program.command("lsp").description("start the Vibgrate language server (stdio) \u2014 the engine behind the IDE extensions").option(
2134
+ "--diagnostics",
2135
+ "also publish Problems-panel diagnostics (EOL runtime, unmaintained, license change). Off by default: drift is not a defect, and the Problems panel is not ours to fill",
2136
+ false
2137
+ ).action(async function(opts) {
2138
+ const global = readGlobal(this);
2139
+ const root = rootOf(global);
2140
+ startLanguageServer({
2141
+ root,
2142
+ // `--local` is the established air-gap flag across the CLI; honour it
2143
+ // here too, so an offline editor session stays offline.
2144
+ offline: global.local === true,
2145
+ diagnostics: opts.diagnostics === true
2146
+ });
2147
+ await new Promise(() => {
2148
+ });
2149
+ });
2150
+ applyGlobalOptions(cmd);
2151
+ }
2152
+
1578
2153
  // src/commands/install.ts
1579
2154
  var SMALL_REPO_FILES = 150;
1580
2155
  function registerInstall(program) {
@@ -1593,7 +2168,7 @@ function registerInstall(program) {
1593
2168
  }
1594
2169
  return;
1595
2170
  }
1596
- const targets = opts.all ? ASSISTANTS : tools.map(resolve5);
2171
+ const targets = opts.all ? ASSISTANTS : tools.map(resolve6);
1597
2172
  if (targets.length === 0) throw usageError("name an assistant (e.g. `vg install claude`) or use --all / --list");
1598
2173
  const graph = loadGraph(root, global.graph);
1599
2174
  const fileCount = graph ? graph.nodes.filter((n) => n.kind === "file").length : 0;
@@ -1617,7 +2192,7 @@ function registerInstall(program) {
1617
2192
  const uninstall = program.command("uninstall").description("remove vg from an AI assistant").argument("<tools...>", "assistant ids").option("--purge", "also delete the skill file").action(function(tools, opts) {
1618
2193
  const global = readGlobal(this);
1619
2194
  const root = rootOf(global);
1620
- const results = tools.map(resolve5).map((a) => ({ id: a.id, removed: uninstallAssistant(a, root, !!opts.purge) }));
2195
+ const results = tools.map(resolve6).map((a) => ({ id: a.id, removed: uninstallAssistant(a, root, !!opts.purge) }));
1621
2196
  if (global.json) {
1622
2197
  json({ root, results });
1623
2198
  return;
@@ -1628,7 +2203,7 @@ function registerInstall(program) {
1628
2203
  });
1629
2204
  applyGlobalOptions(uninstall);
1630
2205
  }
1631
- function resolve5(id) {
2206
+ function resolve6(id) {
1632
2207
  const a = assistantById(id);
1633
2208
  if (!a) {
1634
2209
  const near = ASSISTANTS.filter(
@@ -1649,7 +2224,7 @@ function registerShare(program) {
1649
2224
  const global = readGlobal(this);
1650
2225
  const root = rootOf(global);
1651
2226
  const gitDir = path.join(root, ".git");
1652
- if (!fs6.existsSync(gitDir)) {
2227
+ if (!fs7.existsSync(gitDir)) {
1653
2228
  throw new CliError("not a git repository \u2014 run `vg share` inside a git repo", ExitCode.USAGE_ERROR);
1654
2229
  }
1655
2230
  if (opts.undo) {
@@ -1671,22 +2246,22 @@ function registerShare(program) {
1671
2246
  }
1672
2247
  function writeVibgrateGitignore(root, reports) {
1673
2248
  const dir = path.join(root, ".vibgrate");
1674
- fs6.mkdirSync(dir, { recursive: true });
2249
+ fs7.mkdirSync(dir, { recursive: true });
1675
2250
  const lines = ["# Managed by `vg share` \u2014 keep graph.json committed, ignore the rest", "cache/", "facts.jsonl"];
1676
2251
  if (!reports) lines.push("graph.html", "GRAPH_REPORT.md");
1677
- fs6.writeFileSync(path.join(dir, ".gitignore"), `${lines.join("\n")}
2252
+ fs7.writeFileSync(path.join(dir, ".gitignore"), `${lines.join("\n")}
1678
2253
  `);
1679
2254
  }
1680
2255
  function writeGitAttributes(root) {
1681
2256
  const file = path.join(root, ".gitattributes");
1682
2257
  const line = ".vibgrate/graph.json merge=vg";
1683
- let content = fs6.existsSync(file) ? fs6.readFileSync(file, "utf8") : "";
2258
+ let content = fs7.existsSync(file) ? fs7.readFileSync(file, "utf8") : "";
1684
2259
  if (!content.split("\n").some((l) => l.trim() === line)) {
1685
2260
  content = content.length ? `${content.replace(/\s*$/, "")}
1686
2261
  ${line}
1687
2262
  ` : `${line}
1688
2263
  `;
1689
- fs6.writeFileSync(file, content);
2264
+ fs7.writeFileSync(file, content);
1690
2265
  }
1691
2266
  }
1692
2267
  function configureMergeDriver(root) {
@@ -1695,7 +2270,7 @@ function configureMergeDriver(root) {
1695
2270
  }
1696
2271
  function installPreCommitHook(root) {
1697
2272
  const hooksDir = hookDir(root);
1698
- fs6.mkdirSync(hooksDir, { recursive: true });
2273
+ fs7.mkdirSync(hooksDir, { recursive: true });
1699
2274
  const file = path.join(hooksDir, "pre-commit");
1700
2275
  const block = [
1701
2276
  HOOK_BEGIN,
@@ -1705,7 +2280,7 @@ function installPreCommitHook(root) {
1705
2280
  "fi",
1706
2281
  HOOK_END
1707
2282
  ].join("\n");
1708
- let content = fs6.existsSync(file) ? fs6.readFileSync(file, "utf8") : "#!/bin/sh\n";
2283
+ let content = fs7.existsSync(file) ? fs7.readFileSync(file, "utf8") : "#!/bin/sh\n";
1709
2284
  const re = new RegExp(`${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}`);
1710
2285
  if (re.test(content)) content = content.replace(re, block);
1711
2286
  else content = `${content.replace(/\s*$/, "")}
@@ -1714,21 +2289,21 @@ ${block}
1714
2289
  `;
1715
2290
  if (!content.startsWith("#!")) content = `#!/bin/sh
1716
2291
  ${content}`;
1717
- fs6.writeFileSync(file, content);
1718
- fs6.chmodSync(file, 493);
2292
+ fs7.writeFileSync(file, content);
2293
+ fs7.chmodSync(file, 493);
1719
2294
  }
1720
2295
  function undo(root) {
1721
2296
  const hookFile = path.join(hookDir(root), "pre-commit");
1722
- if (fs6.existsSync(hookFile)) {
2297
+ if (fs7.existsSync(hookFile)) {
1723
2298
  const re = new RegExp(`\\n*${escapeRe(HOOK_BEGIN)}[\\s\\S]*?${escapeRe(HOOK_END)}\\n*`);
1724
- const next2 = fs6.readFileSync(hookFile, "utf8").replace(re, "\n");
1725
- if (next2.trim() === "#!/bin/sh") fs6.rmSync(hookFile);
1726
- else fs6.writeFileSync(hookFile, next2);
2299
+ const next2 = fs7.readFileSync(hookFile, "utf8").replace(re, "\n");
2300
+ if (next2.trim() === "#!/bin/sh") fs7.rmSync(hookFile);
2301
+ else fs7.writeFileSync(hookFile, next2);
1727
2302
  }
1728
2303
  const attr = path.join(root, ".gitattributes");
1729
- if (fs6.existsSync(attr)) {
1730
- const next2 = fs6.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
1731
- fs6.writeFileSync(attr, next2);
2304
+ if (fs7.existsSync(attr)) {
2305
+ const next2 = fs7.readFileSync(attr, "utf8").split("\n").filter((l) => l.trim() !== ".vibgrate/graph.json merge=vg").join("\n");
2306
+ fs7.writeFileSync(attr, next2);
1732
2307
  }
1733
2308
  try {
1734
2309
  git(root, ["config", "--remove-section", "merge.vg"]);
@@ -1861,7 +2436,7 @@ function grepBaselineTokens(term, files) {
1861
2436
  if (f.size > 512 * 1024) continue;
1862
2437
  let content = "";
1863
2438
  try {
1864
- content = fs6.readFileSync(f.abs, "utf8");
2439
+ content = fs7.readFileSync(f.abs, "utf8");
1865
2440
  } catch {
1866
2441
  continue;
1867
2442
  }
@@ -1871,7 +2446,7 @@ function grepBaselineTokens(term, files) {
1871
2446
  }
1872
2447
  function safeSize(abs) {
1873
2448
  try {
1874
- return fs6.statSync(abs).size;
2449
+ return fs7.statSync(abs).size;
1875
2450
  } catch {
1876
2451
  return 0;
1877
2452
  }
@@ -2205,7 +2780,7 @@ function loadStandards(root) {
2205
2780
  const p = path__default.join(root, rel3);
2206
2781
  let text;
2207
2782
  try {
2208
- text = fs6__default.readFileSync(p, "utf8");
2783
+ text = fs7__default.readFileSync(p, "utf8");
2209
2784
  } catch {
2210
2785
  continue;
2211
2786
  }
@@ -2443,7 +3018,7 @@ async function addCmd(root, rest, opts, asJson) {
2443
3018
  }
2444
3019
  function readPackageVersion(root) {
2445
3020
  try {
2446
- const pkg = JSON.parse(fs6__default.readFileSync(path__default.join(root, "package.json"), "utf8"));
3021
+ const pkg = JSON.parse(fs7__default.readFileSync(path__default.join(root, "package.json"), "utf8"));
2447
3022
  return typeof pkg.version === "string" ? pkg.version : void 0;
2448
3023
  } catch {
2449
3024
  return void 0;
@@ -2451,7 +3026,7 @@ function readPackageVersion(root) {
2451
3026
  }
2452
3027
  function readOptionalFile(p) {
2453
3028
  try {
2454
- const t = fs6__default.readFileSync(p, "utf8");
3029
+ const t = fs7__default.readFileSync(p, "utf8");
2455
3030
  return t.trim() ? t : void 0;
2456
3031
  } catch {
2457
3032
  return void 0;
@@ -2597,8 +3172,8 @@ function registerExport(program) {
2597
3172
  out(content.trimEnd());
2598
3173
  return;
2599
3174
  }
2600
- fs6.mkdirSync(path.dirname(path.resolve(file)), { recursive: true });
2601
- fs6.writeFileSync(file, content);
3175
+ fs7.mkdirSync(path.dirname(path.resolve(file)), { recursive: true });
3176
+ fs7.writeFileSync(file, content);
2602
3177
  info(`${c.green("\u2714")} wrote ${file} ${c.dim(`(${format})`)}`);
2603
3178
  });
2604
3179
  applyGlobalOptions(cmd);
@@ -2621,24 +3196,24 @@ function registerBundle(program) {
2621
3196
  } catch {
2622
3197
  throw new CliError("no grammars found to bundle (run a build first)", ExitCode.ERROR);
2623
3198
  }
2624
- fs6.mkdirSync(path.join(outDir, "grammars"), { recursive: true });
3199
+ fs7.mkdirSync(path.join(outDir, "grammars"), { recursive: true });
2625
3200
  let grammarCount = 0;
2626
3201
  for (const { fileName, absPath } of grammarFiles) {
2627
- fs6.copyFileSync(absPath, path.join(outDir, "grammars", fileName));
3202
+ fs7.copyFileSync(absPath, path.join(outDir, "grammars", fileName));
2628
3203
  grammarCount++;
2629
3204
  }
2630
3205
  const included = [`grammars/ (${grammarCount} .wasm)`];
2631
3206
  const graphSrc = global.graph ?? defaultGraphPath(root);
2632
- if (fs6.existsSync(graphSrc)) {
2633
- fs6.copyFileSync(graphSrc, path.join(outDir, "graph.json"));
3207
+ if (fs7.existsSync(graphSrc)) {
3208
+ fs7.copyFileSync(graphSrc, path.join(outDir, "graph.json"));
2634
3209
  included.push("graph.json");
2635
3210
  }
2636
3211
  const cat = catalogPath(root);
2637
- if (fs6.existsSync(cat)) {
2638
- fs6.copyFileSync(cat, path.join(outDir, "vibgrate.lib.json"));
3212
+ if (fs7.existsSync(cat)) {
3213
+ fs7.copyFileSync(cat, path.join(outDir, "vibgrate.lib.json"));
2639
3214
  included.push("vibgrate.lib.json");
2640
- if (fs6.existsSync(libDir(root))) {
2641
- fs6.cpSync(libDir(root), path.join(outDir, "lib"), { recursive: true });
3215
+ if (fs7.existsSync(libDir(root))) {
3216
+ fs7.cpSync(libDir(root), path.join(outDir, "lib"), { recursive: true });
2642
3217
  included.push("lib/");
2643
3218
  }
2644
3219
  }
@@ -2650,7 +3225,7 @@ function registerBundle(program) {
2650
3225
  included,
2651
3226
  usage: "Run `vg build --grammars <this dir>/grammars` to build fully offline."
2652
3227
  };
2653
- fs6.writeFileSync(path.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
3228
+ fs7.writeFileSync(path.join(outDir, "MANIFEST.json"), `${stableStringify(manifest, 2)}
2654
3229
  `);
2655
3230
  if (global.json) {
2656
3231
  json({ out: path.relative(root, outDir), ...manifest });
@@ -2675,7 +3250,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
2675
3250
  console.log(chalk8.green("\u2714") + ` Created ${chalk8.bold("vibgrate.config.ts")}`);
2676
3251
  }
2677
3252
  if (opts.baseline) {
2678
- const { runBaseline } = await import('./baseline-SRVG4ZAD.js');
3253
+ const { runBaseline } = await import('./baseline-BTLZWSNS.js');
2679
3254
  await runBaseline(rootDir);
2680
3255
  }
2681
3256
  console.log("");
@@ -2785,9 +3360,9 @@ async function fileReferencesIdentifier(rootDir, relFile, identifier, readFile3)
2785
3360
  }
2786
3361
  async function defaultReadFile(absPath) {
2787
3362
  try {
2788
- const stat2 = await fs12.stat(absPath);
3363
+ const stat2 = await fs13.stat(absPath);
2789
3364
  if (!stat2.isFile() || stat2.size > MAX_FILE_BYTES) return null;
2790
- return await fs12.readFile(absPath, "utf8");
3365
+ return await fs13.readFile(absPath, "utf8");
2791
3366
  } catch {
2792
3367
  return null;
2793
3368
  }
@@ -3058,7 +3633,9 @@ async function autoPush(artifact, rootDir, opts) {
3058
3633
  if (opts.strict) process.exit(1);
3059
3634
  return;
3060
3635
  }
3061
- const { body, contentEncoding } = await prepareCompressedUpload(artifact);
3636
+ const config = await loadConfig(rootDir);
3637
+ const databaseSchemaCaps = config.scanners !== false ? config.scanners?.databaseSchema : void 0;
3638
+ const { body, contentEncoding } = await prepareCompressedUpload(artifact, { databaseSchemaCaps });
3062
3639
  const timestamp = String(Date.now());
3063
3640
  let host = parsed.host;
3064
3641
  if (opts.region) {
@@ -3083,7 +3660,11 @@ async function autoPush(artifact, rootDir, opts) {
3083
3660
  body,
3084
3661
  contentEncoding,
3085
3662
  timestamp,
3086
- force: opts.force
3663
+ force: opts.force,
3664
+ // Set only by an automated caller running the scan on the workspace's
3665
+ // behalf (e.g. a Vibgrate-hosted remediation run) — never a customer flag.
3666
+ runId: process.env.VIBGRATE_SCAN_RUN_ID,
3667
+ runToken: process.env.VIBGRATE_SCAN_RUN_TOKEN
3087
3668
  });
3088
3669
  host = uploadedHost;
3089
3670
  if (!response.ok) {
@@ -3158,7 +3739,7 @@ var scanCommand = new Command("scan").description("Scan a project for upgrade dr
3158
3739
  'Exclude paths matching a glob pattern. Repeatable, and a single value may list several patterns separated by commas or semicolons (e.g. --exclude "legacy/**,vendor/**"). Merged with excludes from the config file.',
3159
3740
  collectExcludes,
3160
3741
  []
3161
- ).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 drift score 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) => {
3742
+ ).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) => {
3162
3743
  const rootDir = path.resolve(targetPath);
3163
3744
  if (!await pathExists$1(rootDir)) {
3164
3745
  console.error(chalk8.red(`Path does not exist: ${rootDir}`));
@@ -3332,7 +3913,7 @@ Failing: findings detected at warn level or above.`));
3332
3913
  }
3333
3914
  if (scanOpts.driftBudget !== void 0 && artifact.drift.score > scanOpts.driftBudget) {
3334
3915
  console.error(chalk8.red(`
3335
- Failing fitness function: drift score ${artifact.drift.score}/100 exceeds budget ${scanOpts.driftBudget}.`));
3916
+ Failing fitness function: DriftScore ${artifact.drift.score}/100 exceeds budget ${scanOpts.driftBudget}.`));
3336
3917
  process.exit(2);
3337
3918
  }
3338
3919
  if (scanOpts.driftWorseningPercent !== void 0) {
@@ -3426,7 +4007,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
3426
4007
  function scanStaleness(rootDir, artifactPath) {
3427
4008
  let ref;
3428
4009
  try {
3429
- ref = fs6.statSync(artifactPath).mtimeMs;
4010
+ ref = fs7.statSync(artifactPath).mtimeMs;
3430
4011
  } catch {
3431
4012
  return { stale: false };
3432
4013
  }
@@ -3438,7 +4019,7 @@ function scanStaleness(rootDir, artifactPath) {
3438
4019
  if (depth > 8 || scanned > MAX_ENTRIES) return;
3439
4020
  let entries;
3440
4021
  try {
3441
- entries = fs6.readdirSync(dir, { withFileTypes: true });
4022
+ entries = fs7.readdirSync(dir, { withFileTypes: true });
3442
4023
  } catch {
3443
4024
  return;
3444
4025
  }
@@ -3453,7 +4034,7 @@ function scanStaleness(rootDir, artifactPath) {
3453
4034
  const abs = path.join(dir, e.name);
3454
4035
  let mtimeMs;
3455
4036
  try {
3456
- mtimeMs = fs6.statSync(abs).mtimeMs;
4037
+ mtimeMs = fs7.statSync(abs).mtimeMs;
3457
4038
  } catch {
3458
4039
  continue;
3459
4040
  }
@@ -3587,7 +4168,7 @@ function analyzeTree(root, packages) {
3587
4168
  if (depth > MAX_DEPTH || filesSeen >= MAX_FILES) return;
3588
4169
  let entries;
3589
4170
  try {
3590
- entries = fs6.readdirSync(dir, { withFileTypes: true });
4171
+ entries = fs7.readdirSync(dir, { withFileTypes: true });
3591
4172
  } catch {
3592
4173
  return;
3593
4174
  }
@@ -3605,8 +4186,8 @@ function analyzeTree(root, packages) {
3605
4186
  const full = path.join(dir, entry.name);
3606
4187
  let content;
3607
4188
  try {
3608
- if (fs6.statSync(full).size > MAX_FILE_BYTES2) continue;
3609
- content = fs6.readFileSync(full, "utf8");
4189
+ if (fs7.statSync(full).size > MAX_FILE_BYTES2) continue;
4190
+ content = fs7.readFileSync(full, "utf8");
3610
4191
  } catch {
3611
4192
  continue;
3612
4193
  }
@@ -3797,6 +4378,11 @@ function estimateDriftScore(artifact, upgraded) {
3797
4378
  for (const dep of p.dependencies ?? []) {
3798
4379
  if (!upgraded.has(dep.package)) continue;
3799
4380
  const mb3 = dep.majorsBehind ?? 0;
4381
+ dep.majorsBehind = 0;
4382
+ dep.drift = "current";
4383
+ if (dep.libyears != null) dep.libyears = 0;
4384
+ if (dep.ageDays != null) dep.ageDays = 0;
4385
+ if (dep.latestStable) dep.resolvedVersion = dep.latestStable;
3800
4386
  if (mb3 >= 2 && buckets.twoPlusBehind > 0) {
3801
4387
  buckets.twoPlusBehind--;
3802
4388
  buckets.current++;
@@ -3940,8 +4526,8 @@ async function fetchLatestVersion() {
3940
4526
  }
3941
4527
  async function writeCache(data) {
3942
4528
  try {
3943
- await fs12.mkdir(CACHE_DIR, { recursive: true });
3944
- await fs12.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
4529
+ await fs13.mkdir(CACHE_DIR, { recursive: true });
4530
+ await fs13.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
3945
4531
  } catch {
3946
4532
  }
3947
4533
  }
@@ -4018,11 +4604,11 @@ async function isDevDependency(cwd) {
4018
4604
  async function confirmWorkspaceRoot(pm) {
4019
4605
  if (!(process.stdin.isTTY && process.stdout.isTTY)) return false;
4020
4606
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4021
- return new Promise((resolve16) => {
4607
+ return new Promise((resolve17) => {
4022
4608
  rl.question(chalk8.yellow(`Update the ${pm} workspace root with -w? [y/N]: `), (ans) => {
4023
4609
  rl.close();
4024
4610
  const t = ans.trim().toLowerCase();
4025
- resolve16(t === "y" || t === "yes");
4611
+ resolve17(t === "y" || t === "yes");
4026
4612
  });
4027
4613
  });
4028
4614
  }
@@ -4150,7 +4736,7 @@ async function repositoryIdentity(rootDir, override) {
4150
4736
  return { name: override?.trim() || void 0 };
4151
4737
  }
4152
4738
  }
4153
- var fixCommand = new Command("fix").description("Analyse drift and get ranked, risk-tiered upgrade plans from the hosted planner (requires login/DSN; read-only \u2014 never edits your project)").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) => {
4739
+ 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) => {
4154
4740
  const rootDir = path.resolve(targetPath);
4155
4741
  if (!await pathExists(rootDir)) {
4156
4742
  console.error(chalk8.red(`Path does not exist: ${rootDir}`));
@@ -4349,14 +4935,14 @@ function promptPlanSelection(response) {
4349
4935
  const defaultIdx = plans.findIndex((p) => p.tier === response.recommended);
4350
4936
  const def = defaultIdx >= 0 ? defaultIdx + 1 : 1;
4351
4937
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
4352
- return new Promise((resolve16) => {
4938
+ return new Promise((resolve17) => {
4353
4939
  rl.question(`Plan [1-${plans.length}, default ${def}, q to cancel]: `, (ans) => {
4354
4940
  rl.close();
4355
4941
  const t = ans.trim().toLowerCase();
4356
- if (t === "q" || t === "quit") return resolve16(null);
4942
+ if (t === "q" || t === "quit") return resolve17(null);
4357
4943
  const n = t === "" ? def : Number.parseInt(t, 10);
4358
- if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve16(null);
4359
- resolve16(plans[n - 1].tier);
4944
+ if (!Number.isInteger(n) || n < 1 || n > plans.length) return resolve17(null);
4945
+ resolve17(plans[n - 1].tier);
4360
4946
  });
4361
4947
  });
4362
4948
  }
@@ -4727,6 +5313,26 @@ function formatExtended(ext) {
4727
5313
  }
4728
5314
  lines.push("");
4729
5315
  }
5316
+ if (ext.databaseSchema) {
5317
+ const ds = ext.databaseSchema;
5318
+ lines.push(chalk8.bold.underline(" Database Schema"));
5319
+ const dsHead = [];
5320
+ if (ds.providers.length > 0) dsHead.push(ds.providers.join(", "));
5321
+ dsHead.push(`${ds.models.length} model${ds.models.length !== 1 ? "s" : ""}`);
5322
+ dsHead.push(`${ds.enums.length} enum${ds.enums.length !== 1 ? "s" : ""}`);
5323
+ lines.push(` ${dsHead.join(" \xB7 ")}`);
5324
+ const bySource = /* @__PURE__ */ new Map();
5325
+ for (const m of ds.models) bySource.set(m.source, (bySource.get(m.source) ?? 0) + 1);
5326
+ if (bySource.size > 1) {
5327
+ const sourceSummary = [...bySource.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([s, n]) => `${s}: ${n}`).join(", ");
5328
+ lines.push(` Sources: ${sourceSummary}`);
5329
+ }
5330
+ if (ds.models.length > 0) {
5331
+ const preview = ds.models.slice(0, 5).map((m) => m.name).join(", ");
5332
+ lines.push(` Models: ${chalk8.white(preview)}${ds.models.length > 5 ? chalk8.dim(` (+${ds.models.length - 5} more)`) : ""}`);
5333
+ }
5334
+ lines.push("");
5335
+ }
4730
5336
  if (ext.dependencyGraph) {
4731
5337
  const dg = ext.dependencyGraph;
4732
5338
  if (dg.lockfileType) {
@@ -5168,7 +5774,7 @@ function openUrl(url) {
5168
5774
  }
5169
5775
 
5170
5776
  // src/reporting/commands/login.ts
5171
- var delay = (ms) => new Promise((resolve16) => setTimeout(resolve16, ms));
5777
+ var delay = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
5172
5778
  function isInside(dir, file) {
5173
5779
  const rel3 = path.relative(dir, file);
5174
5780
  return !!rel3 && !rel3.startsWith("..") && !path.isAbsolute(rel3);
@@ -5615,7 +6221,7 @@ function formatDeltaText(base, current) {
5615
6221
  "===================",
5616
6222
  `Baseline: ${base.timestamp}`,
5617
6223
  `Current: ${current.timestamp}`,
5618
- `Drift score delta: ${(current.drift.score - base.drift.score).toFixed(2)} points`,
6224
+ `DriftScore delta: ${(current.drift.score - base.drift.score).toFixed(2)} points`,
5619
6225
  "",
5620
6226
  `Added dependencies (${added.length})`,
5621
6227
  ...added.map((d) => ` + ${d}`),
@@ -5693,6 +6299,7 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
5693
6299
  "areas",
5694
6300
  "oddities",
5695
6301
  "serve",
6302
+ "lsp",
5696
6303
  "install",
5697
6304
  "uninstall",
5698
6305
  "share",
@@ -5733,6 +6340,7 @@ ${aliasNote}Docs: https://vibgrate.com/help`;
5733
6340
  registerImpact(program);
5734
6341
  registerUnknowns(program);
5735
6342
  registerServe(program);
6343
+ registerLsp(program);
5736
6344
  registerInstall(program);
5737
6345
  registerShare(program);
5738
6346
  registerBenchmark(program);
@@ -5814,7 +6422,7 @@ function dispatch(argv, cwd) {
5814
6422
  }
5815
6423
  const looksLikeQuestion = /\s/.test(first) || first.endsWith("?");
5816
6424
  if (looksLikeQuestion) return ["ask", ...args];
5817
- if (fs6.existsSync(path.resolve(cwd, first))) {
6425
+ if (fs7.existsSync(path.resolve(cwd, first))) {
5818
6426
  return [hasBuildOnlyFlag(args) ? "build" : "scan", ...args];
5819
6427
  }
5820
6428
  const moved = MOVED_COMMANDS[first];