@vibgrate/cli 2026.729.2 → 2026.730.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.
Files changed (107) hide show
  1. package/DOCS.md +5 -1
  2. package/dist/agent-33BMKWJC.js +22 -0
  3. package/dist/agent-33BMKWJC.js.map +1 -0
  4. package/dist/baseline-V6MYDEMS.js +9 -0
  5. package/dist/{baseline-UOTGTJYT.js.map → baseline-V6MYDEMS.js.map} +1 -1
  6. package/dist/checkpoint-4WFZMKEO.js +56 -0
  7. package/dist/checkpoint-4WFZMKEO.js.map +1 -0
  8. package/dist/chunk-543E6WDJ.js +61 -0
  9. package/dist/chunk-543E6WDJ.js.map +1 -0
  10. package/dist/{chunk-P3QIO4ZU.js → chunk-5G7C6H2G.js} +14 -204
  11. package/dist/chunk-5G7C6H2G.js.map +1 -0
  12. package/dist/{chunk-JIBOJTGS.js → chunk-5HYCB55P.js} +101 -101
  13. package/dist/chunk-5HYCB55P.js.map +1 -0
  14. package/dist/{chunk-67YG3R5F.js → chunk-6D4BCGRQ.js} +6 -62
  15. package/dist/chunk-6D4BCGRQ.js.map +1 -0
  16. package/dist/{chunk-F6ZPUKED.js → chunk-6WNJJXFY.js} +4 -4
  17. package/dist/{chunk-F6ZPUKED.js.map → chunk-6WNJJXFY.js.map} +1 -1
  18. package/dist/{chunk-PXXVLX7K.js → chunk-CFL3QQQZ.js} +7 -6
  19. package/dist/chunk-CFL3QQQZ.js.map +1 -0
  20. package/dist/{chunk-74ZMAOVF.js → chunk-CQDCZQFV.js} +55 -9
  21. package/dist/chunk-CQDCZQFV.js.map +1 -0
  22. package/dist/{chunk-VZRQUI54.js → chunk-DBMYWNLC.js} +4 -4
  23. package/dist/{chunk-VZRQUI54.js.map → chunk-DBMYWNLC.js.map} +1 -1
  24. package/dist/{chunk-QDZ47G45.js → chunk-EKCNSRNJ.js} +20 -11
  25. package/dist/chunk-EKCNSRNJ.js.map +1 -0
  26. package/dist/{chunk-SIPGDJT4.js → chunk-EVLS2M5G.js} +4 -4
  27. package/dist/{chunk-SIPGDJT4.js.map → chunk-EVLS2M5G.js.map} +1 -1
  28. package/dist/{chunk-G4HTI4ZM.js → chunk-FHJBGPJZ.js} +3 -2
  29. package/dist/chunk-FHJBGPJZ.js.map +1 -0
  30. package/dist/{chunk-CYC3ZI32.js → chunk-GLT3N7T2.js} +9 -6
  31. package/dist/chunk-GLT3N7T2.js.map +1 -0
  32. package/dist/chunk-HTLDXEHW.js +60 -0
  33. package/dist/chunk-HTLDXEHW.js.map +1 -0
  34. package/dist/{chunk-GI6W53LM.js → chunk-IDAQV3NQ.js} +4 -2
  35. package/dist/chunk-IDAQV3NQ.js.map +1 -0
  36. package/dist/{chunk-2ZHWF7C6.js → chunk-KGWEBM2J.js} +43 -68
  37. package/dist/chunk-KGWEBM2J.js.map +1 -0
  38. package/dist/{chunk-RZEXHDCF.js → chunk-MYM5VIJ4.js} +14 -3
  39. package/dist/chunk-MYM5VIJ4.js.map +1 -0
  40. package/dist/{chunk-HDQG3QYV.js → chunk-ON7PZNYV.js} +42 -26
  41. package/dist/chunk-ON7PZNYV.js.map +1 -0
  42. package/dist/chunk-Q4UQ73NA.js +6 -0
  43. package/dist/{chunk-WQE4OIZS.js.map → chunk-Q4UQ73NA.js.map} +1 -1
  44. package/dist/{chunk-PMYWZRRS.js → chunk-RBIRXQR6.js} +21 -3
  45. package/dist/chunk-RBIRXQR6.js.map +1 -0
  46. package/dist/{chunk-TCJTQGAO.js → chunk-RGEVBSLK.js} +3 -3
  47. package/dist/{chunk-TCJTQGAO.js.map → chunk-RGEVBSLK.js.map} +1 -1
  48. package/dist/chunk-TJ3WIJ7H.js +216 -0
  49. package/dist/chunk-TJ3WIJ7H.js.map +1 -0
  50. package/dist/chunk-VOEYUAER.js +203 -0
  51. package/dist/chunk-VOEYUAER.js.map +1 -0
  52. package/dist/{chunk-PRGCCW7D.js → chunk-WBMMRERH.js} +3 -3
  53. package/dist/{chunk-PRGCCW7D.js.map → chunk-WBMMRERH.js.map} +1 -1
  54. package/dist/{chunk-6HX47EBL.js → chunk-X634FZVG.js} +3 -3
  55. package/dist/{chunk-6HX47EBL.js.map → chunk-X634FZVG.js.map} +1 -1
  56. package/dist/cli.js +563 -340
  57. package/dist/cli.js.map +1 -1
  58. package/dist/{fs-6JKZNQ3U.js → fs-HNR6LAI7.js} +3 -3
  59. package/dist/fs-HNR6LAI7.js.map +1 -0
  60. package/dist/{graph-backend-GBL33GMW.js → graph-backend-G5Y6QQV4.js} +4 -4
  61. package/dist/{graph-backend-GBL33GMW.js.map → graph-backend-G5Y6QQV4.js.map} +1 -1
  62. package/dist/index.d.ts +1 -1
  63. package/dist/index.js +12 -10
  64. package/dist/index.js.map +1 -1
  65. package/dist/{interactive-HLGJJFLI.js → interactive-NJG6467J.js} +27 -24
  66. package/dist/interactive-NJG6467J.js.map +1 -0
  67. package/dist/{llm-host-5RE34322.js → llm-host-DZBD5D36.js} +5 -5
  68. package/dist/{llm-host-5RE34322.js.map → llm-host-DZBD5D36.js.map} +1 -1
  69. package/dist/load-YPSEDYIW.js +10 -0
  70. package/dist/{load-4MLIHGXF.js.map → load-YPSEDYIW.js.map} +1 -1
  71. package/dist/rules-ASYEUNB5.js +74 -0
  72. package/dist/rules-ASYEUNB5.js.map +1 -0
  73. package/dist/run-outcome-5FQWHWYK.js +253 -0
  74. package/dist/run-outcome-5FQWHWYK.js.map +1 -0
  75. package/dist/runtime-session-Y4ZD3QDO.js +20 -0
  76. package/dist/{runtime-session-5M6QZZOS.js.map → runtime-session-Y4ZD3QDO.js.map} +1 -1
  77. package/dist/{session-2JT4AUZT.js → session-3OBIQLE4.js} +5 -5
  78. package/dist/{session-2JT4AUZT.js.map → session-3OBIQLE4.js.map} +1 -1
  79. package/dist/{stream-json-Y45JBNYP.js → stream-json-3YOPU3LF.js} +82 -10
  80. package/dist/stream-json-3YOPU3LF.js.map +1 -0
  81. package/dist/{vg-mcp-bridge-ZCKBYQ2D.js → vg-mcp-bridge-PZFGTZSA.js} +8 -7
  82. package/dist/vg-mcp-bridge-PZFGTZSA.js.map +1 -0
  83. package/dist/{vgd-TGGEAGQZ.js → vgd-DH7AHQ23.js} +9 -8
  84. package/dist/vgd-DH7AHQ23.js.map +1 -0
  85. package/package.json +1 -1
  86. package/dist/baseline-UOTGTJYT.js +0 -9
  87. package/dist/chunk-2ZHWF7C6.js.map +0 -1
  88. package/dist/chunk-67YG3R5F.js.map +0 -1
  89. package/dist/chunk-74ZMAOVF.js.map +0 -1
  90. package/dist/chunk-CYC3ZI32.js.map +0 -1
  91. package/dist/chunk-G4HTI4ZM.js.map +0 -1
  92. package/dist/chunk-GI6W53LM.js.map +0 -1
  93. package/dist/chunk-HDQG3QYV.js.map +0 -1
  94. package/dist/chunk-JIBOJTGS.js.map +0 -1
  95. package/dist/chunk-P3QIO4ZU.js.map +0 -1
  96. package/dist/chunk-PMYWZRRS.js.map +0 -1
  97. package/dist/chunk-PXXVLX7K.js.map +0 -1
  98. package/dist/chunk-QDZ47G45.js.map +0 -1
  99. package/dist/chunk-RZEXHDCF.js.map +0 -1
  100. package/dist/chunk-WQE4OIZS.js +0 -6
  101. package/dist/fs-6JKZNQ3U.js.map +0 -1
  102. package/dist/interactive-HLGJJFLI.js.map +0 -1
  103. package/dist/load-4MLIHGXF.js +0 -9
  104. package/dist/runtime-session-5M6QZZOS.js +0 -19
  105. package/dist/stream-json-Y45JBNYP.js.map +0 -1
  106. package/dist/vg-mcp-bridge-ZCKBYQ2D.js.map +0 -1
  107. package/dist/vgd-TGGEAGQZ.js.map +0 -1
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var VERSION = "2026.730.1";
3
+
4
+ export { VERSION };
5
+ //# sourceMappingURL=chunk-Q4UQ73NA.js.map
6
+ //# sourceMappingURL=chunk-Q4UQ73NA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AACO,IAAM,OAAA,GAAU","file":"chunk-WQE4OIZS.js","sourcesContent":["// Calendar version (YYYY.DDD.PATCH), shared scheme with @vibgrate/cli.\nexport const VERSION = '2026.729.2';\n"]}
1
+ {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AACO,IAAM,OAAA,GAAU","file":"chunk-Q4UQ73NA.js","sourcesContent":["// Calendar version (YYYY.DDD.PATCH), shared scheme with @vibgrate/cli.\nexport const VERSION = '2026.730.1';\n"]}
@@ -11,9 +11,27 @@ function vgdSocketPath(env = process.env, platform = process.platform) {
11
11
  function vgdPidPath(env = process.env, platform = process.platform) {
12
12
  return path.join(daemonDir(env, platform), "vgd.pid");
13
13
  }
14
+ function defaultVgdTimeoutMs(op) {
15
+ switch (op) {
16
+ case "ping":
17
+ case "status":
18
+ return 2e3;
19
+ // liveness probes — fail fast
20
+ case "put-graph":
21
+ case "load-graph":
22
+ case "host-load":
23
+ return 12e4;
24
+ // large payload / disk load / model load
25
+ case "host-generate":
26
+ return 3e5;
27
+ // local model generation
28
+ default:
29
+ return 1e4;
30
+ }
31
+ }
14
32
  function vgdRequest(request, options = {}) {
15
33
  const socketPath = options.socketPath ?? vgdSocketPath();
16
- const timeoutMs = options.timeoutMs ?? 2e3;
34
+ const timeoutMs = options.timeoutMs ?? defaultVgdTimeoutMs(request.op);
17
35
  return new Promise((resolve, reject) => {
18
36
  const socket = net.createConnection(socketPath);
19
37
  let settled = false;
@@ -58,5 +76,5 @@ async function vgdIsRunning(options = {}) {
58
76
  }
59
77
 
60
78
  export { vgdIsRunning, vgdPidPath, vgdRequest, vgdSocketPath };
61
- //# sourceMappingURL=chunk-PMYWZRRS.js.map
62
- //# sourceMappingURL=chunk-PMYWZRRS.js.map
79
+ //# sourceMappingURL=chunk-RBIRXQR6.js.map
80
+ //# sourceMappingURL=chunk-RBIRXQR6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/vgd/paths.ts","../src/runtime/vgd/client.ts"],"names":[],"mappings":"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","file":"chunk-RBIRXQR6.js","sourcesContent":["import * as path from 'node:path';\nimport { daemonDir } from '../paths.js';\n\n/** Socket (or named-pipe) path for the local vgd instance. */\nexport function vgdSocketPath(env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string {\n if (platform === 'win32') {\n return path.join('\\\\\\\\.\\\\pipe', 'vibgrate-vgd');\n }\n return path.join(daemonDir(env, platform), 'vgd.sock');\n}\n\n/** PID file for quick status without a round-trip (Unix). */\nexport function vgdPidPath(env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string {\n return path.join(daemonDir(env, platform), 'vgd.pid');\n}\n","import * as net from 'node:net';\nimport type { VgdRequest, VgdResponse } from './protocol.js';\nimport { vgdSocketPath } from './paths.js';\n\nexport interface VgdClientOptions {\n socketPath?: string;\n /** End-to-end response timeout in ms (default: per-op, see {@link defaultVgdTimeoutMs}). */\n timeoutMs?: number;\n}\n\n/**\n * Default response timeout per operation.\n *\n * The timer spans the whole round trip — writing the request, the daemon\n * handling it, and the reply. Liveness probes must fail fast, but a flat 2s\n * default guaranteed false \"vgd did not respond\" failures on large repos:\n * `put-graph` ships the entire code map as one JSON line (tens of MB for a\n * 40k-file workspace), and the single-threaded daemon needs seconds to read\n * and store it. Ops that ride on a busy daemon's event loop get headroom too.\n */\nexport function defaultVgdTimeoutMs(op: VgdRequest['op']): number {\n switch (op) {\n case 'ping':\n case 'status':\n return 2000; // liveness probes — fail fast\n case 'put-graph':\n case 'load-graph':\n case 'host-load':\n return 120_000; // large payload / disk load / model load\n case 'host-generate':\n return 300_000; // local model generation\n default:\n return 10_000; // registry + graph queries — may queue behind a put-graph\n }\n}\n\n/**\n * Send one request to a running vgd and return the parsed response.\n * Rejects if the daemon is not reachable.\n */\nexport function vgdRequest(request: VgdRequest, options: VgdClientOptions = {}): Promise<VgdResponse> {\n const socketPath = options.socketPath ?? vgdSocketPath();\n const timeoutMs = options.timeoutMs ?? defaultVgdTimeoutMs(request.op);\n\n return new Promise((resolve, reject) => {\n const socket = net.createConnection(socketPath);\n let settled = false;\n let buffer = '';\n\n const finish = (err?: Error, value?: VgdResponse): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n socket.destroy();\n if (err) reject(err);\n else resolve(value!);\n };\n\n const timer = setTimeout(() => finish(new Error(`vgd did not respond within ${timeoutMs}ms`)), timeoutMs);\n\n socket.setEncoding('utf8');\n socket.on('connect', () => {\n socket.write(JSON.stringify(request) + '\\n');\n });\n socket.on('data', (chunk: string) => {\n buffer += chunk;\n const nl = buffer.indexOf('\\n');\n if (nl < 0) return;\n const line = buffer.slice(0, nl).trim();\n try {\n finish(undefined, JSON.parse(line) as VgdResponse);\n } catch (e) {\n finish(e instanceof Error ? e : new Error(String(e)));\n }\n });\n socket.on('error', (err) => finish(err));\n socket.on('end', () => {\n if (!settled) finish(new Error('vgd closed the connection before responding'));\n });\n });\n}\n\n/** True when a local vgd answers ping. */\nexport async function vgdIsRunning(options: VgdClientOptions = {}): Promise<boolean> {\n try {\n const res = await vgdRequest({ op: 'ping' }, options);\n return res.ok === true && 'pong' in res && res.pong === true;\n } catch {\n return false;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { vgdRequest } from './chunk-PMYWZRRS.js';
1
+ import { vgdRequest } from './chunk-RBIRXQR6.js';
2
2
  import { resolveOne } from './chunk-J7LKEB2R.js';
3
3
  import { impactOf, queryGraph } from './chunk-EETK7S43.js';
4
4
 
@@ -132,5 +132,5 @@ function resolveSymbolId(graph, symbol) {
132
132
  }
133
133
 
134
134
  export { localGraphBackend, resolveGraphBackend, vgdGraphBackend };
135
- //# sourceMappingURL=chunk-TCJTQGAO.js.map
136
- //# sourceMappingURL=chunk-TCJTQGAO.js.map
135
+ //# sourceMappingURL=chunk-RGEVBSLK.js.map
136
+ //# sourceMappingURL=chunk-RGEVBSLK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/code/graph-backend.ts"],"names":[],"mappings":"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","file":"chunk-TCJTQGAO.js","sourcesContent":["/**\n * Graph query backend for the agent tool layer (Fusion Runtime).\n *\n * Tools prefer a warm ActiveGraph in vgd when a daemon session is attached;\n * otherwise they fall back to the in-process {@link VgGraph}. Failures never\n * surface to the model as transport errors — they degrade to local query.\n */\n\nimport { queryGraph } from '../engine/query.js';\nimport { impactOf } from '../engine/impact.js';\nimport { resolveOne } from '../engine/lookup.js';\nimport { vgdRequest, type VgdClientOptions } from '../runtime/vgd/client.js';\nimport type { VgdRequest } from '../runtime/vgd/protocol.js';\nimport type { VgGraph } from '../schema.js';\n\nexport type GraphBackendSource = 'local' | 'vgd';\n\nexport interface GraphSearchHit {\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n signature?: string | null;\n}\n\nexport interface GraphImpactHit {\n id: string;\n name: string;\n kind: string;\n file: string;\n line: number;\n depth: number;\n confidence: number;\n}\n\nexport interface GraphImpactResult {\n root: { id: string; name: string };\n depth: number;\n affected: GraphImpactHit[];\n direct: number;\n transitive: number;\n source: GraphBackendSource;\n}\n\nexport interface GraphSearchResult {\n matches: GraphSearchHit[];\n source: GraphBackendSource;\n}\n\nexport interface GraphBackend {\n readonly source: GraphBackendSource;\n search(query: string, opts?: { limit?: number }): Promise<GraphSearchResult>;\n impact(symbol: string, opts?: { depth?: number }): Promise<GraphImpactResult | null>;\n}\n\n/** Pure in-process backend over a loaded graph. */\nexport function localGraphBackend(graph: VgGraph): GraphBackend {\n return {\n source: 'local',\n async search(query, opts) {\n const res = queryGraph(graph, query, { budget: 1500, limit: opts?.limit ?? 10 });\n return {\n source: 'local',\n matches: res.matches.map((m) => ({\n id: m.node.id,\n qualifiedName: m.node.qualifiedName,\n kind: m.node.kind,\n file: m.node.file,\n line: m.node.span?.start ?? 0,\n score: m.score,\n why: m.why,\n signature: m.node.signature ?? null,\n })),\n };\n },\n async impact(symbol, opts) {\n const node = resolveSymbolId(graph, symbol);\n if (!node) return null;\n const imp = impactOf(graph, node, { depth: opts?.depth ?? 4 });\n return {\n source: 'local',\n root: imp.root,\n depth: imp.depth,\n affected: imp.affected.map((a) => ({\n id: a.id,\n name: a.name,\n kind: a.kind,\n file: a.file,\n line: a.line,\n depth: a.depth,\n confidence: a.confidence,\n })),\n direct: imp.direct,\n transitive: imp.transitive,\n };\n },\n };\n}\n\nexport interface VgdGraphBackendOptions {\n repositoryId: string;\n gitRef?: string;\n socketPath?: string;\n /** Always required for fall back when vgd has no slot or is down. */\n fallback: VgGraph;\n request?: (req: VgdRequest, opts?: VgdClientOptions) => Promise<unknown>;\n}\n\n/**\n * Prefer vgd query/impact; on any failure or empty daemon state, use local.\n * The returned `source` reflects which path answered.\n */\nexport function vgdGraphBackend(options: VgdGraphBackendOptions): GraphBackend {\n const local = localGraphBackend(options.fallback);\n const request = options.request ?? ((req, opts) => vgdRequest(req, opts));\n const clientOpts: VgdClientOptions = { socketPath: options.socketPath };\n\n return {\n source: 'vgd',\n async search(query, opts) {\n try {\n const res = (await request(\n {\n op: 'query-graph',\n repositoryId: options.repositoryId,\n query,\n limit: opts?.limit ?? 10,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n matches?: Array<{\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n }>;\n };\n if (res?.ok && Array.isArray(res.matches)) {\n return {\n source: 'vgd',\n matches: res.matches.map((m) => ({\n id: m.id,\n qualifiedName: m.qualifiedName,\n kind: m.kind,\n file: m.file,\n line: m.line,\n score: m.score,\n why: m.why,\n signature: null,\n })),\n };\n }\n } catch {\n /* fall through */\n }\n return local.search(query, opts);\n },\n async impact(symbol, opts) {\n try {\n const res = (await request(\n {\n op: 'impact-of',\n repositoryId: options.repositoryId,\n symbol,\n depth: opts?.depth ?? 4,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n root?: { id: string; name: string };\n depth?: number;\n affected?: GraphImpactHit[];\n direct?: number;\n transitive?: number;\n };\n if (res?.ok && res.root && Array.isArray(res.affected)) {\n return {\n source: 'vgd',\n root: res.root,\n depth: res.depth ?? opts?.depth ?? 4,\n affected: res.affected,\n direct: res.direct ?? 0,\n transitive: res.transitive ?? 0,\n };\n }\n } catch {\n /* fall through */\n }\n return local.impact(symbol, opts);\n },\n };\n}\n\n/**\n * Pick a backend: vgd when repositoryId + socket are known, else local.\n */\nexport function resolveGraphBackend(input: {\n graph: VgGraph;\n repositoryId?: string | null;\n gitRef?: string | null;\n socketPath?: string | null;\n}): GraphBackend {\n if (input.repositoryId && input.socketPath) {\n return vgdGraphBackend({\n repositoryId: input.repositoryId,\n gitRef: input.gitRef ?? undefined,\n socketPath: input.socketPath,\n fallback: input.graph,\n });\n }\n return localGraphBackend(input.graph);\n}\n\nfunction resolveSymbolId(graph: VgGraph, symbol: string): string | null {\n if (graph.nodes.some((n) => n.id === symbol)) return symbol;\n const hit = resolveOne(graph, symbol);\n if (hit.node?.id) return hit.node.id;\n if (hit.candidates.length === 1 && hit.candidates[0]?.id) return hit.candidates[0].id;\n const q = symbol.toLowerCase();\n const byQn = graph.nodes.find((n) => n.qualifiedName?.toLowerCase() === q || n.name?.toLowerCase() === q);\n return byQn?.id ?? null;\n}\n"]}
1
+ {"version":3,"sources":["../src/code/graph-backend.ts"],"names":[],"mappings":"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","file":"chunk-RGEVBSLK.js","sourcesContent":["/**\n * Graph query backend for the agent tool layer (Fusion Runtime).\n *\n * Tools prefer a warm ActiveGraph in vgd when a daemon session is attached;\n * otherwise they fall back to the in-process {@link VgGraph}. Failures never\n * surface to the model as transport errors — they degrade to local query.\n */\n\nimport { queryGraph } from '../engine/query.js';\nimport { impactOf } from '../engine/impact.js';\nimport { resolveOne } from '../engine/lookup.js';\nimport { vgdRequest, type VgdClientOptions } from '../runtime/vgd/client.js';\nimport type { VgdRequest } from '../runtime/vgd/protocol.js';\nimport type { VgGraph } from '../schema.js';\n\nexport type GraphBackendSource = 'local' | 'vgd';\n\nexport interface GraphSearchHit {\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n signature?: string | null;\n}\n\nexport interface GraphImpactHit {\n id: string;\n name: string;\n kind: string;\n file: string;\n line: number;\n depth: number;\n confidence: number;\n}\n\nexport interface GraphImpactResult {\n root: { id: string; name: string };\n depth: number;\n affected: GraphImpactHit[];\n direct: number;\n transitive: number;\n source: GraphBackendSource;\n}\n\nexport interface GraphSearchResult {\n matches: GraphSearchHit[];\n source: GraphBackendSource;\n}\n\nexport interface GraphBackend {\n readonly source: GraphBackendSource;\n search(query: string, opts?: { limit?: number }): Promise<GraphSearchResult>;\n impact(symbol: string, opts?: { depth?: number }): Promise<GraphImpactResult | null>;\n}\n\n/** Pure in-process backend over a loaded graph. */\nexport function localGraphBackend(graph: VgGraph): GraphBackend {\n return {\n source: 'local',\n async search(query, opts) {\n const res = queryGraph(graph, query, { budget: 1500, limit: opts?.limit ?? 10 });\n return {\n source: 'local',\n matches: res.matches.map((m) => ({\n id: m.node.id,\n qualifiedName: m.node.qualifiedName,\n kind: m.node.kind,\n file: m.node.file,\n line: m.node.span?.start ?? 0,\n score: m.score,\n why: m.why,\n signature: m.node.signature ?? null,\n })),\n };\n },\n async impact(symbol, opts) {\n const node = resolveSymbolId(graph, symbol);\n if (!node) return null;\n const imp = impactOf(graph, node, { depth: opts?.depth ?? 4 });\n return {\n source: 'local',\n root: imp.root,\n depth: imp.depth,\n affected: imp.affected.map((a) => ({\n id: a.id,\n name: a.name,\n kind: a.kind,\n file: a.file,\n line: a.line,\n depth: a.depth,\n confidence: a.confidence,\n })),\n direct: imp.direct,\n transitive: imp.transitive,\n };\n },\n };\n}\n\nexport interface VgdGraphBackendOptions {\n repositoryId: string;\n gitRef?: string;\n socketPath?: string;\n /** Always required for fall back when vgd has no slot or is down. */\n fallback: VgGraph;\n request?: (req: VgdRequest, opts?: VgdClientOptions) => Promise<unknown>;\n}\n\n/**\n * Prefer vgd query/impact; on any failure or empty daemon state, use local.\n * The returned `source` reflects which path answered.\n */\nexport function vgdGraphBackend(options: VgdGraphBackendOptions): GraphBackend {\n const local = localGraphBackend(options.fallback);\n const request = options.request ?? ((req, opts) => vgdRequest(req, opts));\n const clientOpts: VgdClientOptions = { socketPath: options.socketPath };\n\n return {\n source: 'vgd',\n async search(query, opts) {\n try {\n const res = (await request(\n {\n op: 'query-graph',\n repositoryId: options.repositoryId,\n query,\n limit: opts?.limit ?? 10,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n matches?: Array<{\n id: string;\n qualifiedName: string;\n kind: string;\n file: string;\n line: number;\n score: number;\n why: string;\n }>;\n };\n if (res?.ok && Array.isArray(res.matches)) {\n return {\n source: 'vgd',\n matches: res.matches.map((m) => ({\n id: m.id,\n qualifiedName: m.qualifiedName,\n kind: m.kind,\n file: m.file,\n line: m.line,\n score: m.score,\n why: m.why,\n signature: null,\n })),\n };\n }\n } catch {\n /* fall through */\n }\n return local.search(query, opts);\n },\n async impact(symbol, opts) {\n try {\n const res = (await request(\n {\n op: 'impact-of',\n repositoryId: options.repositoryId,\n symbol,\n depth: opts?.depth ?? 4,\n gitRef: options.gitRef,\n },\n clientOpts,\n )) as {\n ok?: boolean;\n root?: { id: string; name: string };\n depth?: number;\n affected?: GraphImpactHit[];\n direct?: number;\n transitive?: number;\n };\n if (res?.ok && res.root && Array.isArray(res.affected)) {\n return {\n source: 'vgd',\n root: res.root,\n depth: res.depth ?? opts?.depth ?? 4,\n affected: res.affected,\n direct: res.direct ?? 0,\n transitive: res.transitive ?? 0,\n };\n }\n } catch {\n /* fall through */\n }\n return local.impact(symbol, opts);\n },\n };\n}\n\n/**\n * Pick a backend: vgd when repositoryId + socket are known, else local.\n */\nexport function resolveGraphBackend(input: {\n graph: VgGraph;\n repositoryId?: string | null;\n gitRef?: string | null;\n socketPath?: string | null;\n}): GraphBackend {\n if (input.repositoryId && input.socketPath) {\n return vgdGraphBackend({\n repositoryId: input.repositoryId,\n gitRef: input.gitRef ?? undefined,\n socketPath: input.socketPath,\n fallback: input.graph,\n });\n }\n return localGraphBackend(input.graph);\n}\n\nfunction resolveSymbolId(graph: VgGraph, symbol: string): string | null {\n if (graph.nodes.some((n) => n.id === symbol)) return symbol;\n const hit = resolveOne(graph, symbol);\n if (hit.node?.id) return hit.node.id;\n if (hit.candidates.length === 1 && hit.candidates[0]?.id) return hit.candidates[0].id;\n const q = symbol.toLowerCase();\n const byQn = graph.nodes.find((n) => n.qualifiedName?.toLowerCase() === q || n.name?.toLowerCase() === q);\n return byQn?.id ?? null;\n}\n"]}
@@ -0,0 +1,216 @@
1
+ import { resolveIngestHost } from './chunk-HTLDXEHW.js';
2
+ import { VERSION } from './chunk-Q4UQ73NA.js';
3
+ import { cacheDir } from './chunk-ZKNB4YH4.js';
4
+ import * as fs from 'fs';
5
+ import * as os from 'os';
6
+ import * as path from 'path';
7
+ import { randomUUID } from 'crypto';
8
+
9
+ var SCHEMA_VERSION = "1";
10
+ var OFFSET_FILE = "stats-share.json";
11
+ var INSTALL_ID_DIR = path.join(os.homedir(), ".vibgrate");
12
+ var INSTALL_ID_FILE = path.join(INSTALL_ID_DIR, "install-id");
13
+ var SEND_TIMEOUT_MS = 4e3;
14
+ function telemetryOptOut(env = process.env) {
15
+ const dnt = (env.DO_NOT_TRACK ?? "").trim().toLowerCase();
16
+ if (dnt !== "" && dnt !== "0" && dnt !== "false") return "DO_NOT_TRACK";
17
+ const vt = (env.VIBGRATE_TELEMETRY ?? "").trim().toLowerCase();
18
+ if (vt === "0" || vt === "false" || vt === "off") return "VIBGRATE_TELEMETRY";
19
+ return null;
20
+ }
21
+ var CI_ENV_VARS = [
22
+ "CI",
23
+ "GITHUB_ACTIONS",
24
+ "GITLAB_CI",
25
+ "CIRCLECI",
26
+ "TRAVIS",
27
+ "BUILDKITE",
28
+ "JENKINS_URL",
29
+ "TF_BUILD"
30
+ ];
31
+ function isCI(env = process.env) {
32
+ return CI_ENV_VARS.some((v) => {
33
+ const val = (env[v] ?? "").trim().toLowerCase();
34
+ return val !== "" && val !== "0" && val !== "false";
35
+ });
36
+ }
37
+ function installId(env = process.env) {
38
+ if (telemetryOptOut(env) !== null || isCI(env)) return randomUuid();
39
+ try {
40
+ const existing = fs.readFileSync(INSTALL_ID_FILE, "utf8").trim();
41
+ if (isUuid(existing)) return existing;
42
+ } catch {
43
+ }
44
+ const id = randomUuid();
45
+ try {
46
+ fs.mkdirSync(INSTALL_ID_DIR, { recursive: true });
47
+ fs.writeFileSync(INSTALL_ID_FILE, id + "\n", { mode: 384 });
48
+ } catch {
49
+ }
50
+ return id;
51
+ }
52
+ function isUuid(s) {
53
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);
54
+ }
55
+ function randomUuid() {
56
+ return randomUUID();
57
+ }
58
+ function statsEndpoint() {
59
+ const override = process.env.VIBGRATE_STATS_ENDPOINT;
60
+ if (override && /^https?:\/\//.test(override)) return override;
61
+ return `https://${resolveIngestHost()}/v1/ingest/cli-mcp-usage`;
62
+ }
63
+ function offsetPath(root) {
64
+ return path.join(cacheDir(root), OFFSET_FILE);
65
+ }
66
+ function ledgerFilePath(root) {
67
+ return path.join(cacheDir(root), "savings.jsonl");
68
+ }
69
+ function readOffset(root) {
70
+ try {
71
+ const raw = JSON.parse(fs.readFileSync(offsetPath(root), "utf8"));
72
+ return typeof raw.offset === "number" && raw.offset >= 0 ? raw.offset : 0;
73
+ } catch {
74
+ return 0;
75
+ }
76
+ }
77
+ function writeOffset(root, offset) {
78
+ try {
79
+ fs.mkdirSync(cacheDir(root), { recursive: true });
80
+ fs.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + "\n");
81
+ } catch {
82
+ }
83
+ }
84
+ function buildBatch(root, fromOffset, id = installId()) {
85
+ const file = ledgerFilePath(root);
86
+ let size = 0;
87
+ try {
88
+ size = fs.statSync(file).size;
89
+ } catch {
90
+ return { batch: null, newOffset: 0 };
91
+ }
92
+ const start = fromOffset > size ? 0 : fromOffset;
93
+ if (start >= size) return { batch: null, newOffset: size };
94
+ let text = "";
95
+ try {
96
+ const fd = fs.openSync(file, "r");
97
+ try {
98
+ const buf = Buffer.alloc(size - start);
99
+ fs.readSync(fd, buf, 0, buf.length, start);
100
+ text = buf.toString("utf8");
101
+ } finally {
102
+ fs.closeSync(fd);
103
+ }
104
+ } catch {
105
+ return { batch: null, newOffset: fromOffset };
106
+ }
107
+ const lastNl = text.lastIndexOf("\n");
108
+ if (lastNl < 0) return { batch: null, newOffset: start };
109
+ const consumed = start + lastNl + 1;
110
+ const rows = /* @__PURE__ */ new Map();
111
+ let total = 0;
112
+ let minTs = Infinity;
113
+ let maxTs = -Infinity;
114
+ for (const line of text.slice(0, lastNl).split("\n")) {
115
+ if (!line.trim()) continue;
116
+ let e;
117
+ try {
118
+ e = JSON.parse(line);
119
+ } catch {
120
+ continue;
121
+ }
122
+ const source = e.source ?? "mcp";
123
+ const client = e.client ?? "unknown";
124
+ const outcome = e.outcome ?? "complete";
125
+ const key = `${source}|${client}|${e.tool}|${outcome}`;
126
+ const row = rows.get(key) ?? {
127
+ source,
128
+ client,
129
+ tool: e.tool,
130
+ outcome,
131
+ calls: 0,
132
+ vgTokens: 0,
133
+ baselineTokens: 0
134
+ };
135
+ row.calls++;
136
+ row.vgTokens += e.vgTokens ?? 0;
137
+ row.baselineTokens += e.baselineTokens ?? 0;
138
+ rows.set(key, row);
139
+ total++;
140
+ if (typeof e.ts === "number") {
141
+ if (e.ts < minTs) minTs = e.ts;
142
+ if (e.ts > maxTs) maxTs = e.ts;
143
+ }
144
+ }
145
+ if (total === 0 || !Number.isFinite(minTs)) return { batch: null, newOffset: consumed };
146
+ const batch = {
147
+ schemaVersion: SCHEMA_VERSION,
148
+ installId: id,
149
+ vgVersion: VERSION,
150
+ os: process.platform,
151
+ arch: process.arch,
152
+ windowStart: new Date(minTs).toISOString(),
153
+ windowEnd: new Date(maxTs).toISOString(),
154
+ totalCalls: total,
155
+ rows: [...rows.values()]
156
+ };
157
+ return { batch, newOffset: consumed };
158
+ }
159
+ async function postBatch(batch) {
160
+ const controller = new AbortController();
161
+ const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);
162
+ timer.unref?.();
163
+ try {
164
+ const res = await fetch(statsEndpoint(), {
165
+ method: "POST",
166
+ headers: { "Content-Type": "application/json", Connection: "close" },
167
+ body: JSON.stringify(batch),
168
+ signal: controller.signal
169
+ });
170
+ return res.ok;
171
+ } catch {
172
+ return false;
173
+ } finally {
174
+ clearTimeout(timer);
175
+ }
176
+ }
177
+ var StatsSharer = class {
178
+ constructor(root) {
179
+ this.root = root;
180
+ this.offset = readOffset(root);
181
+ }
182
+ root;
183
+ id = installId();
184
+ offset;
185
+ flushing = false;
186
+ /**
187
+ * Flush any new ledger entries. Single-flight (a slow POST won't overlap the
188
+ * next tick). Best-effort: any failure is swallowed and retried next time.
189
+ */
190
+ async flush() {
191
+ if (this.flushing) return;
192
+ this.flushing = true;
193
+ try {
194
+ const { batch, newOffset } = buildBatch(this.root, this.offset, this.id);
195
+ if (!batch) {
196
+ if (newOffset > this.offset) {
197
+ this.offset = newOffset;
198
+ writeOffset(this.root, newOffset);
199
+ }
200
+ return;
201
+ }
202
+ const ok = await postBatch(batch);
203
+ if (ok) {
204
+ this.offset = newOffset;
205
+ writeOffset(this.root, newOffset);
206
+ }
207
+ } catch {
208
+ } finally {
209
+ this.flushing = false;
210
+ }
211
+ }
212
+ };
213
+
214
+ export { StatsSharer, installId, isCI, statsEndpoint, telemetryOptOut };
215
+ //# sourceMappingURL=chunk-TJ3WIJ7H.js.map
216
+ //# sourceMappingURL=chunk-TJ3WIJ7H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/stats-share.ts"],"names":[],"mappings":"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","file":"chunk-TJ3WIJ7H.js","sourcesContent":["import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { cacheDir } from './cache.js';\nimport { VERSION } from '../version.js';\nimport { resolveIngestHost } from '../reporting/regions.js';\nimport type { SavingEntry, Source, Outcome } from './savings.js';\n\n/**\n * Opt-in usage-stats sharing for `vg serve --share-stats`.\n *\n * This is the ONLY path in `vg serve` that sends anything off the machine, and\n * it is off unless the operator explicitly asks for it. What we send is the\n * same counts-only ledger `vg savings` reports locally — per (source, client,\n * tool, outcome): how many calls and the vg-vs-grep token figures — plus the vg\n * version, OS/arch, and a random per-install id. We never send code, file paths,\n * question text, repo identity, or any credential. See GUARDRAILS §3.4.\n *\n * Even when the flag is passed, the universal `DO_NOT_TRACK` opt-out (or\n * `VIBGRATE_TELEMETRY=0`) wins: nothing is uploaded and no install id is ever\n * minted or persisted (see `telemetryOptOut` / `installId`).\n *\n * Design:\n * - The local ledger (savings.jsonl) is the single source of truth; the flusher\n * reads only the tail past a persisted byte offset, so a batch is sent once.\n * - Fire-and-forget with a short timeout. A network problem never blocks a tool\n * call and never throws — the offset only advances on a confirmed 2xx, so a\n * failed batch is retried on the next flush.\n * - Fully offline-safe: under `--local` the sharer is never constructed.\n */\n\n/** Payload schema version — must match the server's `mcpUsageStatsSchema`. */\nconst SCHEMA_VERSION = '1';\n/** Where the offset (and cached install id) live, per repo, beside the ledger. */\nconst OFFSET_FILE = 'stats-share.json';\n/** The machine-global anonymous install id lives here (stable across repos). */\nconst INSTALL_ID_DIR = path.join(os.homedir(), '.vibgrate');\nconst INSTALL_ID_FILE = path.join(INSTALL_ID_DIR, 'install-id');\n/** Give a flush POST a hard ceiling so a hung endpoint never stalls shutdown. */\nconst SEND_TIMEOUT_MS = 4000;\n\n/** One aggregated row of the shared batch — counts only. */\nexport interface StatsRow {\n source: Source;\n client: string;\n tool: string;\n outcome: Outcome;\n calls: number;\n vgTokens: number;\n baselineTokens: number;\n}\n\n/** The counts-only batch POSTed to the ingest endpoint. */\nexport interface StatsBatch {\n schemaVersion: string;\n installId: string;\n vgVersion: string;\n os: string;\n arch: string;\n windowStart: string;\n windowEnd: string;\n totalCalls: number;\n rows: StatsRow[];\n}\n\n/**\n * The universal opt-out (https://consoledonottrack.com) plus a tool-specific\n * alias, honoured even when `--share-stats` is passed explicitly. Pure function\n * of the environment for testability. Returns the name of the variable that\n * opted out (for the disclosure message), or null when sharing may proceed.\n */\nexport function telemetryOptOut(env: NodeJS.ProcessEnv = process.env): string | null {\n const dnt = (env.DO_NOT_TRACK ?? '').trim().toLowerCase();\n if (dnt !== '' && dnt !== '0' && dnt !== 'false') return 'DO_NOT_TRACK';\n const vt = (env.VIBGRATE_TELEMETRY ?? '').trim().toLowerCase();\n if (vt === '0' || vt === 'false' || vt === 'off') return 'VIBGRATE_TELEMETRY';\n return null;\n}\n\n/** Common CI environment markers — a CI runner is never an interactive session. */\nconst CI_ENV_VARS = [\n 'CI',\n 'GITHUB_ACTIONS',\n 'GITLAB_CI',\n 'CIRCLECI',\n 'TRAVIS',\n 'BUILDKITE',\n 'JENKINS_URL',\n 'TF_BUILD',\n] as const;\n\n/** True when running under a recognised CI system. Pure function of the env. */\nexport function isCI(env: NodeJS.ProcessEnv = process.env): boolean {\n return CI_ENV_VARS.some((v) => {\n const val = (env[v] ?? '').trim().toLowerCase();\n return val !== '' && val !== '0' && val !== 'false';\n });\n}\n\n/**\n * Read (or lazily create) the anonymous per-install id — a random UUID stored in\n * `~/.vibgrate/install-id`. It is *not* tied to the user, the repo, or any\n * account; it only lets us de-duplicate batches from the same install when\n * aggregating. If the home dir isn't writable we fall back to an ephemeral id\n * so sharing still works (it just can't be de-duplicated across restarts).\n *\n * Under an env opt-out no id is ever read or persisted (the sharing path isn't\n * reached then either — this is defence in depth), and on CI runners the id is\n * ephemeral: a persisted id on a shared/throwaway runner would be meaningless\n * for de-duplication and would leave state behind on machines we don't own.\n */\nexport function installId(env: NodeJS.ProcessEnv = process.env): string {\n if (telemetryOptOut(env) !== null || isCI(env)) return randomUuid();\n try {\n const existing = fs.readFileSync(INSTALL_ID_FILE, 'utf8').trim();\n if (isUuid(existing)) return existing;\n } catch {\n /* not created yet */\n }\n const id = randomUuid();\n try {\n fs.mkdirSync(INSTALL_ID_DIR, { recursive: true });\n fs.writeFileSync(INSTALL_ID_FILE, id + '\\n', { mode: 0o600 });\n } catch {\n /* home dir read-only — use the ephemeral id for this process */\n }\n return id;\n}\n\nfunction isUuid(s: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);\n}\n\nfunction randomUuid(): string {\n return randomUUID();\n}\n\n/** Resolve the ingest endpoint: env override wins, else the default region host. */\nexport function statsEndpoint(): string {\n const override = process.env.VIBGRATE_STATS_ENDPOINT;\n if (override && /^https?:\\/\\//.test(override)) return override;\n return `https://${resolveIngestHost()}/v1/ingest/cli-mcp-usage`;\n}\n\nfunction offsetPath(root: string): string {\n return path.join(cacheDir(root), OFFSET_FILE);\n}\n\nfunction ledgerFilePath(root: string): string {\n return path.join(cacheDir(root), 'savings.jsonl');\n}\n\nfunction readOffset(root: string): number {\n try {\n const raw = JSON.parse(fs.readFileSync(offsetPath(root), 'utf8')) as { offset?: number };\n return typeof raw.offset === 'number' && raw.offset >= 0 ? raw.offset : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeOffset(root: string, offset: number): void {\n try {\n fs.mkdirSync(cacheDir(root), { recursive: true });\n fs.writeFileSync(offsetPath(root), JSON.stringify({ offset }) + '\\n');\n } catch {\n /* best-effort; a lost offset just means one batch may re-send */\n }\n}\n\n/**\n * Aggregate the ledger entries after `fromOffset` into a counts-only batch.\n * Returns the batch (or null if there's nothing new) and the new byte offset to\n * persist once the batch is confirmed sent.\n */\nexport function buildBatch(\n root: string,\n fromOffset: number,\n id = installId(),\n): { batch: StatsBatch | null; newOffset: number } {\n const file = ledgerFilePath(root);\n let size = 0;\n try {\n size = fs.statSync(file).size;\n } catch {\n return { batch: null, newOffset: 0 };\n }\n // The ledger was truncated/recreated under us — re-read from the top.\n const start = fromOffset > size ? 0 : fromOffset;\n if (start >= size) return { batch: null, newOffset: size };\n\n let text = '';\n try {\n const fd = fs.openSync(file, 'r');\n try {\n const buf = Buffer.alloc(size - start);\n fs.readSync(fd, buf, 0, buf.length, start);\n text = buf.toString('utf8');\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return { batch: null, newOffset: fromOffset };\n }\n\n // Only whole lines are complete; a trailing partial line (mid-append) is left\n // for the next flush by rewinding the offset to the last newline.\n const lastNl = text.lastIndexOf('\\n');\n if (lastNl < 0) return { batch: null, newOffset: start };\n const consumed = start + lastNl + 1;\n const rows = new Map<string, StatsRow>();\n let total = 0;\n let minTs = Infinity;\n let maxTs = -Infinity;\n for (const line of text.slice(0, lastNl).split('\\n')) {\n if (!line.trim()) continue;\n let e: SavingEntry;\n try {\n e = JSON.parse(line) as SavingEntry;\n } catch {\n continue;\n }\n const source: Source = e.source ?? 'mcp';\n const client = e.client ?? 'unknown';\n const outcome: Outcome = e.outcome ?? 'complete';\n const key = `${source}|${client}|${e.tool}|${outcome}`;\n const row = rows.get(key) ?? {\n source,\n client,\n tool: e.tool,\n outcome,\n calls: 0,\n vgTokens: 0,\n baselineTokens: 0,\n };\n row.calls++;\n row.vgTokens += e.vgTokens ?? 0;\n row.baselineTokens += e.baselineTokens ?? 0;\n rows.set(key, row);\n total++;\n if (typeof e.ts === 'number') {\n if (e.ts < minTs) minTs = e.ts;\n if (e.ts > maxTs) maxTs = e.ts;\n }\n }\n if (total === 0 || !Number.isFinite(minTs)) return { batch: null, newOffset: consumed };\n const batch: StatsBatch = {\n schemaVersion: SCHEMA_VERSION,\n installId: id,\n vgVersion: VERSION,\n os: process.platform,\n arch: process.arch,\n windowStart: new Date(minTs).toISOString(),\n windowEnd: new Date(maxTs).toISOString(),\n totalCalls: total,\n rows: [...rows.values()],\n };\n return { batch, newOffset: consumed };\n}\n\n/**\n * POST a batch to the endpoint. Never throws; returns whether it was accepted.\n * A short timeout keeps a hung endpoint from stalling the caller (e.g. shutdown).\n */\nasync function postBatch(batch: StatsBatch): Promise<boolean> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);\n timer.unref?.();\n try {\n const res = await fetch(statsEndpoint(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Connection: 'close' },\n body: JSON.stringify(batch),\n signal: controller.signal,\n });\n return res.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Periodic + on-shutdown flusher for one serve session. Holds the install id and\n * the persisted offset so each flush reads only new ledger lines and advances the\n * offset only when the batch is confirmed sent.\n */\nexport class StatsSharer {\n private readonly id = installId();\n private offset: number;\n private flushing = false;\n\n constructor(private readonly root: string) {\n this.offset = readOffset(root);\n }\n\n /**\n * Flush any new ledger entries. Single-flight (a slow POST won't overlap the\n * next tick). Best-effort: any failure is swallowed and retried next time.\n */\n async flush(): Promise<void> {\n if (this.flushing) return;\n this.flushing = true;\n try {\n const { batch, newOffset } = buildBatch(this.root, this.offset, this.id);\n if (!batch) {\n // Nothing to send, but still advance past consumed blank/partial space.\n if (newOffset > this.offset) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n return;\n }\n const ok = await postBatch(batch);\n if (ok) {\n this.offset = newOffset;\n writeOffset(this.root, newOffset);\n }\n } catch {\n /* never let sharing break serving */\n } finally {\n this.flushing = false;\n }\n }\n}\n"]}
@@ -0,0 +1,203 @@
1
+ import { loadGraphFileWithSnapshot, resolveGraphPath } from './chunk-5G7C6H2G.js';
2
+ import { cacheDir } from './chunk-ZKNB4YH4.js';
3
+ import { __require } from './chunk-Z6ZWNWWR.js';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+
7
+ // src/schema.ts
8
+ var SCHEMA_VERSION = "vg-graph/1.0";
9
+
10
+ // src/engine/index-db.ts
11
+ function indexDbPath(root) {
12
+ return path.join(cacheDir(root), "graph.db");
13
+ }
14
+ function writeGraphIndex(root, graph) {
15
+ const file = indexDbPath(root);
16
+ try {
17
+ const { DatabaseSync } = __require("sqlite");
18
+ fs.mkdirSync(path.dirname(file), { recursive: true });
19
+ const tmp = `${file}.${process.pid}.tmp`;
20
+ try {
21
+ if (fs.existsSync(tmp)) fs.unlinkSync(tmp);
22
+ } catch {
23
+ }
24
+ const db = new DatabaseSync(tmp);
25
+ db.exec(`
26
+ PRAGMA journal_mode = OFF;
27
+ PRAGMA synchronous = OFF;
28
+ CREATE TABLE meta (
29
+ key TEXT PRIMARY KEY,
30
+ value TEXT NOT NULL
31
+ );
32
+ CREATE TABLE nodes (
33
+ id TEXT PRIMARY KEY,
34
+ name TEXT NOT NULL,
35
+ qualified_name TEXT NOT NULL,
36
+ kind TEXT NOT NULL,
37
+ file TEXT NOT NULL,
38
+ line INTEGER NOT NULL,
39
+ importance REAL NOT NULL,
40
+ area INTEGER NOT NULL,
41
+ is_hub INTEGER NOT NULL,
42
+ lang TEXT NOT NULL,
43
+ json TEXT NOT NULL
44
+ );
45
+ CREATE TABLE edges (
46
+ id TEXT PRIMARY KEY,
47
+ kind TEXT NOT NULL,
48
+ src TEXT NOT NULL,
49
+ dst TEXT NOT NULL,
50
+ resolution TEXT NOT NULL,
51
+ confidence REAL NOT NULL,
52
+ epistemic TEXT NOT NULL,
53
+ json TEXT NOT NULL
54
+ );
55
+ CREATE TABLE areas (
56
+ id INTEGER PRIMARY KEY,
57
+ json TEXT NOT NULL
58
+ );
59
+ CREATE INDEX idx_nodes_name ON nodes(name);
60
+ CREATE INDEX idx_nodes_qn ON nodes(qualified_name);
61
+ CREATE INDEX idx_nodes_file ON nodes(file);
62
+ CREATE INDEX idx_edges_src ON edges(src);
63
+ CREATE INDEX idx_edges_dst ON edges(dst);
64
+ CREATE INDEX idx_edges_kind ON edges(kind);
65
+ `);
66
+ const insMeta = db.prepare("INSERT INTO meta(key, value) VALUES (?, ?)");
67
+ insMeta.run("corpusHash", graph.provenance.corpusHash);
68
+ insMeta.run("schemaVersion", graph.schemaVersion);
69
+ insMeta.run("generatedAt", graph.generatedAt);
70
+ insMeta.run("nodeCount", String(graph.nodes.length));
71
+ insMeta.run("edgeCount", String(graph.edges.length));
72
+ insMeta.run("analysisTier", graph.meta.analysisTier ?? "full");
73
+ insMeta.run("indexVersion", "vg-graph-index/2");
74
+ insMeta.run("graphMeta", JSON.stringify(graph.meta));
75
+ insMeta.run("graphProvenance", JSON.stringify(graph.provenance));
76
+ if (graph.facts) insMeta.run("factsJson", JSON.stringify(graph.facts));
77
+ if (graph.grounding) insMeta.run("groundingJson", JSON.stringify(graph.grounding));
78
+ if (graph.summaries) insMeta.run("summariesJson", JSON.stringify(graph.summaries));
79
+ if (graph.unknowns) insMeta.run("unknownsJson", JSON.stringify(graph.unknowns));
80
+ const insNode = db.prepare(
81
+ `INSERT INTO nodes(id, name, qualified_name, kind, file, line, importance, area, is_hub, lang, json)
82
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
83
+ );
84
+ for (const n of graph.nodes) {
85
+ insNode.run(
86
+ n.id,
87
+ n.name,
88
+ n.qualifiedName,
89
+ n.kind,
90
+ n.file,
91
+ n.span.start,
92
+ n.importance,
93
+ n.area,
94
+ n.isHub ? 1 : 0,
95
+ n.lang,
96
+ JSON.stringify(n)
97
+ );
98
+ }
99
+ const insEdge = db.prepare(
100
+ `INSERT INTO edges(id, kind, src, dst, resolution, confidence, epistemic, json)
101
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
102
+ );
103
+ for (const e of graph.edges) {
104
+ insEdge.run(
105
+ e.id,
106
+ e.kind,
107
+ e.src,
108
+ e.dst,
109
+ e.resolution,
110
+ e.confidence,
111
+ e.epistemic ?? "observed",
112
+ JSON.stringify(e)
113
+ );
114
+ }
115
+ const insArea = db.prepare("INSERT INTO areas(id, json) VALUES (?, ?)");
116
+ for (const a of graph.areas) {
117
+ insArea.run(a.id, JSON.stringify(a));
118
+ }
119
+ db.close();
120
+ fs.renameSync(tmp, file);
121
+ return { path: file, nodes: graph.nodes.length, edges: graph.edges.length, ok: true };
122
+ } catch (err) {
123
+ return {
124
+ path: file,
125
+ nodes: 0,
126
+ edges: 0,
127
+ ok: false,
128
+ reason: err.message
129
+ };
130
+ }
131
+ }
132
+ function loadGraphFromIndex(root) {
133
+ const file = indexDbPath(root);
134
+ if (!fs.existsSync(file)) return null;
135
+ try {
136
+ const { DatabaseSync } = __require("sqlite");
137
+ const db = new DatabaseSync(file, { readOnly: true });
138
+ const metaRows = db.prepare("SELECT key, value FROM meta").all();
139
+ const meta = {};
140
+ for (const r of metaRows) meta[r.key] = r.value;
141
+ if (meta.indexVersion !== "vg-graph-index/2" || !meta.graphMeta || !meta.graphProvenance) {
142
+ db.close();
143
+ return null;
144
+ }
145
+ const nodeRows = db.prepare("SELECT json FROM nodes ORDER BY id").all();
146
+ const edgeRows = db.prepare("SELECT json FROM edges ORDER BY id").all();
147
+ const areaRows = db.prepare("SELECT json FROM areas ORDER BY id").all();
148
+ db.close();
149
+ const nodes = nodeRows.map((r) => JSON.parse(r.json));
150
+ const edges = edgeRows.map((r) => JSON.parse(r.json));
151
+ const areas = areaRows.map((r) => JSON.parse(r.json));
152
+ nodes.sort((a, b) => a.id.localeCompare(b.id));
153
+ edges.sort(
154
+ (a, b) => a.kind.localeCompare(b.kind) || a.src.localeCompare(b.src) || a.dst.localeCompare(b.dst)
155
+ );
156
+ areas.sort((a, b) => a.id - b.id);
157
+ const graph = {
158
+ schemaVersion: meta.schemaVersion || SCHEMA_VERSION,
159
+ generatedAt: meta.generatedAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
160
+ provenance: JSON.parse(meta.graphProvenance),
161
+ meta: JSON.parse(meta.graphMeta),
162
+ nodes,
163
+ edges,
164
+ areas
165
+ };
166
+ if (meta.factsJson) graph.facts = JSON.parse(meta.factsJson);
167
+ if (meta.groundingJson) graph.grounding = JSON.parse(meta.groundingJson);
168
+ if (meta.summariesJson) graph.summaries = JSON.parse(meta.summariesJson);
169
+ if (meta.unknownsJson) graph.unknowns = JSON.parse(meta.unknownsJson);
170
+ for (const e of edges) {
171
+ if (!e.resolution) e.resolution = "heuristic";
172
+ if (!e.epistemic) e.epistemic = "observed";
173
+ }
174
+ return graph;
175
+ } catch {
176
+ return null;
177
+ }
178
+ }
179
+ function loadGraphPreferIndex(root, graphJsonPath) {
180
+ const jsonGraph = loadGraphFileWithSnapshot(graphJsonPath);
181
+ const fromIndex = loadGraphFromIndex(root);
182
+ if (fromIndex) {
183
+ if (!jsonGraph || fromIndex.provenance.corpusHash === jsonGraph.provenance.corpusHash) {
184
+ return { graph: fromIndex, source: "index" };
185
+ }
186
+ }
187
+ if (jsonGraph) return { graph: jsonGraph, source: "json" };
188
+ return null;
189
+ }
190
+
191
+ // src/engine/load.ts
192
+ function loadGraph(root, graphPath) {
193
+ const file = resolveGraphPath(root, graphPath);
194
+ if (!graphPath) {
195
+ const preferred = loadGraphPreferIndex(root, file);
196
+ if (preferred) return preferred.graph;
197
+ }
198
+ return loadGraphFileWithSnapshot(file);
199
+ }
200
+
201
+ export { SCHEMA_VERSION, loadGraph, loadGraphPreferIndex, writeGraphIndex };
202
+ //# sourceMappingURL=chunk-VOEYUAER.js.map
203
+ //# sourceMappingURL=chunk-VOEYUAER.js.map