@vibgrate/cli 2026.703.5 → 2026.704.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +22 -0
- package/dist/baseline-FESLZK5O.js +6 -0
- package/dist/{baseline-AQKQEA2O.js.map → baseline-FESLZK5O.js.map} +1 -1
- package/dist/{chunk-4M2MUQRO.js → chunk-GI6W53LM.js} +131 -17
- package/dist/chunk-GI6W53LM.js.map +1 -0
- package/dist/{chunk-L7YBNIBF.js → chunk-RJHYTD62.js} +16 -16
- package/dist/chunk-RJHYTD62.js.map +1 -0
- package/dist/{chunk-6T3R7RF2.js → chunk-W4ANUENJ.js} +3 -3
- package/dist/{chunk-6T3R7RF2.js.map → chunk-W4ANUENJ.js.map} +1 -1
- package/dist/{chunk-W2QP2YH6.js → chunk-YODVLV37.js} +496 -234
- package/dist/chunk-YODVLV37.js.map +1 -0
- package/dist/cli.js +127 -50
- package/dist/cli.js.map +1 -1
- package/dist/fs-IPY4FJKH.js +3 -0
- package/dist/fs-IPY4FJKH.js.map +1 -0
- package/dist/index.d.ts +48 -2
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/dist/baseline-AQKQEA2O.js +0 -6
- package/dist/chunk-4M2MUQRO.js.map +0 -1
- package/dist/chunk-L7YBNIBF.js.map +0 -1
- package/dist/chunk-W2QP2YH6.js.map +0 -1
- package/dist/fs-7KZ4F3SB.js +0 -3
- package/dist/fs-7KZ4F3SB.js.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { langById, shortId, canonicalize, grammarSetVersion,
|
|
2
|
-
import { writeTextFile, pathExists, readJsonFile, VERSION, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem } from './chunk-
|
|
3
|
-
import * as
|
|
1
|
+
import { langById, shortId, canonicalize, grammarSetVersion, hashString, hashBytes, langForExtension, setGrammarsOverride, parseSource } from './chunk-X5YT263H.js';
|
|
2
|
+
import { writeTextFile, pathExists, readJsonFile, VERSION, computeUpgradeImpact, getChangelogSignals, gitHistoryAvailable, buildVersionTimelines, findPackageTimeline, severityRank, projectTypeToVulnEcosystem } from './chunk-RJHYTD62.js';
|
|
3
|
+
import * as fs18 from 'fs';
|
|
4
|
+
import { execFileSync } from 'child_process';
|
|
4
5
|
import * as path18 from 'path';
|
|
5
6
|
import ignore from 'ignore';
|
|
7
|
+
import * as v8 from 'v8';
|
|
6
8
|
import Graph from 'graphology';
|
|
7
9
|
import pagerank from 'graphology-metrics/centrality/pagerank.js';
|
|
8
10
|
import betweenness from 'graphology-metrics/centrality/betweenness.js';
|
|
@@ -12,7 +14,6 @@ import * as os from 'os';
|
|
|
12
14
|
import { fileURLToPath } from 'url';
|
|
13
15
|
import ts from 'typescript';
|
|
14
16
|
import { bidirectional } from 'graphology-shortest-path/unweighted.js';
|
|
15
|
-
import { execFileSync } from 'child_process';
|
|
16
17
|
import * as crypto from 'crypto';
|
|
17
18
|
import { Command } from 'commander';
|
|
18
19
|
import chalk from 'chalk';
|
|
@@ -23,32 +24,196 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
23
24
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
24
25
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
25
26
|
|
|
27
|
+
var NPX_INVOCATION = "npx @vibgrate/cli";
|
|
28
|
+
function whichOnPath(cmd) {
|
|
29
|
+
try {
|
|
30
|
+
const out = execFileSync(process.platform === "win32" ? "where" : "which", [cmd], {
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
33
|
+
}).trim().split(/\r?\n/)[0];
|
|
34
|
+
return out || null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isOwnBinary(binPath) {
|
|
40
|
+
try {
|
|
41
|
+
const real = fs18.realpathSync(binPath);
|
|
42
|
+
if (/[\\/]@vibgrate[\\/]cli[\\/]/.test(real)) return true;
|
|
43
|
+
const head = fs18.readFileSync(real, { encoding: "utf8" }).slice(0, 2048);
|
|
44
|
+
return head.includes("@vibgrate/cli") || head.includes("vibgrate");
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function isEphemeralNpxBinary(binPath) {
|
|
50
|
+
const NPX_SEGMENT = /[\\/]_npx[\\/]/;
|
|
51
|
+
if (NPX_SEGMENT.test(binPath)) return true;
|
|
52
|
+
try {
|
|
53
|
+
return NPX_SEGMENT.test(fs18.realpathSync(binPath));
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isInstalledOwnBinary(binPath) {
|
|
59
|
+
return isOwnBinary(binPath) && !isEphemeralNpxBinary(binPath);
|
|
60
|
+
}
|
|
61
|
+
var cached;
|
|
62
|
+
function resolveCliInvocation(which) {
|
|
63
|
+
if (!which && cached !== void 0) return cached;
|
|
64
|
+
const lookup = which ?? whichOnPath;
|
|
65
|
+
const vg = lookup("vg");
|
|
66
|
+
let result;
|
|
67
|
+
if (vg && isInstalledOwnBinary(vg)) {
|
|
68
|
+
result = "vg";
|
|
69
|
+
} else {
|
|
70
|
+
const vibgrate = lookup("vibgrate");
|
|
71
|
+
result = vibgrate && isInstalledOwnBinary(vibgrate) ? "vibgrate" : NPX_INVOCATION;
|
|
72
|
+
}
|
|
73
|
+
if (!which) cached = result;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
26
76
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
77
|
+
// Version control, IDE & tool metadata
|
|
27
78
|
".git",
|
|
28
|
-
"
|
|
79
|
+
".svn",
|
|
80
|
+
".hg",
|
|
81
|
+
".idea",
|
|
82
|
+
".vscode",
|
|
83
|
+
".vs",
|
|
29
84
|
".vibgrate",
|
|
85
|
+
".wrangler",
|
|
86
|
+
".turbo",
|
|
87
|
+
".cache",
|
|
88
|
+
// JavaScript / Node — installed dependency trees
|
|
89
|
+
"node_modules",
|
|
90
|
+
"bower_components",
|
|
91
|
+
"jspm_packages",
|
|
92
|
+
"web_modules",
|
|
93
|
+
".pnpm-store",
|
|
94
|
+
".yarn",
|
|
95
|
+
// JS/TS meta-framework & bundler build output
|
|
96
|
+
".next",
|
|
97
|
+
".nuxt",
|
|
98
|
+
".output",
|
|
99
|
+
".svelte-kit",
|
|
100
|
+
".astro",
|
|
101
|
+
".vercel",
|
|
102
|
+
".netlify",
|
|
103
|
+
".angular",
|
|
104
|
+
".parcel-cache",
|
|
105
|
+
".docusaurus",
|
|
106
|
+
"storybook-static",
|
|
107
|
+
// Generic build / dist / coverage output
|
|
30
108
|
"dist",
|
|
31
109
|
"build",
|
|
32
110
|
"out",
|
|
33
111
|
"coverage",
|
|
34
|
-
|
|
35
|
-
".nuxt",
|
|
36
|
-
".svelte-kit",
|
|
37
|
-
".turbo",
|
|
38
|
-
".cache",
|
|
112
|
+
// Vendored third-party source trees
|
|
39
113
|
"vendor",
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"obj",
|
|
44
|
-
// .NET
|
|
45
|
-
"__pycache__",
|
|
114
|
+
"Pods",
|
|
115
|
+
"Carthage",
|
|
116
|
+
// Python — virtualenvs & tool caches
|
|
46
117
|
".venv",
|
|
47
118
|
"venv",
|
|
119
|
+
"virtualenv",
|
|
48
120
|
".tox",
|
|
121
|
+
".nox",
|
|
122
|
+
"__pycache__",
|
|
123
|
+
".mypy_cache",
|
|
124
|
+
".pytest_cache",
|
|
125
|
+
".ruff_cache",
|
|
126
|
+
".eggs",
|
|
127
|
+
".ipynb_checkpoints",
|
|
128
|
+
// Ruby
|
|
129
|
+
".bundle",
|
|
130
|
+
// Rust / Maven / sbt / Clojure — all build into target/
|
|
131
|
+
"target",
|
|
132
|
+
// JVM (Gradle / Maven) & .NET build output
|
|
49
133
|
".gradle",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
134
|
+
"bin",
|
|
135
|
+
"obj",
|
|
136
|
+
"TestResults",
|
|
137
|
+
// Swift / Xcode
|
|
138
|
+
".build",
|
|
139
|
+
".swiftpm",
|
|
140
|
+
"DerivedData",
|
|
141
|
+
// Dart / Flutter
|
|
142
|
+
".dart_tool",
|
|
143
|
+
// Elixir / Erlang
|
|
144
|
+
"_build",
|
|
145
|
+
"deps",
|
|
146
|
+
// Haskell (Cabal / Stack)
|
|
147
|
+
"dist-newstyle",
|
|
148
|
+
".stack-work",
|
|
149
|
+
// Infrastructure-as-code build/state
|
|
150
|
+
".terraform",
|
|
151
|
+
".serverless",
|
|
152
|
+
"cdk.out",
|
|
153
|
+
".aws-sam"
|
|
154
|
+
]);
|
|
155
|
+
var SKIP_FILES = /* @__PURE__ */ new Set([
|
|
156
|
+
// JavaScript / Node
|
|
157
|
+
"package-lock.json",
|
|
158
|
+
"npm-shrinkwrap.json",
|
|
159
|
+
"yarn.lock",
|
|
160
|
+
"pnpm-lock.yaml",
|
|
161
|
+
"bun.lockb",
|
|
162
|
+
"bun.lock",
|
|
163
|
+
"deno.lock",
|
|
164
|
+
".pnp.cjs",
|
|
165
|
+
".pnp.data.json",
|
|
166
|
+
".pnp.loader.mjs",
|
|
167
|
+
// Python
|
|
168
|
+
"poetry.lock",
|
|
169
|
+
"pipfile.lock",
|
|
170
|
+
"pdm.lock",
|
|
171
|
+
"uv.lock",
|
|
172
|
+
"pylock.toml",
|
|
173
|
+
"conda-lock.yml",
|
|
174
|
+
// Ruby
|
|
175
|
+
"gemfile.lock",
|
|
176
|
+
// PHP
|
|
177
|
+
"composer.lock",
|
|
178
|
+
// Rust
|
|
179
|
+
"cargo.lock",
|
|
180
|
+
// Go
|
|
181
|
+
"go.sum",
|
|
182
|
+
"go.work.sum",
|
|
183
|
+
"gopkg.lock",
|
|
184
|
+
"glide.lock",
|
|
185
|
+
// .NET
|
|
186
|
+
"packages.lock.json",
|
|
187
|
+
// Java / JVM (Gradle)
|
|
188
|
+
"gradle.lockfile",
|
|
189
|
+
// Swift / Xcode
|
|
190
|
+
"package.resolved",
|
|
191
|
+
// Dart / Flutter
|
|
192
|
+
"pubspec.lock",
|
|
193
|
+
// Elixir
|
|
194
|
+
"mix.lock",
|
|
195
|
+
// Haskell (Cabal / Stack)
|
|
196
|
+
"cabal.project.freeze",
|
|
197
|
+
"stack.yaml.lock",
|
|
198
|
+
// Julia
|
|
199
|
+
"manifest.toml",
|
|
200
|
+
// R
|
|
201
|
+
"renv.lock",
|
|
202
|
+
// Perl (Carton)
|
|
203
|
+
"cpanfile.snapshot",
|
|
204
|
+
// CocoaPods / Carthage
|
|
205
|
+
"podfile.lock",
|
|
206
|
+
"cartfile.resolved",
|
|
207
|
+
// Terraform / IaC
|
|
208
|
+
".terraform.lock.hcl",
|
|
209
|
+
// Helm
|
|
210
|
+
"chart.lock",
|
|
211
|
+
// C / C++ (Conan)
|
|
212
|
+
"conan.lock",
|
|
213
|
+
// Bazel
|
|
214
|
+
"module.bazel.lock",
|
|
215
|
+
// Nix
|
|
216
|
+
"flake.lock"
|
|
52
217
|
]);
|
|
53
218
|
function toPosix(p) {
|
|
54
219
|
return p.split(path18.sep).join("/");
|
|
@@ -56,8 +221,8 @@ function toPosix(p) {
|
|
|
56
221
|
function buildRootIgnore(root, exclude) {
|
|
57
222
|
const ig = ignore();
|
|
58
223
|
const gitignorePath = path18.join(root, ".gitignore");
|
|
59
|
-
if (
|
|
60
|
-
ig.add(
|
|
224
|
+
if (fs18.existsSync(gitignorePath)) {
|
|
225
|
+
ig.add(fs18.readFileSync(gitignorePath, "utf8"));
|
|
61
226
|
}
|
|
62
227
|
if (exclude.length) ig.add(exclude);
|
|
63
228
|
return ig;
|
|
@@ -72,12 +237,13 @@ function discover(options) {
|
|
|
72
237
|
}
|
|
73
238
|
}
|
|
74
239
|
const rootIg = buildRootIgnore(root, options.exclude ?? []);
|
|
75
|
-
const scopeAbs = (options.paths && options.paths.length ? options.paths.map((p) => path18.resolve(root, p)) : [root]).filter((p) =>
|
|
240
|
+
const scopeAbs = (options.paths && options.paths.length ? options.paths.map((p) => path18.resolve(root, p)) : [root]).filter((p) => fs18.existsSync(p));
|
|
76
241
|
const found = /* @__PURE__ */ new Map();
|
|
77
242
|
const considerFile = (abs) => {
|
|
78
243
|
const rel2 = toPosix(path18.relative(root, abs));
|
|
79
244
|
if (rel2.startsWith("..")) return;
|
|
80
245
|
if (rel2 === "" || rootIg.ignores(rel2)) return;
|
|
246
|
+
if (SKIP_FILES.has(path18.basename(abs).toLowerCase())) return;
|
|
81
247
|
const lang = langForExtension(path18.extname(abs));
|
|
82
248
|
if (!lang || !allowLang(lang)) return;
|
|
83
249
|
found.set(rel2, { rel: rel2, abs, lang });
|
|
@@ -85,7 +251,7 @@ function discover(options) {
|
|
|
85
251
|
const walk2 = (dir) => {
|
|
86
252
|
let entries;
|
|
87
253
|
try {
|
|
88
|
-
entries =
|
|
254
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
89
255
|
} catch {
|
|
90
256
|
return;
|
|
91
257
|
}
|
|
@@ -102,7 +268,7 @@ function discover(options) {
|
|
|
102
268
|
}
|
|
103
269
|
};
|
|
104
270
|
for (const scope of scopeAbs) {
|
|
105
|
-
const stat =
|
|
271
|
+
const stat = fs18.statSync(scope);
|
|
106
272
|
if (stat.isDirectory()) walk2(scope);
|
|
107
273
|
else if (stat.isFile()) considerFile(scope);
|
|
108
274
|
}
|
|
@@ -115,6 +281,58 @@ var UsageError = class extends Error {
|
|
|
115
281
|
this.name = "UsageError";
|
|
116
282
|
}
|
|
117
283
|
};
|
|
284
|
+
var MIB = 1024 * 1024;
|
|
285
|
+
var DEFAULT_MAX_FILE_BYTES = 2 * MIB;
|
|
286
|
+
var DEFAULT_MAX_FILES = 1e5;
|
|
287
|
+
var DEFAULT_TSC_MAX_FILES = 1e4;
|
|
288
|
+
var HEAP_GUARD_FRACTION = 0.9;
|
|
289
|
+
var ResourceLimitError = class extends Error {
|
|
290
|
+
isResourceLimitError = true;
|
|
291
|
+
constructor(message) {
|
|
292
|
+
super(message);
|
|
293
|
+
this.name = "ResourceLimitError";
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
function envInt(name, fallback) {
|
|
297
|
+
const raw = process.env[name];
|
|
298
|
+
if (raw === void 0 || raw.trim() === "") return fallback;
|
|
299
|
+
const n = Number(raw);
|
|
300
|
+
return Number.isInteger(n) && n >= 0 ? n : fallback;
|
|
301
|
+
}
|
|
302
|
+
function envIntOptional(name) {
|
|
303
|
+
const n = envInt(name, 0);
|
|
304
|
+
return n > 0 ? n : void 0;
|
|
305
|
+
}
|
|
306
|
+
function defaultMemoryBudgetMb() {
|
|
307
|
+
return Math.floor(v8.getHeapStatistics().heap_size_limit / MIB * HEAP_GUARD_FRACTION);
|
|
308
|
+
}
|
|
309
|
+
function resolveLimits(overrides = {}) {
|
|
310
|
+
return {
|
|
311
|
+
maxFileBytes: overrides.maxFileBytes ?? envInt("VG_MAX_FILE_BYTES", DEFAULT_MAX_FILE_BYTES),
|
|
312
|
+
maxFiles: overrides.maxFiles ?? envInt("VG_MAX_FILES", DEFAULT_MAX_FILES),
|
|
313
|
+
tscMaxFiles: overrides.tscMaxFiles ?? envInt("VG_TSC_MAX_FILES", DEFAULT_TSC_MAX_FILES),
|
|
314
|
+
memoryBudgetMb: overrides.memoryBudgetMb ?? envInt("VG_MEMORY_BUDGET_MB", defaultMemoryBudgetMb())
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function envJobs() {
|
|
318
|
+
return envIntOptional("VG_JOBS");
|
|
319
|
+
}
|
|
320
|
+
function envWorkerHeapMb() {
|
|
321
|
+
return envIntOptional("VG_WORKER_HEAP_MB");
|
|
322
|
+
}
|
|
323
|
+
function checkMemoryBudget(phase, budgetMb) {
|
|
324
|
+
if (budgetMb <= 0) return;
|
|
325
|
+
const usedMb = process.memoryUsage().heapUsed / MIB;
|
|
326
|
+
if (usedMb <= budgetMb) return;
|
|
327
|
+
throw new ResourceLimitError(
|
|
328
|
+
`graph build stopped during ${phase}: heap use ${Math.round(usedMb)} MiB exceeds the ${budgetMb} MiB budget. Narrow the build (scope to sub-paths, add --exclude globs, or --only <langs>), raise the Node heap (NODE_OPTIONS=--max-old-space-size=8192), or set VG_MEMORY_BUDGET_MB (0 disables this safeguard).`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
function formatBytes(n) {
|
|
332
|
+
if (n >= MIB) return `${(n / MIB).toFixed(1)} MiB`;
|
|
333
|
+
if (n >= 1024) return `${(n / 1024).toFixed(1)} KiB`;
|
|
334
|
+
return `${n} B`;
|
|
335
|
+
}
|
|
118
336
|
var JS_TS_EXT = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
119
337
|
var OTHER_EXT = [
|
|
120
338
|
".py",
|
|
@@ -336,7 +554,7 @@ function matchPattern(pattern, source) {
|
|
|
336
554
|
function loadTsconfigPaths(root) {
|
|
337
555
|
for (const name of ["tsconfig.base.json", "tsconfig.json"]) {
|
|
338
556
|
const file = path18.join(root, name);
|
|
339
|
-
if (
|
|
557
|
+
if (fs18.existsSync(file)) {
|
|
340
558
|
const merged = readTsconfigChain(root, file, /* @__PURE__ */ new Set());
|
|
341
559
|
if (merged && merged.paths.length) return merged;
|
|
342
560
|
}
|
|
@@ -348,7 +566,7 @@ function readTsconfigChain(root, file, seen) {
|
|
|
348
566
|
seen.add(file);
|
|
349
567
|
let cfg;
|
|
350
568
|
try {
|
|
351
|
-
cfg = parseJsonc(
|
|
569
|
+
cfg = parseJsonc(fs18.readFileSync(file, "utf8"));
|
|
352
570
|
} catch {
|
|
353
571
|
return null;
|
|
354
572
|
}
|
|
@@ -356,7 +574,7 @@ function readTsconfigChain(root, file, seen) {
|
|
|
356
574
|
let base = { baseUrlRel: "", paths: [] };
|
|
357
575
|
if (cfg.extends && cfg.extends.startsWith(".")) {
|
|
358
576
|
const extPath = path18.resolve(dir, cfg.extends.endsWith(".json") ? cfg.extends : `${cfg.extends}.json`);
|
|
359
|
-
if (
|
|
577
|
+
if (fs18.existsSync(extPath)) {
|
|
360
578
|
const inherited = readTsconfigChain(root, extPath, seen);
|
|
361
579
|
if (inherited) base = inherited;
|
|
362
580
|
}
|
|
@@ -371,17 +589,17 @@ function loadWorkspacePackages(root) {
|
|
|
371
589
|
const map = /* @__PURE__ */ new Map();
|
|
372
590
|
const globs = [];
|
|
373
591
|
const rootPkg = path18.join(root, "package.json");
|
|
374
|
-
if (
|
|
592
|
+
if (fs18.existsSync(rootPkg)) {
|
|
375
593
|
try {
|
|
376
|
-
const pkg = JSON.parse(
|
|
594
|
+
const pkg = JSON.parse(fs18.readFileSync(rootPkg, "utf8"));
|
|
377
595
|
const ws = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages;
|
|
378
596
|
if (ws) globs.push(...ws);
|
|
379
597
|
} catch {
|
|
380
598
|
}
|
|
381
599
|
}
|
|
382
600
|
const pnpmWs = path18.join(root, "pnpm-workspace.yaml");
|
|
383
|
-
if (
|
|
384
|
-
for (const line of
|
|
601
|
+
if (fs18.existsSync(pnpmWs)) {
|
|
602
|
+
for (const line of fs18.readFileSync(pnpmWs, "utf8").split("\n")) {
|
|
385
603
|
const m = /^\s*-\s*['"]?([^'"\n]+)['"]?\s*$/.exec(line);
|
|
386
604
|
if (m) globs.push(m[1].trim());
|
|
387
605
|
}
|
|
@@ -389,7 +607,7 @@ function loadWorkspacePackages(root) {
|
|
|
389
607
|
for (const dir of expandWorkspaceGlobs(root, globs)) {
|
|
390
608
|
const pj = path18.join(dir, "package.json");
|
|
391
609
|
try {
|
|
392
|
-
const name = JSON.parse(
|
|
610
|
+
const name = JSON.parse(fs18.readFileSync(pj, "utf8")).name;
|
|
393
611
|
if (name) map.set(name, path18.relative(root, dir).split(path18.sep).join("/"));
|
|
394
612
|
} catch {
|
|
395
613
|
}
|
|
@@ -403,7 +621,7 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
403
621
|
const baseDir = path18.join(root, clean);
|
|
404
622
|
const recurse = glob.endsWith("**");
|
|
405
623
|
if (glob === clean) {
|
|
406
|
-
if (
|
|
624
|
+
if (fs18.existsSync(path18.join(baseDir, "package.json"))) out.add(baseDir);
|
|
407
625
|
continue;
|
|
408
626
|
}
|
|
409
627
|
collectPackageDirs(baseDir, recurse ? 4 : 1, out);
|
|
@@ -414,14 +632,14 @@ function collectPackageDirs(dir, depth, out) {
|
|
|
414
632
|
if (depth < 0) return;
|
|
415
633
|
let entries;
|
|
416
634
|
try {
|
|
417
|
-
entries =
|
|
635
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
418
636
|
} catch {
|
|
419
637
|
return;
|
|
420
638
|
}
|
|
421
639
|
for (const e of entries) {
|
|
422
640
|
if (!e.isDirectory() || e.name === "node_modules" || e.name.startsWith(".")) continue;
|
|
423
641
|
const child = path18.join(dir, e.name);
|
|
424
|
-
if (
|
|
642
|
+
if (fs18.existsSync(path18.join(child, "package.json"))) out.add(child);
|
|
425
643
|
else collectPackageDirs(child, depth - 1, out);
|
|
426
644
|
}
|
|
427
645
|
}
|
|
@@ -921,12 +1139,12 @@ function loadCoverage(root, explicit) {
|
|
|
921
1139
|
const candidates = (explicit && explicit.length ? explicit : DEFAULT_PATHS).map(
|
|
922
1140
|
(p) => path18.resolve(root, p)
|
|
923
1141
|
);
|
|
924
|
-
const found = candidates.filter((p) =>
|
|
1142
|
+
const found = candidates.filter((p) => fs18.existsSync(p));
|
|
925
1143
|
if (found.length === 0) return null;
|
|
926
1144
|
const map = /* @__PURE__ */ new Map();
|
|
927
1145
|
for (const file of found) {
|
|
928
1146
|
try {
|
|
929
|
-
const text =
|
|
1147
|
+
const text = fs18.readFileSync(file, "utf8");
|
|
930
1148
|
if (file.endsWith(".json")) mergeIstanbul(map, text, root);
|
|
931
1149
|
else mergeLcov(map, text, root);
|
|
932
1150
|
} catch {
|
|
@@ -1256,34 +1474,42 @@ var DEFAULT_INLINE_THRESHOLD = 24;
|
|
|
1256
1474
|
async function parseFiles(files, options = {}) {
|
|
1257
1475
|
const threshold = options.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;
|
|
1258
1476
|
const cores = Math.max(1, os.cpus()?.length ?? 1);
|
|
1259
|
-
const jobs = Math.max(1, options.jobs ?? (Math.min(cores - 1, files.length) || 1));
|
|
1477
|
+
const jobs = Math.max(1, options.jobs ?? envJobs() ?? (Math.min(cores - 1, files.length) || 1));
|
|
1260
1478
|
const workerFile = resolveWorkerFile();
|
|
1261
1479
|
const useInline = options.inline === true || jobs <= 1 || files.length < threshold || workerFile === null;
|
|
1262
1480
|
if (useInline) {
|
|
1263
1481
|
if (options.grammarsDir) setGrammarsOverride(options.grammarsDir);
|
|
1264
|
-
return sortByRel(await parseInline(files, options
|
|
1482
|
+
return sortByRel(await parseInline(files, options));
|
|
1265
1483
|
}
|
|
1266
|
-
return sortByRel(
|
|
1267
|
-
await parsePooled(files, jobs, workerFile, options.onProgress, options.grammarsDir)
|
|
1268
|
-
);
|
|
1484
|
+
return sortByRel(await parsePooled(files, jobs, workerFile, options));
|
|
1269
1485
|
}
|
|
1270
|
-
|
|
1486
|
+
var MEM_CHECK_EVERY = 64;
|
|
1487
|
+
async function parseInline(files, options) {
|
|
1488
|
+
const { onProgress, memoryBudgetMb = 0 } = options;
|
|
1271
1489
|
const out = [];
|
|
1272
1490
|
onProgress?.(0, files.length);
|
|
1273
1491
|
for (const file of files) {
|
|
1274
1492
|
try {
|
|
1275
|
-
const source =
|
|
1493
|
+
const source = fs18.readFileSync(file.abs, "utf8");
|
|
1276
1494
|
out.push(await parseSource(file.rel, file.lang.id, source));
|
|
1277
1495
|
} catch (err) {
|
|
1278
1496
|
out.push(emptyParse(file, `parse failed: ${err.message}`));
|
|
1279
1497
|
}
|
|
1280
1498
|
onProgress?.(out.length, files.length);
|
|
1499
|
+
if (out.length % MEM_CHECK_EVERY === 0) checkMemoryBudget("parse", memoryBudgetMb);
|
|
1281
1500
|
}
|
|
1282
1501
|
return out;
|
|
1283
1502
|
}
|
|
1284
|
-
async function parsePooled(files, jobs, workerFile,
|
|
1503
|
+
async function parsePooled(files, jobs, workerFile, options) {
|
|
1504
|
+
const { onProgress, grammarsDir, memoryBudgetMb = 0 } = options;
|
|
1285
1505
|
const { default: Tinypool } = await import('tinypool');
|
|
1286
|
-
const
|
|
1506
|
+
const workerHeapMb = envWorkerHeapMb();
|
|
1507
|
+
const pool = new Tinypool({
|
|
1508
|
+
filename: workerFile,
|
|
1509
|
+
maxThreads: jobs,
|
|
1510
|
+
minThreads: 1,
|
|
1511
|
+
...workerHeapMb ? { resourceLimits: { maxOldGenerationSizeMb: workerHeapMb } } : {}
|
|
1512
|
+
});
|
|
1287
1513
|
try {
|
|
1288
1514
|
const total = files.length;
|
|
1289
1515
|
const buckets = chunk(
|
|
@@ -1297,19 +1523,31 @@ async function parsePooled(files, jobs, workerFile, onProgress, grammarsDir) {
|
|
|
1297
1523
|
(b) => pool.run({ tasks: b, grammarsDir }).then((r) => {
|
|
1298
1524
|
done += b.length;
|
|
1299
1525
|
onProgress?.(done, total);
|
|
1526
|
+
checkMemoryBudget("parse", memoryBudgetMb);
|
|
1300
1527
|
return r;
|
|
1301
1528
|
})
|
|
1302
1529
|
)
|
|
1303
1530
|
);
|
|
1304
1531
|
return results.flat();
|
|
1532
|
+
} catch (err) {
|
|
1533
|
+
if (isWorkerOom(err)) {
|
|
1534
|
+
throw new ResourceLimitError(
|
|
1535
|
+
`graph build stopped: a parse worker exceeded its ${workerHeapMb ?? "?"} MiB heap cap (VG_WORKER_HEAP_MB). Raise the cap, exclude the offending files (--exclude), or run single-threaded with --jobs 1.`
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
throw err;
|
|
1305
1539
|
} finally {
|
|
1306
1540
|
await pool.destroy();
|
|
1307
1541
|
}
|
|
1308
1542
|
}
|
|
1543
|
+
function isWorkerOom(err) {
|
|
1544
|
+
const e = err;
|
|
1545
|
+
return e?.code === "ERR_WORKER_OUT_OF_MEMORY" || /out of memory/i.test(e?.message ?? "");
|
|
1546
|
+
}
|
|
1309
1547
|
function resolveWorkerFile() {
|
|
1310
1548
|
const here = path18.dirname(fileURLToPath(import.meta.url));
|
|
1311
1549
|
const candidate = path18.join(here, "parse-worker.js");
|
|
1312
|
-
return
|
|
1550
|
+
return fs18.existsSync(candidate) ? candidate : null;
|
|
1313
1551
|
}
|
|
1314
1552
|
function chunk(items, buckets) {
|
|
1315
1553
|
const out = Array.from({ length: Math.min(buckets, items.length || 1) }, () => []);
|
|
@@ -1769,9 +2007,9 @@ function loadCache(root, opts) {
|
|
|
1769
2007
|
grammars: opts.grammars,
|
|
1770
2008
|
entries: {}
|
|
1771
2009
|
};
|
|
1772
|
-
if (!opts.disabled &&
|
|
2010
|
+
if (!opts.disabled && fs18.existsSync(file)) {
|
|
1773
2011
|
try {
|
|
1774
|
-
const loaded = JSON.parse(
|
|
2012
|
+
const loaded = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
1775
2013
|
if (loaded.version === CACHE_VERSION && loaded.toolVersion === opts.toolVersion && loaded.grammars === opts.grammars && loaded.entries) {
|
|
1776
2014
|
data = loaded;
|
|
1777
2015
|
}
|
|
@@ -1792,8 +2030,8 @@ function loadCache(root, opts) {
|
|
|
1792
2030
|
}
|
|
1793
2031
|
},
|
|
1794
2032
|
save() {
|
|
1795
|
-
|
|
1796
|
-
|
|
2033
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
2034
|
+
fs18.writeFileSync(file, stableStringify(data, 0));
|
|
1797
2035
|
}
|
|
1798
2036
|
};
|
|
1799
2037
|
}
|
|
@@ -1808,6 +2046,13 @@ async function buildGraph(options) {
|
|
|
1808
2046
|
exclude: options.exclude,
|
|
1809
2047
|
paths: options.paths
|
|
1810
2048
|
});
|
|
2049
|
+
const limits = resolveLimits(options.limits);
|
|
2050
|
+
if (limits.maxFiles > 0 && files.length > limits.maxFiles) {
|
|
2051
|
+
throw new ResourceLimitError(
|
|
2052
|
+
`graph build stopped: ${files.length.toLocaleString()} files exceed the ${limits.maxFiles.toLocaleString()}-file limit. Scope the build (pass sub-paths, add --exclude globs, or --only <langs>), or set VG_MAX_FILES to raise the limit (0 disables it).`
|
|
2053
|
+
);
|
|
2054
|
+
}
|
|
2055
|
+
checkMemoryBudget("discovery", limits.memoryBudgetMb);
|
|
1811
2056
|
const grammars = grammarSetVersion();
|
|
1812
2057
|
const cache = loadCache(root, {
|
|
1813
2058
|
toolVersion: VERSION,
|
|
@@ -1818,27 +2063,46 @@ async function buildGraph(options) {
|
|
|
1818
2063
|
const fileStats = [];
|
|
1819
2064
|
const toParse = [];
|
|
1820
2065
|
const reused = [];
|
|
2066
|
+
const buildWarnings = [];
|
|
1821
2067
|
for (const file of files) {
|
|
1822
|
-
let hash = "";
|
|
1823
2068
|
let stat;
|
|
1824
2069
|
try {
|
|
1825
|
-
stat =
|
|
1826
|
-
|
|
2070
|
+
stat = fs18.statSync(file.abs);
|
|
2071
|
+
} catch {
|
|
2072
|
+
continue;
|
|
2073
|
+
}
|
|
2074
|
+
if (limits.maxFileBytes > 0 && stat.size > limits.maxFileBytes) {
|
|
2075
|
+
fileStats.push({
|
|
2076
|
+
rel: file.rel,
|
|
2077
|
+
size: stat.size,
|
|
2078
|
+
mtimeMs: stat.mtimeMs,
|
|
2079
|
+
hash: hashString(`vg:oversize:${stat.size}`)
|
|
2080
|
+
});
|
|
2081
|
+
buildWarnings.push(
|
|
2082
|
+
`${file.rel}: skipped \u2014 ${formatBytes(stat.size)} exceeds the ${formatBytes(limits.maxFileBytes)} per-file limit (set VG_MAX_FILE_BYTES to raise it, 0 to disable)`
|
|
2083
|
+
);
|
|
2084
|
+
continue;
|
|
2085
|
+
}
|
|
2086
|
+
let hash = "";
|
|
2087
|
+
try {
|
|
2088
|
+
hash = hashBytes(fs18.readFileSync(file.abs));
|
|
1827
2089
|
} catch {
|
|
1828
2090
|
continue;
|
|
1829
2091
|
}
|
|
1830
2092
|
hashes.set(file.rel, hash);
|
|
1831
2093
|
fileStats.push({ rel: file.rel, size: stat.size, mtimeMs: stat.mtimeMs, hash });
|
|
1832
|
-
const
|
|
1833
|
-
if (
|
|
2094
|
+
const cached2 = cache.get(file.rel, hash);
|
|
2095
|
+
if (cached2) reused.push(cached2);
|
|
1834
2096
|
else toParse.push(file);
|
|
1835
2097
|
}
|
|
1836
2098
|
const parsedNew = await parseFiles(toParse, {
|
|
1837
2099
|
jobs: options.jobs,
|
|
1838
2100
|
inline: options.inline,
|
|
1839
2101
|
onProgress: options.onParseProgress,
|
|
1840
|
-
grammarsDir: options.grammarsDir
|
|
2102
|
+
grammarsDir: options.grammarsDir,
|
|
2103
|
+
memoryBudgetMb: limits.memoryBudgetMb
|
|
1841
2104
|
});
|
|
2105
|
+
checkMemoryBudget("parse", limits.memoryBudgetMb);
|
|
1842
2106
|
for (const p of parsedNew) cache.set(p.rel, p);
|
|
1843
2107
|
const currentRels = new Set(files.map((f) => f.rel));
|
|
1844
2108
|
cache.prune(currentRels);
|
|
@@ -1846,14 +2110,21 @@ async function buildGraph(options) {
|
|
|
1846
2110
|
const parses = [...reused, ...parsedNew].sort(
|
|
1847
2111
|
(a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0
|
|
1848
2112
|
);
|
|
1849
|
-
const warnings = parses.flatMap((p) => p.warnings ?? []);
|
|
2113
|
+
const warnings = [...buildWarnings, ...parses.flatMap((p) => p.warnings ?? [])];
|
|
1850
2114
|
const moduleResolver = buildModuleResolver(root, new Set(parses.map((p) => p.rel)));
|
|
1851
2115
|
const resolved = resolve4(parses, moduleResolver);
|
|
2116
|
+
checkMemoryBudget("resolve", limits.memoryBudgetMb);
|
|
1852
2117
|
const nodeFileById = new Map(resolved.nodes.map((n) => [n.id, n.file]));
|
|
1853
2118
|
let edges = resolved.edges;
|
|
1854
2119
|
const resolvers = [...resolved.stats.resolvers];
|
|
1855
2120
|
let tscStats;
|
|
1856
|
-
|
|
2121
|
+
let tsFiles = options.noTsc ? [] : files.filter((f) => (f.lang.id === "ts" || f.lang.id === "tsx" || f.lang.id === "js") && hashes.has(f.rel)).map((f) => ({ rel: f.rel, abs: f.abs }));
|
|
2122
|
+
if (limits.tscMaxFiles > 0 && tsFiles.length > limits.tscMaxFiles) {
|
|
2123
|
+
warnings.push(
|
|
2124
|
+
`typescript resolver skipped \u2014 ${tsFiles.length.toLocaleString()} TS/JS files exceed the ${limits.tscMaxFiles.toLocaleString()}-file limit; calls use the heuristic resolver (set VG_TSC_MAX_FILES to raise it, 0 to disable)`
|
|
2125
|
+
);
|
|
2126
|
+
tsFiles = [];
|
|
2127
|
+
}
|
|
1857
2128
|
if (tsFiles.length) {
|
|
1858
2129
|
const res = tsResolveEdges(root, tsFiles, resolved.nodes);
|
|
1859
2130
|
if (res.stats.files > 0) {
|
|
@@ -1861,6 +2132,7 @@ async function buildGraph(options) {
|
|
|
1861
2132
|
if (!resolvers.includes("tsc")) resolvers.unshift("tsc");
|
|
1862
2133
|
tscStats = res.stats;
|
|
1863
2134
|
}
|
|
2135
|
+
checkMemoryBudget("typescript resolution", limits.memoryBudgetMb);
|
|
1864
2136
|
}
|
|
1865
2137
|
const scip = options.noScip ? null : loadScipIndex(root, options.scip);
|
|
1866
2138
|
let scipStats;
|
|
@@ -1875,6 +2147,7 @@ async function buildGraph(options) {
|
|
|
1875
2147
|
const coverage = options.noCoverage ? null : loadCoverage(root, options.coverage);
|
|
1876
2148
|
if (coverage) nodes = applyCoverage(nodes, coverage);
|
|
1877
2149
|
const analysis = analyze(nodes, linked.edges, { cluster: options.cluster });
|
|
2150
|
+
checkMemoryBudget("analysis", limits.memoryBudgetMb);
|
|
1878
2151
|
const languages = [...new Set(parses.map((p) => p.lang))].sort();
|
|
1879
2152
|
const edgeKinds = [...new Set(analysis.edges.map((e) => e.kind))].sort();
|
|
1880
2153
|
const corpusHash = computeCorpusHash(parses, hashes);
|
|
@@ -1943,9 +2216,9 @@ function loadScipIndex(root, explicit) {
|
|
|
1943
2216
|
].filter((p) => Boolean(p));
|
|
1944
2217
|
for (const file of candidates) {
|
|
1945
2218
|
const abs = path18.isAbsolute(file) ? file : path18.resolve(root, file);
|
|
1946
|
-
if (!
|
|
2219
|
+
if (!fs18.existsSync(abs)) continue;
|
|
1947
2220
|
try {
|
|
1948
|
-
const index = decodeScipIndex(new Uint8Array(
|
|
2221
|
+
const index = decodeScipIndex(new Uint8Array(fs18.readFileSync(abs)));
|
|
1949
2222
|
if (index.documents.length) {
|
|
1950
2223
|
return { index, tool: index.toolVersion ? `${index.toolName} ${index.toolVersion}` : index.toolName };
|
|
1951
2224
|
}
|
|
@@ -1987,7 +2260,7 @@ function isProcessAlive(pid) {
|
|
|
1987
2260
|
}
|
|
1988
2261
|
function lockIsStale(file, staleMs) {
|
|
1989
2262
|
try {
|
|
1990
|
-
const { pid, at } = JSON.parse(
|
|
2263
|
+
const { pid, at } = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
1991
2264
|
if (typeof at === "number" && Date.now() - at > staleMs) return true;
|
|
1992
2265
|
if (typeof pid === "number" && !isProcessAlive(pid)) return true;
|
|
1993
2266
|
return false;
|
|
@@ -1998,10 +2271,10 @@ function lockIsStale(file, staleMs) {
|
|
|
1998
2271
|
function acquireLock(file, staleMs = DEFAULT_LOCK_STALE_MS) {
|
|
1999
2272
|
const write = () => {
|
|
2000
2273
|
try {
|
|
2001
|
-
|
|
2002
|
-
const fd =
|
|
2003
|
-
|
|
2004
|
-
|
|
2274
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
2275
|
+
const fd = fs18.openSync(file, "wx");
|
|
2276
|
+
fs18.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: Date.now() }));
|
|
2277
|
+
fs18.closeSync(fd);
|
|
2005
2278
|
return true;
|
|
2006
2279
|
} catch {
|
|
2007
2280
|
return false;
|
|
@@ -2010,7 +2283,7 @@ function acquireLock(file, staleMs = DEFAULT_LOCK_STALE_MS) {
|
|
|
2010
2283
|
if (write()) return true;
|
|
2011
2284
|
if (lockIsStale(file, staleMs)) {
|
|
2012
2285
|
try {
|
|
2013
|
-
|
|
2286
|
+
fs18.rmSync(file, { force: true });
|
|
2014
2287
|
} catch {
|
|
2015
2288
|
}
|
|
2016
2289
|
return write();
|
|
@@ -2019,7 +2292,7 @@ function acquireLock(file, staleMs = DEFAULT_LOCK_STALE_MS) {
|
|
|
2019
2292
|
}
|
|
2020
2293
|
function releaseLock(file) {
|
|
2021
2294
|
try {
|
|
2022
|
-
|
|
2295
|
+
fs18.rmSync(file, { force: true });
|
|
2023
2296
|
} catch {
|
|
2024
2297
|
}
|
|
2025
2298
|
}
|
|
@@ -2036,7 +2309,7 @@ function modelReadyMarker(modelId) {
|
|
|
2036
2309
|
return path18.join(modelCacheDir(), `.ready-${safe(modelId)}`);
|
|
2037
2310
|
}
|
|
2038
2311
|
function isModelReady(modelId = resolveEmbedModel()) {
|
|
2039
|
-
return
|
|
2312
|
+
return fs18.existsSync(modelReadyMarker(modelId));
|
|
2040
2313
|
}
|
|
2041
2314
|
function unavailableMessage(reason) {
|
|
2042
2315
|
switch (reason) {
|
|
@@ -2053,13 +2326,13 @@ function unavailableMessage(reason) {
|
|
|
2053
2326
|
}
|
|
2054
2327
|
function modelCacheInfo(modelId = resolveEmbedModel()) {
|
|
2055
2328
|
const dir = modelCacheDir();
|
|
2056
|
-
return { dir, present: isModelReady(modelId) ||
|
|
2329
|
+
return { dir, present: isModelReady(modelId) || fs18.existsSync(dir), bytes: dirSize(dir) };
|
|
2057
2330
|
}
|
|
2058
2331
|
function clearModelCache() {
|
|
2059
2332
|
const dir = modelCacheDir();
|
|
2060
2333
|
const bytes = dirSize(dir);
|
|
2061
2334
|
try {
|
|
2062
|
-
|
|
2335
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
2063
2336
|
} catch {
|
|
2064
2337
|
}
|
|
2065
2338
|
return bytes;
|
|
@@ -2068,7 +2341,7 @@ function dirSize(dir) {
|
|
|
2068
2341
|
let total = 0;
|
|
2069
2342
|
let entries;
|
|
2070
2343
|
try {
|
|
2071
|
-
entries =
|
|
2344
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
2072
2345
|
} catch {
|
|
2073
2346
|
return 0;
|
|
2074
2347
|
}
|
|
@@ -2077,7 +2350,7 @@ function dirSize(dir) {
|
|
|
2077
2350
|
if (e.isDirectory()) total += dirSize(p);
|
|
2078
2351
|
else {
|
|
2079
2352
|
try {
|
|
2080
|
-
total +=
|
|
2353
|
+
total += fs18.statSync(p).size;
|
|
2081
2354
|
} catch {
|
|
2082
2355
|
}
|
|
2083
2356
|
}
|
|
@@ -2089,7 +2362,7 @@ function isPermissionError(e) {
|
|
|
2089
2362
|
return code === "EACCES" || code === "EPERM" || code === "EROFS";
|
|
2090
2363
|
}
|
|
2091
2364
|
function embeddingsCached(root, modelId) {
|
|
2092
|
-
return
|
|
2365
|
+
return fs18.existsSync(path18.join(cacheDir(root), `embeddings-${safe(modelId)}.json`));
|
|
2093
2366
|
}
|
|
2094
2367
|
async function loadEmbedder(options = {}) {
|
|
2095
2368
|
if (options.local) return null;
|
|
@@ -2103,7 +2376,7 @@ async function loadEmbedder(options = {}) {
|
|
|
2103
2376
|
if (!mod?.FlagEmbedding) return fail("not-installed");
|
|
2104
2377
|
const cache = modelCacheDir();
|
|
2105
2378
|
try {
|
|
2106
|
-
|
|
2379
|
+
fs18.mkdirSync(cache, { recursive: true });
|
|
2107
2380
|
} catch (e) {
|
|
2108
2381
|
return fail(isPermissionError(e) ? "no-permission" : "init-failed");
|
|
2109
2382
|
}
|
|
@@ -2118,7 +2391,7 @@ async function loadEmbedder(options = {}) {
|
|
|
2118
2391
|
"embedding model init timed out"
|
|
2119
2392
|
);
|
|
2120
2393
|
try {
|
|
2121
|
-
|
|
2394
|
+
fs18.writeFileSync(modelReadyMarker(modelId), (/* @__PURE__ */ new Date(0)).toISOString());
|
|
2122
2395
|
} catch {
|
|
2123
2396
|
}
|
|
2124
2397
|
return {
|
|
@@ -2225,15 +2498,15 @@ function countPending(graph, root, modelId) {
|
|
|
2225
2498
|
for (const n of graph.nodes) {
|
|
2226
2499
|
if (n.kind === "file" || n.kind === "external") continue;
|
|
2227
2500
|
const h = hashString(nodeEmbedText(n, areaLabel.get(n.area)));
|
|
2228
|
-
const
|
|
2229
|
-
if (!
|
|
2501
|
+
const cached2 = entries[n.id];
|
|
2502
|
+
if (!cached2 || cached2.hash !== h) pending++;
|
|
2230
2503
|
}
|
|
2231
2504
|
return pending;
|
|
2232
2505
|
}
|
|
2233
2506
|
function readCacheEntries(file, modelId) {
|
|
2234
|
-
if (!
|
|
2507
|
+
if (!fs18.existsSync(file)) return {};
|
|
2235
2508
|
try {
|
|
2236
|
-
const loaded = JSON.parse(
|
|
2509
|
+
const loaded = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
2237
2510
|
if (loaded.model === modelId && loaded.entries) return loaded.entries;
|
|
2238
2511
|
} catch {
|
|
2239
2512
|
}
|
|
@@ -2242,9 +2515,9 @@ function readCacheEntries(file, modelId) {
|
|
|
2242
2515
|
async function getNodeEmbeddings(graph, embedder, root, onProgress) {
|
|
2243
2516
|
const file = vectorCachePath(root, embedder.id);
|
|
2244
2517
|
let cache = { model: embedder.id, entries: {} };
|
|
2245
|
-
if (
|
|
2518
|
+
if (fs18.existsSync(file)) {
|
|
2246
2519
|
try {
|
|
2247
|
-
const loaded = JSON.parse(
|
|
2520
|
+
const loaded = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
2248
2521
|
if (loaded.model === embedder.id && loaded.entries) cache = loaded;
|
|
2249
2522
|
} catch {
|
|
2250
2523
|
}
|
|
@@ -2256,16 +2529,16 @@ async function getNodeEmbeddings(graph, embedder, root, onProgress) {
|
|
|
2256
2529
|
for (const n of targets) {
|
|
2257
2530
|
const text = nodeEmbedText(n, areaLabel.get(n.area));
|
|
2258
2531
|
const h = hashString(text);
|
|
2259
|
-
const
|
|
2260
|
-
if (
|
|
2532
|
+
const cached2 = cache.entries[n.id];
|
|
2533
|
+
if (cached2 && cached2.hash === h) vectors.set(n.id, cached2.vec);
|
|
2261
2534
|
else toEmbed.push({ id: n.id, text, hash: h });
|
|
2262
2535
|
}
|
|
2263
2536
|
const persist = () => {
|
|
2264
2537
|
try {
|
|
2265
|
-
|
|
2538
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
2266
2539
|
const tmp = `${file}.tmp.${process.pid}`;
|
|
2267
|
-
|
|
2268
|
-
|
|
2540
|
+
fs18.writeFileSync(tmp, JSON.stringify(cache));
|
|
2541
|
+
fs18.renameSync(tmp, file);
|
|
2269
2542
|
} catch {
|
|
2270
2543
|
}
|
|
2271
2544
|
};
|
|
@@ -2421,31 +2694,31 @@ function defaultGraphPath(root) {
|
|
|
2421
2694
|
}
|
|
2422
2695
|
function writeArtifacts(graph, options) {
|
|
2423
2696
|
const dir = vibgrateDir(options.root);
|
|
2424
|
-
|
|
2697
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
2425
2698
|
const graphPath = options.graphPath ?? defaultGraphPath(options.root);
|
|
2426
|
-
|
|
2699
|
+
fs18.mkdirSync(path18.dirname(graphPath), { recursive: true });
|
|
2427
2700
|
const tmp = `${graphPath}.${process.pid}.tmp`;
|
|
2428
2701
|
try {
|
|
2429
|
-
|
|
2430
|
-
|
|
2702
|
+
fs18.writeFileSync(tmp, serializeGraph(graph));
|
|
2703
|
+
fs18.renameSync(tmp, graphPath);
|
|
2431
2704
|
} catch (err) {
|
|
2432
|
-
|
|
2705
|
+
fs18.rmSync(tmp, { force: true });
|
|
2433
2706
|
throw err;
|
|
2434
2707
|
}
|
|
2435
2708
|
const written = { graphPath };
|
|
2436
2709
|
if (options.report !== false) {
|
|
2437
2710
|
const reportPath = path18.join(dir, "GRAPH_REPORT.md");
|
|
2438
|
-
|
|
2711
|
+
fs18.writeFileSync(reportPath, renderReport(graph));
|
|
2439
2712
|
written.reportPath = reportPath;
|
|
2440
2713
|
}
|
|
2441
2714
|
if (options.html !== false) {
|
|
2442
2715
|
const htmlPath = path18.join(dir, "graph.html");
|
|
2443
|
-
|
|
2716
|
+
fs18.writeFileSync(htmlPath, renderHtml(graph));
|
|
2444
2717
|
written.htmlPath = htmlPath;
|
|
2445
2718
|
}
|
|
2446
2719
|
if (graph.facts && graph.facts.length) {
|
|
2447
2720
|
const factsPath = path18.join(dir, "facts.jsonl");
|
|
2448
|
-
|
|
2721
|
+
fs18.writeFileSync(factsPath, graph.facts.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
2449
2722
|
written.factsPath = factsPath;
|
|
2450
2723
|
}
|
|
2451
2724
|
return written;
|
|
@@ -2459,14 +2732,14 @@ function writeSnapshot(root, corpusHash, fileStats, scope = {}) {
|
|
|
2459
2732
|
for (const f of fileStats) files[f.rel] = { size: f.size, mtimeMs: f.mtimeMs, hash: f.hash };
|
|
2460
2733
|
const snapshot = { version: SNAPSHOT_VERSION, corpusHash, scope: pruneScope(scope), files };
|
|
2461
2734
|
try {
|
|
2462
|
-
|
|
2463
|
-
|
|
2735
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
2736
|
+
fs18.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
|
|
2464
2737
|
} catch {
|
|
2465
2738
|
}
|
|
2466
2739
|
}
|
|
2467
2740
|
function loadSnapshot(root) {
|
|
2468
2741
|
try {
|
|
2469
|
-
const loaded = JSON.parse(
|
|
2742
|
+
const loaded = JSON.parse(fs18.readFileSync(snapshotPath(root), "utf8"));
|
|
2470
2743
|
if (loaded.version === SNAPSHOT_VERSION && loaded.files && typeof loaded.corpusHash === "string") {
|
|
2471
2744
|
return { ...loaded, scope: loaded.scope ?? {} };
|
|
2472
2745
|
}
|
|
@@ -2502,7 +2775,7 @@ function probeFreshness(root) {
|
|
|
2502
2775
|
}
|
|
2503
2776
|
let stat;
|
|
2504
2777
|
try {
|
|
2505
|
-
stat =
|
|
2778
|
+
stat = fs18.statSync(file.abs);
|
|
2506
2779
|
} catch {
|
|
2507
2780
|
drift.removed.push(file.rel);
|
|
2508
2781
|
continue;
|
|
@@ -2510,7 +2783,7 @@ function probeFreshness(root) {
|
|
|
2510
2783
|
if (stat.size === entry.size && stat.mtimeMs === entry.mtimeMs) continue;
|
|
2511
2784
|
let hash = "";
|
|
2512
2785
|
try {
|
|
2513
|
-
hash = hashBytes(
|
|
2786
|
+
hash = hashBytes(fs18.readFileSync(file.abs));
|
|
2514
2787
|
} catch {
|
|
2515
2788
|
drift.removed.push(file.rel);
|
|
2516
2789
|
continue;
|
|
@@ -2527,7 +2800,7 @@ function probeFreshness(root) {
|
|
|
2527
2800
|
}
|
|
2528
2801
|
if (absorbed && !hasDrift(drift)) {
|
|
2529
2802
|
try {
|
|
2530
|
-
|
|
2803
|
+
fs18.writeFileSync(snapshotPath(root), stableStringify(snapshot, 0));
|
|
2531
2804
|
} catch {
|
|
2532
2805
|
}
|
|
2533
2806
|
}
|
|
@@ -2573,8 +2846,8 @@ function usageError(message) {
|
|
|
2573
2846
|
}
|
|
2574
2847
|
function loadGraph(root, graphPath) {
|
|
2575
2848
|
const file = graphPath ?? defaultGraphPath(root);
|
|
2576
|
-
if (!
|
|
2577
|
-
return parseGraph(
|
|
2849
|
+
if (!fs18.existsSync(file)) return null;
|
|
2850
|
+
return parseGraph(fs18.readFileSync(file, "utf8"));
|
|
2578
2851
|
}
|
|
2579
2852
|
|
|
2580
2853
|
// src/engine/verify.ts
|
|
@@ -2583,10 +2856,10 @@ async function verifyDeterminism(opts) {
|
|
|
2583
2856
|
const base = { root: opts.root, only: opts.only, exclude: opts.exclude, generatedAt: PINNED };
|
|
2584
2857
|
const a = serializeGraph((await buildGraph({ ...base, noCache: true, jobs: opts.jobs })).graph);
|
|
2585
2858
|
const b = serializeGraph((await buildGraph({ ...base, noCache: true, jobs: 1 })).graph);
|
|
2586
|
-
const
|
|
2859
|
+
const cached2 = serializeGraph((await buildGraph({ ...base, noCache: false })).graph);
|
|
2587
2860
|
const checks = [
|
|
2588
2861
|
{ name: "run-to-run determinism", ok: a === b, detail: diffHint(a, b) },
|
|
2589
|
-
{ name: "cache safety (incremental == full)", ok: a ===
|
|
2862
|
+
{ name: "cache safety (incremental == full)", ok: a === cached2, detail: diffHint(a, cached2) }
|
|
2590
2863
|
];
|
|
2591
2864
|
return {
|
|
2592
2865
|
ok: checks.every((c) => c.ok),
|
|
@@ -2871,8 +3144,8 @@ async function refreshIfStale(root, opts = {}) {
|
|
|
2871
3144
|
const dir = vibgrateDir(root);
|
|
2872
3145
|
writeArtifacts(result.graph, {
|
|
2873
3146
|
root,
|
|
2874
|
-
report:
|
|
2875
|
-
html:
|
|
3147
|
+
report: fs18.existsSync(path18.join(dir, "GRAPH_REPORT.md")),
|
|
3148
|
+
html: fs18.existsSync(path18.join(dir, "graph.html"))
|
|
2876
3149
|
});
|
|
2877
3150
|
}
|
|
2878
3151
|
writeSnapshot(root, result.graph.provenance.corpusHash, result.fileStats, scope);
|
|
@@ -3049,9 +3322,9 @@ function testsToRun(graph, rootId, depth = 4) {
|
|
|
3049
3322
|
}
|
|
3050
3323
|
function detectRunner(root, lang) {
|
|
3051
3324
|
const pkgPath = path18.join(root, "package.json");
|
|
3052
|
-
if (
|
|
3325
|
+
if (fs18.existsSync(pkgPath)) {
|
|
3053
3326
|
try {
|
|
3054
|
-
const pkg = JSON.parse(
|
|
3327
|
+
const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
|
|
3055
3328
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
3056
3329
|
if (deps.vitest) return { name: "vitest", command: (f) => `npx vitest run ${f.join(" ")}`.trim() };
|
|
3057
3330
|
if (deps.jest) return { name: "jest", command: (f) => `npx jest ${f.join(" ")}`.trim() };
|
|
@@ -3059,10 +3332,10 @@ function detectRunner(root, lang) {
|
|
|
3059
3332
|
} catch {
|
|
3060
3333
|
}
|
|
3061
3334
|
}
|
|
3062
|
-
if (lang === "py" ||
|
|
3335
|
+
if (lang === "py" || fs18.existsSync(path18.join(root, "pyproject.toml")) || fs18.existsSync(path18.join(root, "pytest.ini"))) {
|
|
3063
3336
|
return { name: "pytest", command: (f) => `pytest ${f.join(" ")}`.trim() };
|
|
3064
3337
|
}
|
|
3065
|
-
if (lang === "go" ||
|
|
3338
|
+
if (lang === "go" || fs18.existsSync(path18.join(root, "go.mod"))) {
|
|
3066
3339
|
return { name: "go test", command: () => "go test ./..." };
|
|
3067
3340
|
}
|
|
3068
3341
|
if (lang === "cs" || hasFile(root, /\.csproj$/) || hasFile(root, /\.sln$/)) {
|
|
@@ -3073,7 +3346,7 @@ function detectRunner(root, lang) {
|
|
|
3073
3346
|
}
|
|
3074
3347
|
function hasFile(root, re) {
|
|
3075
3348
|
try {
|
|
3076
|
-
return
|
|
3349
|
+
return fs18.readdirSync(root).some((f) => re.test(f));
|
|
3077
3350
|
} catch {
|
|
3078
3351
|
return false;
|
|
3079
3352
|
}
|
|
@@ -3145,7 +3418,7 @@ function findManifests(root) {
|
|
|
3145
3418
|
if (depth > 8 || scanned > MAX_ENTRIES) return;
|
|
3146
3419
|
let entries;
|
|
3147
3420
|
try {
|
|
3148
|
-
entries =
|
|
3421
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
3149
3422
|
} catch {
|
|
3150
3423
|
return;
|
|
3151
3424
|
}
|
|
@@ -3169,7 +3442,7 @@ function npmDeps(files) {
|
|
|
3169
3442
|
for (const file of files) {
|
|
3170
3443
|
let pkg;
|
|
3171
3444
|
try {
|
|
3172
|
-
pkg = JSON.parse(
|
|
3445
|
+
pkg = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
3173
3446
|
} catch {
|
|
3174
3447
|
continue;
|
|
3175
3448
|
}
|
|
@@ -3186,7 +3459,7 @@ function installedNpmVersion(dir, name) {
|
|
|
3186
3459
|
for (let i = 0; i < 12; i++) {
|
|
3187
3460
|
const p = path18.join(cur, "node_modules", name, "package.json");
|
|
3188
3461
|
try {
|
|
3189
|
-
return JSON.parse(
|
|
3462
|
+
return JSON.parse(fs18.readFileSync(p, "utf8")).version;
|
|
3190
3463
|
} catch {
|
|
3191
3464
|
}
|
|
3192
3465
|
const parent = path18.dirname(cur);
|
|
@@ -3206,7 +3479,7 @@ function normalizePep503(name) {
|
|
|
3206
3479
|
function sitePackagesDirs(base) {
|
|
3207
3480
|
const out = [];
|
|
3208
3481
|
try {
|
|
3209
|
-
for (const d of
|
|
3482
|
+
for (const d of fs18.readdirSync(path18.join(base, "lib"))) {
|
|
3210
3483
|
if (d.startsWith("python")) out.push(path18.join(base, "lib", d, "site-packages"));
|
|
3211
3484
|
}
|
|
3212
3485
|
} catch {
|
|
@@ -3220,7 +3493,7 @@ function installedPypiVersion(root, name) {
|
|
|
3220
3493
|
for (const sp of sitePackagesDirs(path18.join(root, venv))) {
|
|
3221
3494
|
let entries;
|
|
3222
3495
|
try {
|
|
3223
|
-
entries =
|
|
3496
|
+
entries = fs18.readdirSync(sp);
|
|
3224
3497
|
} catch {
|
|
3225
3498
|
continue;
|
|
3226
3499
|
}
|
|
@@ -3235,7 +3508,7 @@ function installedPypiVersion(root, name) {
|
|
|
3235
3508
|
function installedPhpVersion(root, name) {
|
|
3236
3509
|
let data;
|
|
3237
3510
|
try {
|
|
3238
|
-
data = JSON.parse(
|
|
3511
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "vendor", "composer", "installed.json"), "utf8"));
|
|
3239
3512
|
} catch {
|
|
3240
3513
|
return void 0;
|
|
3241
3514
|
}
|
|
@@ -3254,7 +3527,7 @@ function pypiDeps(files) {
|
|
|
3254
3527
|
for (const file of files) {
|
|
3255
3528
|
let text;
|
|
3256
3529
|
try {
|
|
3257
|
-
text =
|
|
3530
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3258
3531
|
} catch {
|
|
3259
3532
|
continue;
|
|
3260
3533
|
}
|
|
@@ -3342,7 +3615,7 @@ function goDeps(files) {
|
|
|
3342
3615
|
for (const mod of files) {
|
|
3343
3616
|
let text;
|
|
3344
3617
|
try {
|
|
3345
|
-
text =
|
|
3618
|
+
text = fs18.readFileSync(mod, "utf8");
|
|
3346
3619
|
} catch {
|
|
3347
3620
|
continue;
|
|
3348
3621
|
}
|
|
@@ -3360,7 +3633,7 @@ function cargoDeps(files) {
|
|
|
3360
3633
|
for (const file of files) {
|
|
3361
3634
|
let text;
|
|
3362
3635
|
try {
|
|
3363
|
-
text =
|
|
3636
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3364
3637
|
} catch {
|
|
3365
3638
|
continue;
|
|
3366
3639
|
}
|
|
@@ -3392,7 +3665,7 @@ function rubyDeps(files) {
|
|
|
3392
3665
|
for (const file of files) {
|
|
3393
3666
|
let text;
|
|
3394
3667
|
try {
|
|
3395
|
-
text =
|
|
3668
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3396
3669
|
} catch {
|
|
3397
3670
|
continue;
|
|
3398
3671
|
}
|
|
@@ -3407,7 +3680,7 @@ function phpDeps(files) {
|
|
|
3407
3680
|
for (const file of files) {
|
|
3408
3681
|
let pkg;
|
|
3409
3682
|
try {
|
|
3410
|
-
pkg = JSON.parse(
|
|
3683
|
+
pkg = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
3411
3684
|
} catch {
|
|
3412
3685
|
continue;
|
|
3413
3686
|
}
|
|
@@ -3424,7 +3697,7 @@ function dotnetDeps(files) {
|
|
|
3424
3697
|
for (const file of files) {
|
|
3425
3698
|
let text;
|
|
3426
3699
|
try {
|
|
3427
|
-
text =
|
|
3700
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3428
3701
|
} catch {
|
|
3429
3702
|
continue;
|
|
3430
3703
|
}
|
|
@@ -3444,7 +3717,7 @@ function swiftDeps(files) {
|
|
|
3444
3717
|
for (const file of files) {
|
|
3445
3718
|
let text;
|
|
3446
3719
|
try {
|
|
3447
|
-
text =
|
|
3720
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3448
3721
|
} catch {
|
|
3449
3722
|
continue;
|
|
3450
3723
|
}
|
|
@@ -3466,7 +3739,7 @@ function dartDeps(files) {
|
|
|
3466
3739
|
for (const file of files) {
|
|
3467
3740
|
let text;
|
|
3468
3741
|
try {
|
|
3469
|
-
text =
|
|
3742
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3470
3743
|
} catch {
|
|
3471
3744
|
continue;
|
|
3472
3745
|
}
|
|
@@ -3491,7 +3764,7 @@ function javaDeps(files) {
|
|
|
3491
3764
|
for (const file of files) {
|
|
3492
3765
|
let text;
|
|
3493
3766
|
try {
|
|
3494
|
-
text =
|
|
3767
|
+
text = fs18.readFileSync(file, "utf8");
|
|
3495
3768
|
} catch {
|
|
3496
3769
|
continue;
|
|
3497
3770
|
}
|
|
@@ -3580,7 +3853,7 @@ function walk(dir, depth, onFile) {
|
|
|
3580
3853
|
if (depth < 0) return;
|
|
3581
3854
|
let entries;
|
|
3582
3855
|
try {
|
|
3583
|
-
entries =
|
|
3856
|
+
entries = fs18.readdirSync(dir, { withFileTypes: true });
|
|
3584
3857
|
} catch {
|
|
3585
3858
|
return;
|
|
3586
3859
|
}
|
|
@@ -3616,7 +3889,7 @@ function lockfileVersion(root, ecosystem, name) {
|
|
|
3616
3889
|
function gradleLock(root, name) {
|
|
3617
3890
|
let text;
|
|
3618
3891
|
try {
|
|
3619
|
-
text =
|
|
3892
|
+
text = fs18.readFileSync(path18.join(root, "gradle.lockfile"), "utf8");
|
|
3620
3893
|
} catch {
|
|
3621
3894
|
return void 0;
|
|
3622
3895
|
}
|
|
@@ -3626,7 +3899,7 @@ function gradleLock(root, name) {
|
|
|
3626
3899
|
function packageResolved(root, name) {
|
|
3627
3900
|
let data;
|
|
3628
3901
|
try {
|
|
3629
|
-
data = JSON.parse(
|
|
3902
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "Package.resolved"), "utf8"));
|
|
3630
3903
|
} catch {
|
|
3631
3904
|
return void 0;
|
|
3632
3905
|
}
|
|
@@ -3642,7 +3915,7 @@ function packageResolved(root, name) {
|
|
|
3642
3915
|
function pubspecLock(root, name) {
|
|
3643
3916
|
let text;
|
|
3644
3917
|
try {
|
|
3645
|
-
text =
|
|
3918
|
+
text = fs18.readFileSync(path18.join(root, "pubspec.lock"), "utf8");
|
|
3646
3919
|
} catch {
|
|
3647
3920
|
return void 0;
|
|
3648
3921
|
}
|
|
@@ -3666,7 +3939,7 @@ function escapeRegExp(s) {
|
|
|
3666
3939
|
function gemfileLock(root, name) {
|
|
3667
3940
|
let text;
|
|
3668
3941
|
try {
|
|
3669
|
-
text =
|
|
3942
|
+
text = fs18.readFileSync(path18.join(root, "Gemfile.lock"), "utf8");
|
|
3670
3943
|
} catch {
|
|
3671
3944
|
return void 0;
|
|
3672
3945
|
}
|
|
@@ -3676,7 +3949,7 @@ function gemfileLock(root, name) {
|
|
|
3676
3949
|
function composerLock(root, name) {
|
|
3677
3950
|
let data;
|
|
3678
3951
|
try {
|
|
3679
|
-
data = JSON.parse(
|
|
3952
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "composer.lock"), "utf8"));
|
|
3680
3953
|
} catch {
|
|
3681
3954
|
return void 0;
|
|
3682
3955
|
}
|
|
@@ -3691,7 +3964,7 @@ function composerLock(root, name) {
|
|
|
3691
3964
|
function packagesLock(root, name) {
|
|
3692
3965
|
let data;
|
|
3693
3966
|
try {
|
|
3694
|
-
data = JSON.parse(
|
|
3967
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "packages.lock.json"), "utf8"));
|
|
3695
3968
|
} catch {
|
|
3696
3969
|
return void 0;
|
|
3697
3970
|
}
|
|
@@ -3716,7 +3989,7 @@ function pypiLockVersion(root, name) {
|
|
|
3716
3989
|
function tomlPackageLock(root, file, name, normalize3) {
|
|
3717
3990
|
let text;
|
|
3718
3991
|
try {
|
|
3719
|
-
text =
|
|
3992
|
+
text = fs18.readFileSync(path18.join(root, file), "utf8");
|
|
3720
3993
|
} catch {
|
|
3721
3994
|
return void 0;
|
|
3722
3995
|
}
|
|
@@ -3733,7 +4006,7 @@ function tomlPackageLock(root, file, name, normalize3) {
|
|
|
3733
4006
|
function pipfileLock(root, name) {
|
|
3734
4007
|
let data;
|
|
3735
4008
|
try {
|
|
3736
|
-
data = JSON.parse(
|
|
4009
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "Pipfile.lock"), "utf8"));
|
|
3737
4010
|
} catch {
|
|
3738
4011
|
return void 0;
|
|
3739
4012
|
}
|
|
@@ -3752,7 +4025,7 @@ function pipfileLock(root, name) {
|
|
|
3752
4025
|
function packageLockVersion(root, name) {
|
|
3753
4026
|
let data;
|
|
3754
4027
|
try {
|
|
3755
|
-
data = JSON.parse(
|
|
4028
|
+
data = JSON.parse(fs18.readFileSync(path18.join(root, "package-lock.json"), "utf8"));
|
|
3756
4029
|
} catch {
|
|
3757
4030
|
return void 0;
|
|
3758
4031
|
}
|
|
@@ -3764,7 +4037,7 @@ function packageLockVersion(root, name) {
|
|
|
3764
4037
|
function yarnLockVersion(root, name) {
|
|
3765
4038
|
let text;
|
|
3766
4039
|
try {
|
|
3767
|
-
text =
|
|
4040
|
+
text = fs18.readFileSync(path18.join(root, "yarn.lock"), "utf8");
|
|
3768
4041
|
} catch {
|
|
3769
4042
|
return void 0;
|
|
3770
4043
|
}
|
|
@@ -3802,9 +4075,9 @@ function libId(name) {
|
|
|
3802
4075
|
}
|
|
3803
4076
|
function loadCatalog(root) {
|
|
3804
4077
|
const file = catalogPath(root);
|
|
3805
|
-
if (
|
|
4078
|
+
if (fs18.existsSync(file)) {
|
|
3806
4079
|
try {
|
|
3807
|
-
const data = JSON.parse(
|
|
4080
|
+
const data = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
3808
4081
|
if (data.schemaVersion === LIB_SCHEMA && data.libraries) return data;
|
|
3809
4082
|
} catch {
|
|
3810
4083
|
}
|
|
@@ -3812,7 +4085,7 @@ function loadCatalog(root) {
|
|
|
3812
4085
|
return { schemaVersion: LIB_SCHEMA, libraries: {} };
|
|
3813
4086
|
}
|
|
3814
4087
|
function saveCatalog(root, catalog) {
|
|
3815
|
-
|
|
4088
|
+
fs18.writeFileSync(catalogPath(root), `${stableStringify(catalog, 2)}
|
|
3816
4089
|
`);
|
|
3817
4090
|
}
|
|
3818
4091
|
function resolveLib(catalog, name) {
|
|
@@ -3889,16 +4162,16 @@ async function addLibrary(source, opts) {
|
|
|
3889
4162
|
type = source.endsWith("llms.txt") ? "llms.txt" : source.endsWith(".json") ? "openapi" : "website";
|
|
3890
4163
|
} else {
|
|
3891
4164
|
const abs = path18.resolve(root, source);
|
|
3892
|
-
if (!
|
|
4165
|
+
if (!fs18.existsSync(abs)) throw new Error(`source not found: ${source}`);
|
|
3893
4166
|
content = readLocal(abs);
|
|
3894
4167
|
type = "local";
|
|
3895
4168
|
}
|
|
3896
4169
|
const name = opts.name ?? inferName(source);
|
|
3897
4170
|
const id = libId(name);
|
|
3898
4171
|
const version = opts.version ?? installedVersion(root, name) ?? "*";
|
|
3899
|
-
|
|
4172
|
+
fs18.mkdirSync(libDir(root), { recursive: true });
|
|
3900
4173
|
const docFileAbs = path18.join(libDir(root), `${id}.md`);
|
|
3901
|
-
|
|
4174
|
+
fs18.writeFileSync(docFileAbs, content);
|
|
3902
4175
|
const entry = {
|
|
3903
4176
|
id,
|
|
3904
4177
|
name,
|
|
@@ -3915,13 +4188,13 @@ async function addLibrary(source, opts) {
|
|
|
3915
4188
|
}
|
|
3916
4189
|
function readDoc(root, entry) {
|
|
3917
4190
|
const abs = path18.resolve(root, entry.docFile);
|
|
3918
|
-
return
|
|
4191
|
+
return fs18.existsSync(abs) ? fs18.readFileSync(abs, "utf8") : "";
|
|
3919
4192
|
}
|
|
3920
4193
|
function npmPackageDir(root, name) {
|
|
3921
4194
|
let cur = root;
|
|
3922
4195
|
for (let i = 0; i < 12; i++) {
|
|
3923
4196
|
const dir = path18.join(cur, "node_modules", name);
|
|
3924
|
-
if (
|
|
4197
|
+
if (fs18.existsSync(path18.join(dir, "package.json"))) return dir;
|
|
3925
4198
|
const parent = path18.dirname(cur);
|
|
3926
4199
|
if (parent === cur) break;
|
|
3927
4200
|
cur = parent;
|
|
@@ -3935,7 +4208,7 @@ function localPackageDocs(root, name) {
|
|
|
3935
4208
|
for (const f of ["llms.txt", "README.md", "README.mdx", "README", "readme.md"]) {
|
|
3936
4209
|
const p = path18.join(dir, f);
|
|
3937
4210
|
try {
|
|
3938
|
-
const docs =
|
|
4211
|
+
const docs = fs18.readFileSync(p, "utf8");
|
|
3939
4212
|
if (docs.trim()) {
|
|
3940
4213
|
return { docs, version, source: path18.relative(root, p).split(path18.sep).join("/") };
|
|
3941
4214
|
}
|
|
@@ -3943,7 +4216,7 @@ function localPackageDocs(root, name) {
|
|
|
3943
4216
|
}
|
|
3944
4217
|
}
|
|
3945
4218
|
try {
|
|
3946
|
-
const pkg = JSON.parse(
|
|
4219
|
+
const pkg = JSON.parse(fs18.readFileSync(path18.join(dir, "package.json"), "utf8"));
|
|
3947
4220
|
if (pkg.description?.trim()) {
|
|
3948
4221
|
return {
|
|
3949
4222
|
docs: `# ${name}
|
|
@@ -3959,17 +4232,17 @@ ${pkg.description}`,
|
|
|
3959
4232
|
}
|
|
3960
4233
|
function dtsEntry(dir) {
|
|
3961
4234
|
try {
|
|
3962
|
-
const pkg = JSON.parse(
|
|
4235
|
+
const pkg = JSON.parse(fs18.readFileSync(path18.join(dir, "package.json"), "utf8"));
|
|
3963
4236
|
const rel2 = pkg.types ?? pkg.typings;
|
|
3964
4237
|
if (typeof rel2 === "string") {
|
|
3965
4238
|
const p = path18.join(dir, rel2);
|
|
3966
|
-
if (
|
|
4239
|
+
if (fs18.existsSync(p)) return p;
|
|
3967
4240
|
}
|
|
3968
4241
|
} catch {
|
|
3969
4242
|
}
|
|
3970
4243
|
for (const c of ["index.d.ts", "dist/index.d.ts", "lib/index.d.ts", "types/index.d.ts"]) {
|
|
3971
4244
|
const p = path18.join(dir, c);
|
|
3972
|
-
if (
|
|
4245
|
+
if (fs18.existsSync(p)) return p;
|
|
3973
4246
|
}
|
|
3974
4247
|
return void 0;
|
|
3975
4248
|
}
|
|
@@ -4002,7 +4275,7 @@ function localApiSurface(root, name) {
|
|
|
4002
4275
|
if (!dts) return void 0;
|
|
4003
4276
|
let src;
|
|
4004
4277
|
try {
|
|
4005
|
-
src =
|
|
4278
|
+
src = fs18.readFileSync(dts, "utf8");
|
|
4006
4279
|
} catch {
|
|
4007
4280
|
return void 0;
|
|
4008
4281
|
}
|
|
@@ -4010,36 +4283,36 @@ function localApiSurface(root, name) {
|
|
|
4010
4283
|
return decls.length ? decls.join("\n\n") : void 0;
|
|
4011
4284
|
}
|
|
4012
4285
|
function cloneAndReadGit(url) {
|
|
4013
|
-
const dir =
|
|
4286
|
+
const dir = fs18.mkdtempSync(path18.join(os.tmpdir(), "vg-lib-git-"));
|
|
4014
4287
|
try {
|
|
4015
4288
|
execFileSync("git", ["clone", "--depth", "1", "--quiet", url, dir], {
|
|
4016
4289
|
stdio: ["ignore", "ignore", "pipe"]
|
|
4017
4290
|
});
|
|
4018
4291
|
} catch (err) {
|
|
4019
|
-
|
|
4292
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
4020
4293
|
const detail = err instanceof Error && err.message ? `: ${err.message.split("\n")[0]}` : "";
|
|
4021
4294
|
throw new Error(`git clone failed for ${url}${detail}`);
|
|
4022
4295
|
}
|
|
4023
4296
|
try {
|
|
4024
4297
|
return readGitDocs(dir);
|
|
4025
4298
|
} finally {
|
|
4026
|
-
|
|
4299
|
+
fs18.rmSync(dir, { recursive: true, force: true });
|
|
4027
4300
|
}
|
|
4028
4301
|
}
|
|
4029
4302
|
function readGitDocs(dir) {
|
|
4030
4303
|
const docsDir = path18.join(dir, "docs");
|
|
4031
|
-
if (
|
|
4032
|
-
const readme = ["README.md", "README.mdx", "README.txt", "README.rst", "readme.md"].map((f) => path18.join(dir, f)).find((p) =>
|
|
4033
|
-
if (readme) return
|
|
4304
|
+
if (fs18.existsSync(docsDir) && fs18.statSync(docsDir).isDirectory()) return readLocal(docsDir);
|
|
4305
|
+
const readme = ["README.md", "README.mdx", "README.txt", "README.rst", "readme.md"].map((f) => path18.join(dir, f)).find((p) => fs18.existsSync(p));
|
|
4306
|
+
if (readme) return fs18.readFileSync(readme, "utf8");
|
|
4034
4307
|
return readLocal(dir);
|
|
4035
4308
|
}
|
|
4036
4309
|
function readLocal(abs) {
|
|
4037
|
-
const stat =
|
|
4038
|
-
if (stat.isFile()) return
|
|
4310
|
+
const stat = fs18.statSync(abs);
|
|
4311
|
+
if (stat.isFile()) return fs18.readFileSync(abs, "utf8");
|
|
4039
4312
|
const parts = [];
|
|
4040
|
-
const files =
|
|
4313
|
+
const files = fs18.readdirSync(abs, { withFileTypes: true }).filter((e) => e.isFile() && /\.(md|mdx|txt|rst)$/i.test(e.name)).map((e) => e.name).sort();
|
|
4041
4314
|
for (const f of files) parts.push(`<!-- ${f} -->
|
|
4042
|
-
${
|
|
4315
|
+
${fs18.readFileSync(path18.join(abs, f), "utf8")}`);
|
|
4043
4316
|
return parts.join("\n\n");
|
|
4044
4317
|
}
|
|
4045
4318
|
function inferName(source) {
|
|
@@ -4050,7 +4323,7 @@ function inferName(source) {
|
|
|
4050
4323
|
function findGitRoot(startDir = process.cwd()) {
|
|
4051
4324
|
let dir = path18.resolve(startDir);
|
|
4052
4325
|
for (; ; ) {
|
|
4053
|
-
if (
|
|
4326
|
+
if (fs18.existsSync(path18.join(dir, ".git"))) return dir;
|
|
4054
4327
|
const parent = path18.dirname(dir);
|
|
4055
4328
|
if (parent === dir) return null;
|
|
4056
4329
|
dir = parent;
|
|
@@ -4067,14 +4340,14 @@ function ensureGitignored(entry, startDir = process.cwd()) {
|
|
|
4067
4340
|
let existing = "";
|
|
4068
4341
|
let fileExisted = true;
|
|
4069
4342
|
try {
|
|
4070
|
-
existing =
|
|
4343
|
+
existing = fs18.readFileSync(gitignorePath, "utf8");
|
|
4071
4344
|
} catch {
|
|
4072
4345
|
fileExisted = false;
|
|
4073
4346
|
}
|
|
4074
4347
|
const alreadyPresent = existing.split(/\r?\n/).some((line) => normalizeEntry(line) === target);
|
|
4075
4348
|
if (alreadyPresent) return { status: "present", entry, gitignorePath };
|
|
4076
4349
|
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
4077
|
-
|
|
4350
|
+
fs18.appendFileSync(gitignorePath, `${needsLeadingNewline ? "\n" : ""}${entry}
|
|
4078
4351
|
`, "utf8");
|
|
4079
4352
|
return { status: fileExisted ? "added" : "created", entry, gitignorePath };
|
|
4080
4353
|
}
|
|
@@ -4250,41 +4523,51 @@ dsnCommand.command("create").description("Create a new DSN token").option("--ing
|
|
|
4250
4523
|
}
|
|
4251
4524
|
}
|
|
4252
4525
|
});
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4526
|
+
var STORE_DIRNAME = ".vibgrate";
|
|
4527
|
+
var STORE_FILENAME = "credentials.json";
|
|
4528
|
+
function homeCredentialsPath() {
|
|
4529
|
+
return path18.join(os.homedir(), STORE_DIRNAME, STORE_FILENAME);
|
|
4530
|
+
}
|
|
4531
|
+
function projectCredentialsPath(cwd = process.cwd()) {
|
|
4532
|
+
const root = findGitRoot(cwd) ?? cwd;
|
|
4533
|
+
return path18.join(root, STORE_DIRNAME, STORE_FILENAME);
|
|
4534
|
+
}
|
|
4535
|
+
function credentialsPath(opts = {}) {
|
|
4536
|
+
const override = process.env.VIBGRATE_CREDENTIALS?.trim();
|
|
4537
|
+
if (override) return path18.resolve(override);
|
|
4538
|
+
const local = projectCredentialsPath(opts.cwd);
|
|
4539
|
+
if (opts.local) return local;
|
|
4540
|
+
if (fs18.existsSync(local)) return local;
|
|
4541
|
+
return homeCredentialsPath();
|
|
4542
|
+
}
|
|
4543
|
+
function gitignoreEntryForCredentials(repoRoot, credsFile = credentialsPath()) {
|
|
4544
|
+
const rel2 = path18.relative(repoRoot, credsFile);
|
|
4261
4545
|
if (rel2 && !rel2.startsWith("..") && !path18.isAbsolute(rel2)) {
|
|
4262
4546
|
return rel2.split(path18.sep).join("/");
|
|
4263
4547
|
}
|
|
4264
|
-
return
|
|
4548
|
+
return `${STORE_DIRNAME}/${STORE_FILENAME}`;
|
|
4265
4549
|
}
|
|
4266
|
-
function readStoredCredentials() {
|
|
4550
|
+
function readStoredCredentials(opts = {}) {
|
|
4267
4551
|
try {
|
|
4268
|
-
const raw =
|
|
4552
|
+
const raw = fs18.readFileSync(credentialsPath(opts), "utf8");
|
|
4269
4553
|
const parsed = JSON.parse(raw);
|
|
4270
4554
|
return parsed && typeof parsed.dsn === "string" && parsed.dsn ? parsed : null;
|
|
4271
4555
|
} catch {
|
|
4272
4556
|
return null;
|
|
4273
4557
|
}
|
|
4274
4558
|
}
|
|
4275
|
-
function writeStoredCredentials(creds) {
|
|
4276
|
-
const
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
fs17.writeFileSync(file, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
4559
|
+
function writeStoredCredentials(creds, opts = {}) {
|
|
4560
|
+
const file = credentialsPath(opts);
|
|
4561
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
4562
|
+
fs18.writeFileSync(file, JSON.stringify(creds, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
4280
4563
|
try {
|
|
4281
|
-
|
|
4564
|
+
fs18.chmodSync(file, 384);
|
|
4282
4565
|
} catch {
|
|
4283
4566
|
}
|
|
4284
4567
|
}
|
|
4285
|
-
function clearStoredCredentials() {
|
|
4568
|
+
function clearStoredCredentials(opts = {}) {
|
|
4286
4569
|
try {
|
|
4287
|
-
|
|
4570
|
+
fs18.rmSync(credentialsPath(opts));
|
|
4288
4571
|
return true;
|
|
4289
4572
|
} catch {
|
|
4290
4573
|
return false;
|
|
@@ -4673,7 +4956,7 @@ var pushCommand = new Command("push").description("Push scan results to Vibgrate
|
|
|
4673
4956
|
function readScanArtifact(root) {
|
|
4674
4957
|
try {
|
|
4675
4958
|
const file = path18.join(root, ".vibgrate", "scan_result.json");
|
|
4676
|
-
return JSON.parse(
|
|
4959
|
+
return JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
4677
4960
|
} catch {
|
|
4678
4961
|
return null;
|
|
4679
4962
|
}
|
|
@@ -5648,13 +5931,13 @@ function ledgerPath(root) {
|
|
|
5648
5931
|
return path18.join(cacheDir(root), LEDGER);
|
|
5649
5932
|
}
|
|
5650
5933
|
function savingsRecorded(root) {
|
|
5651
|
-
return
|
|
5934
|
+
return fs18.existsSync(ledgerPath(root));
|
|
5652
5935
|
}
|
|
5653
5936
|
function recordSaving(root, entry, now) {
|
|
5654
5937
|
try {
|
|
5655
|
-
|
|
5938
|
+
fs18.mkdirSync(cacheDir(root), { recursive: true });
|
|
5656
5939
|
const line = JSON.stringify({ ts: now, ...entry });
|
|
5657
|
-
|
|
5940
|
+
fs18.appendFileSync(ledgerPath(root), line + "\n");
|
|
5658
5941
|
} catch {
|
|
5659
5942
|
}
|
|
5660
5943
|
}
|
|
@@ -5666,8 +5949,8 @@ function readSavings(root, days, now, ratePerM = DEFAULT_RATE_PER_M) {
|
|
|
5666
5949
|
let queries = 0;
|
|
5667
5950
|
let vgTokens = 0;
|
|
5668
5951
|
let baselineTokens = 0;
|
|
5669
|
-
if (
|
|
5670
|
-
for (const line of
|
|
5952
|
+
if (fs18.existsSync(file)) {
|
|
5953
|
+
for (const line of fs18.readFileSync(file, "utf8").split("\n")) {
|
|
5671
5954
|
if (!line.trim()) continue;
|
|
5672
5955
|
try {
|
|
5673
5956
|
const e = JSON.parse(line);
|
|
@@ -5723,9 +6006,9 @@ var GraphSource = class {
|
|
|
5723
6006
|
/** Current graph: auto-refreshed if the tree drifted, reloaded if the file changed. */
|
|
5724
6007
|
async get() {
|
|
5725
6008
|
if (this.refresh) await this.maybeRefresh();
|
|
5726
|
-
const stat =
|
|
6009
|
+
const stat = fs18.statSync(this.graphPath);
|
|
5727
6010
|
if (stat.mtimeMs !== this.cachedMtimeMs || !this.cached) {
|
|
5728
|
-
this.cached = parseGraph(
|
|
6011
|
+
this.cached = parseGraph(fs18.readFileSync(this.graphPath, "utf8"));
|
|
5729
6012
|
this.cachedMtimeMs = stat.mtimeMs;
|
|
5730
6013
|
}
|
|
5731
6014
|
return this.cached;
|
|
@@ -5806,8 +6089,8 @@ async function serveStdio(graphPath, opts = {}) {
|
|
|
5806
6089
|
await server.connect(new StdioServerTransport());
|
|
5807
6090
|
}
|
|
5808
6091
|
function sleep(ms) {
|
|
5809
|
-
return new Promise((
|
|
5810
|
-
const timer = setTimeout(
|
|
6092
|
+
return new Promise((resolve12) => {
|
|
6093
|
+
const timer = setTimeout(resolve12, ms);
|
|
5811
6094
|
timer.unref?.();
|
|
5812
6095
|
});
|
|
5813
6096
|
}
|
|
@@ -5960,9 +6243,9 @@ function assistantById(id) {
|
|
|
5960
6243
|
}
|
|
5961
6244
|
function detectServeLaunch(which = whichOnPath) {
|
|
5962
6245
|
const vg = which("vg");
|
|
5963
|
-
if (vg &&
|
|
6246
|
+
if (vg && isInstalledOwnBinary(vg)) return { command: "vg", args: ["serve"] };
|
|
5964
6247
|
const vibgrate = which("vibgrate");
|
|
5965
|
-
if (vibgrate &&
|
|
6248
|
+
if (vibgrate && isInstalledOwnBinary(vibgrate)) {
|
|
5966
6249
|
return {
|
|
5967
6250
|
command: "vibgrate",
|
|
5968
6251
|
args: ["serve"],
|
|
@@ -5975,27 +6258,6 @@ function detectServeLaunch(which = whichOnPath) {
|
|
|
5975
6258
|
note: "vg is not installed on PATH \u2014 registered an npx launcher. Install globally (`npm i -g @vibgrate/cli`) and rerun `vg install` for a faster startup."
|
|
5976
6259
|
};
|
|
5977
6260
|
}
|
|
5978
|
-
function whichOnPath(cmd) {
|
|
5979
|
-
try {
|
|
5980
|
-
const out = execFileSync(process.platform === "win32" ? "where" : "which", [cmd], {
|
|
5981
|
-
encoding: "utf8",
|
|
5982
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
5983
|
-
}).trim().split(/\r?\n/)[0];
|
|
5984
|
-
return out || null;
|
|
5985
|
-
} catch {
|
|
5986
|
-
return null;
|
|
5987
|
-
}
|
|
5988
|
-
}
|
|
5989
|
-
function isOwnBinary(binPath) {
|
|
5990
|
-
try {
|
|
5991
|
-
const real = fs17.realpathSync(binPath);
|
|
5992
|
-
if (/[\\/]@vibgrate[\\/]cli[\\/]/.test(real)) return true;
|
|
5993
|
-
const head = fs17.readFileSync(real, { encoding: "utf8" }).slice(0, 2048);
|
|
5994
|
-
return head.includes("@vibgrate/cli") || head.includes("vibgrate");
|
|
5995
|
-
} catch {
|
|
5996
|
-
return false;
|
|
5997
|
-
}
|
|
5998
|
-
}
|
|
5999
6261
|
function installAssistant(a, opts) {
|
|
6000
6262
|
const wrote = [];
|
|
6001
6263
|
const skipped = [];
|
|
@@ -6030,23 +6292,23 @@ function uninstallAssistant(a, root, purge) {
|
|
|
6030
6292
|
const file = path18.join(root, a.nudge.file);
|
|
6031
6293
|
if (a.nudge.kind === "block") {
|
|
6032
6294
|
if (removeBlock(file)) removed.push(a.nudge.file);
|
|
6033
|
-
} else if (
|
|
6034
|
-
|
|
6295
|
+
} else if (fs18.existsSync(file)) {
|
|
6296
|
+
fs18.rmSync(file);
|
|
6035
6297
|
removed.push(a.nudge.file);
|
|
6036
6298
|
}
|
|
6037
6299
|
}
|
|
6038
6300
|
if (purge && a.skill) {
|
|
6039
6301
|
const file = path18.join(root, a.skill);
|
|
6040
|
-
if (
|
|
6041
|
-
|
|
6302
|
+
if (fs18.existsSync(file)) {
|
|
6303
|
+
fs18.rmSync(file);
|
|
6042
6304
|
removed.push(a.skill);
|
|
6043
6305
|
}
|
|
6044
6306
|
}
|
|
6045
6307
|
return removed;
|
|
6046
6308
|
}
|
|
6047
6309
|
function writeFileEnsured(file, content) {
|
|
6048
|
-
|
|
6049
|
-
|
|
6310
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
6311
|
+
fs18.writeFileSync(file, content);
|
|
6050
6312
|
}
|
|
6051
6313
|
function upsertMcp(file, target, launch) {
|
|
6052
6314
|
const config = readJson(file);
|
|
@@ -6059,7 +6321,7 @@ function upsertMcp(file, target, launch) {
|
|
|
6059
6321
|
`);
|
|
6060
6322
|
}
|
|
6061
6323
|
function removeMcp(file, target) {
|
|
6062
|
-
if (!
|
|
6324
|
+
if (!fs18.existsSync(file)) return false;
|
|
6063
6325
|
const config = readJson(file);
|
|
6064
6326
|
const bag = config[target.key];
|
|
6065
6327
|
if (!bag || !(bag.vg !== void 0)) return false;
|
|
@@ -6082,8 +6344,8 @@ ${stripMarkers(nudgeMarkdown(smallRepo))}` : stripMarkers(nudgeMarkdown(smallRep
|
|
|
6082
6344
|
upsertBlock(file, nudgeMarkdown(smallRepo));
|
|
6083
6345
|
}
|
|
6084
6346
|
function upsertBlock(file, block) {
|
|
6085
|
-
|
|
6086
|
-
let existing =
|
|
6347
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
6348
|
+
let existing = fs18.existsSync(file) ? fs18.readFileSync(file, "utf8") : "";
|
|
6087
6349
|
const re = new RegExp(`${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}`);
|
|
6088
6350
|
if (re.test(existing)) existing = existing.replace(re, block);
|
|
6089
6351
|
else existing = existing.length ? `${existing.replace(/\s*$/, "")}
|
|
@@ -6091,20 +6353,20 @@ function upsertBlock(file, block) {
|
|
|
6091
6353
|
${block}
|
|
6092
6354
|
` : `${block}
|
|
6093
6355
|
`;
|
|
6094
|
-
|
|
6356
|
+
fs18.writeFileSync(file, existing);
|
|
6095
6357
|
}
|
|
6096
6358
|
function removeBlock(file) {
|
|
6097
|
-
if (!
|
|
6098
|
-
const existing =
|
|
6359
|
+
if (!fs18.existsSync(file)) return false;
|
|
6360
|
+
const existing = fs18.readFileSync(file, "utf8");
|
|
6099
6361
|
const re = new RegExp(`\\n*${escapeRe(NUDGE_BEGIN)}[\\s\\S]*?${escapeRe(NUDGE_END)}\\n*`);
|
|
6100
6362
|
if (!re.test(existing)) return false;
|
|
6101
|
-
|
|
6363
|
+
fs18.writeFileSync(file, existing.replace(re, "\n"));
|
|
6102
6364
|
return true;
|
|
6103
6365
|
}
|
|
6104
6366
|
function readJson(file) {
|
|
6105
|
-
if (!
|
|
6367
|
+
if (!fs18.existsSync(file)) return {};
|
|
6106
6368
|
try {
|
|
6107
|
-
const parsed = JSON.parse(
|
|
6369
|
+
const parsed = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
6108
6370
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6109
6371
|
return parsed;
|
|
6110
6372
|
}
|
|
@@ -6262,6 +6524,6 @@ function spdx(ctx) {
|
|
|
6262
6524
|
return JSON.stringify(doc, null, 2) + "\n";
|
|
6263
6525
|
}
|
|
6264
6526
|
|
|
6265
|
-
export { ASSISTANTS, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, SCHEMA_VERSION, SKIP_DIRS, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, exportGraph, fetchHostedDocs, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeSnapshot, writeStoredCredentials };
|
|
6266
|
-
//# sourceMappingURL=chunk-
|
|
6267
|
-
//# sourceMappingURL=chunk-
|
|
6527
|
+
export { ASSISTANTS, CliError, ECOSYSTEMS, ExitCode, FREE_PACK, GraphIndex, GraphSource, NPX_INVOCATION, ResourceLimitError, SCHEMA_VERSION, SKIP_DIRS, SKIP_FILES, TOOLS, UsageError, addLibrary, analyze, applyCoverage, applyStaticTestLinkage, assessDocQuality, assistantById, availableRegionIds, buildFacts, buildGraph, buildModuleResolver, cacheDir, catalogPath, clearModelCache, clearStoredCredentials, cosine, countPending, coveringTests, createServer, createWorkspaceDsn, credentialsPath, dashHostForIngestHost, decodeScipIndex, defaultGraphPath, detectRunner, detectServeLaunch, discover, discoverModels, driftCount, driftFor, dsnCommand, embeddingsCached, enrichOnline, ensureGitignored, exportGraph, fetchHostedDocs, findGitRoot, findNodes, formatForExt, getNodeEmbeddings, gitignoreEntryForCredentials, groundGraph, hasDrift, identifierParts, impactOf, installAssistant, inventory, isModelReady, isTestFile, libDir, libId, loadCatalog, loadCoverage, loadEmbedder, loadGraph, loadSnapshot, localApiSurface, localPackageDocs, modelCacheInfo, nodeById, nodeEmbedText, parseDsn, parseGraph, parseJsonc, probeFreshness, publishPrivateLibrary, pushCommand, queryGraph, queryGraphSemantic, readDoc, readSavings, readScanArtifact, recordSaving, refreshIfStale, relativeResolver, renderHtml, renderReport, resolveCliInvocation, resolveDsn, resolveEmbedModel, resolveIngestHost, resolveLib, resolveLimits, resolveOne, resolveVersion, saveCatalog, savingsRecorded, scipEdges, selectForBudget, serializeGraph, serveStdio, shortestPath, stableStringify, symbolsFromApi, testsToRun, unavailableMessage, uninstallAssistant, uploadScanArtifact, usageError, verifyDeterminism, vibgrateDir, writeArtifacts, writeSnapshot, writeStoredCredentials };
|
|
6528
|
+
//# sourceMappingURL=chunk-YODVLV37.js.map
|
|
6529
|
+
//# sourceMappingURL=chunk-YODVLV37.js.map
|