docbridge 0.12.0 → 0.13.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/CHANGELOG.md +38 -1
- package/README.md +3 -3
- package/dist/bin/darwin-arm64/SHA256SUMS +3 -3
- package/dist/bin/darwin-arm64/docbridge-go-scanner +0 -0
- package/dist/bin/darwin-arm64/docbridge-swift-scanner +0 -0
- package/dist/bin/darwin-arm64/docbridge_dart_scanner +0 -0
- package/dist/bin/linux-x64/SHA256SUMS +2 -2
- package/dist/bin/linux-x64/docbridge-go-scanner +0 -0
- package/dist/bin/linux-x64/docbridge-swift-scanner +1 -1
- package/dist/index.js +199 -325
- package/dist/workers/java/docbridge-java-scanner.jar +0 -0
- package/docs/README.md +1 -1
- package/docs/user/configuration.md +37 -30
- package/docs/user/getting-started.md +1 -1
- package/docs/user/linking.md +28 -1
- package/docs/user/troubleshooting.md +16 -12
- package/package.json +1 -1
- package/schemas/context-output.schema.json +11 -1
- package/schemas/docbridge.schema.json +24 -1
- package/schemas/graph-output.schema.json +11 -1
package/dist/index.js
CHANGED
|
@@ -175581,7 +175581,7 @@ import { join as join15, resolve as resolve5 } from "node:path";
|
|
|
175581
175581
|
// package.json
|
|
175582
175582
|
var package_default = {
|
|
175583
175583
|
name: "docbridge",
|
|
175584
|
-
version: "0.
|
|
175584
|
+
version: "0.13.1",
|
|
175585
175585
|
description: "A CLI that links Markdown specifications and code declarations. Runs on Node.js and Bun.",
|
|
175586
175586
|
keywords: [
|
|
175587
175587
|
"bun",
|
|
@@ -175781,7 +175781,8 @@ var KNOWN_CODE_LANGUAGES = [
|
|
|
175781
175781
|
"go",
|
|
175782
175782
|
"javascript",
|
|
175783
175783
|
"python",
|
|
175784
|
-
"ruby"
|
|
175784
|
+
"ruby",
|
|
175785
|
+
"java"
|
|
175785
175786
|
];
|
|
175786
175787
|
function isCodeLanguage(value) {
|
|
175787
175788
|
return KNOWN_CODE_LANGUAGES.includes(value);
|
|
@@ -175794,7 +175795,8 @@ var LANGUAGE_SUFFIXES = {
|
|
|
175794
175795
|
go: [".go"],
|
|
175795
175796
|
javascript: [".js", ".jsx", ".mjs", ".cjs"],
|
|
175796
175797
|
python: [".py"],
|
|
175797
|
-
ruby: [".rb"]
|
|
175798
|
+
ruby: [".rb"],
|
|
175799
|
+
java: [".java"]
|
|
175798
175800
|
};
|
|
175799
175801
|
var EXCLUDED_SUFFIXES = {
|
|
175800
175802
|
typescript: [".d.ts", ".d.mts", ".d.cts"],
|
|
@@ -175804,7 +175806,8 @@ var EXCLUDED_SUFFIXES = {
|
|
|
175804
175806
|
go: [],
|
|
175805
175807
|
javascript: [],
|
|
175806
175808
|
python: [],
|
|
175807
|
-
ruby: []
|
|
175809
|
+
ruby: [],
|
|
175810
|
+
java: []
|
|
175808
175811
|
};
|
|
175809
175812
|
function codeFenceLanguage(language, filePath) {
|
|
175810
175813
|
if (language === "typescript") {
|
|
@@ -175924,7 +175927,8 @@ var LANGUAGE_VISIBILITY = {
|
|
|
175924
175927
|
go: ["exported", "unexported"],
|
|
175925
175928
|
javascript: ["public", "protected", "private"],
|
|
175926
175929
|
python: ["public", "private"],
|
|
175927
|
-
ruby: ["public", "protected", "private"]
|
|
175930
|
+
ruby: ["public", "protected", "private"],
|
|
175931
|
+
java: ["public", "protected", "package", "private"]
|
|
175928
175932
|
};
|
|
175929
175933
|
function loadConfig(projectRoot) {
|
|
175930
175934
|
let rawText;
|
|
@@ -176061,10 +176065,6 @@ function validateCodeEntry(language, value, diagnostics) {
|
|
|
176061
176065
|
}
|
|
176062
176066
|
function validateVisibilityOptions(language, values, target, diagnostics) {
|
|
176063
176067
|
const allowed = LANGUAGE_VISIBILITY[language];
|
|
176064
|
-
if (allowed.length === 0) {
|
|
176065
|
-
diagnostics.push(configDiagnostic2("config_invalid_value", `${target}.visibility`, `\`${target}.visibility\` is not supported for ${language}.`));
|
|
176066
|
-
return;
|
|
176067
|
-
}
|
|
176068
176068
|
for (const value of values) {
|
|
176069
176069
|
if (!allowed.includes(value)) {
|
|
176070
176070
|
diagnostics.push(configDiagnostic2("config_invalid_value", `${target}.visibility`, `Unsupported ${language} visibility: ${value}. Supported values: ${allowed.join(", ")}.`));
|
|
@@ -177775,9 +177775,6 @@ function duplicateLinkDiagnostic(source, target, location, range) {
|
|
|
177775
177775
|
// src/scan/code/typescript.ts
|
|
177776
177776
|
var typeScriptAdapter = {
|
|
177777
177777
|
language: "typescript",
|
|
177778
|
-
scanFile(filePath, content, options) {
|
|
177779
|
-
return scanTypeScript(filePath, content, options);
|
|
177780
|
-
},
|
|
177781
177778
|
scanFiles(files, options) {
|
|
177782
177779
|
return files.map(({ filePath, content }) => scanTypeScript(filePath, content, options));
|
|
177783
177780
|
}
|
|
@@ -178246,12 +178243,9 @@ function firstToken(text) {
|
|
|
178246
178243
|
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync3, realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
178247
178244
|
import { extname, isAbsolute as isAbsolute2, join as join7, resolve as resolve2 } from "node:path";
|
|
178248
178245
|
|
|
178249
|
-
// src/scan/code/worker/runtime-probe.ts
|
|
178250
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
178251
|
-
|
|
178252
178246
|
// src/scan/code/worker/scanner-worker.ts
|
|
178253
178247
|
var import__2020 = __toESM(require_2020(), 1);
|
|
178254
|
-
import { spawn
|
|
178248
|
+
import { spawn } from "node:child_process";
|
|
178255
178249
|
import { mkdirSync } from "node:fs";
|
|
178256
178250
|
import { tmpdir } from "node:os";
|
|
178257
178251
|
import { dirname, join as join4 } from "node:path";
|
|
@@ -178450,14 +178444,12 @@ var scanner_worker_schema_default = {
|
|
|
178450
178444
|
// src/scan/code/worker/scanner-worker.ts
|
|
178451
178445
|
var WORKER_OUTPUT_LIMIT_BYTES = 1024 * 1024 * 1024;
|
|
178452
178446
|
var KILLED_WORKER_GRACE_MS = 500;
|
|
178453
|
-
|
|
178454
|
-
|
|
178455
|
-
|
|
178456
|
-
|
|
178457
|
-
|
|
178458
|
-
};
|
|
178447
|
+
var liveWorkers = new Map;
|
|
178448
|
+
var compiledResponseValidator;
|
|
178449
|
+
function responseValidator() {
|
|
178450
|
+
compiledResponseValidator ??= compileWorkerResponseValidator();
|
|
178451
|
+
return compiledResponseValidator;
|
|
178459
178452
|
}
|
|
178460
|
-
var responseValidator = createLazyWorkerResponseValidator(compileWorkerResponseValidator);
|
|
178461
178453
|
function compileWorkerResponseValidator() {
|
|
178462
178454
|
const ajv = new import__2020.default({ allErrors: true, strict: true });
|
|
178463
178455
|
ajv.addSchema(common_output_schema_default);
|
|
@@ -178468,13 +178460,10 @@ function compileWorkerResponseValidator() {
|
|
|
178468
178460
|
});
|
|
178469
178461
|
}
|
|
178470
178462
|
function invokeScannerWorker(request, command, run = runScannerWorkerProcess, stripEnv = []) {
|
|
178471
|
-
|
|
178472
|
-
}
|
|
178473
|
-
function invokeScannerWorkerAsync(request, command, runAsync = runScannerWorkerProcessAsync, stripEnv = []) {
|
|
178474
|
-
const run = runAsync(processInput(request, command, stripEnv));
|
|
178463
|
+
const task = run(processInput(request, command, stripEnv));
|
|
178475
178464
|
return {
|
|
178476
|
-
promise:
|
|
178477
|
-
cancel: () =>
|
|
178465
|
+
promise: task.promise.then((processResult) => interpretWorkerProcess(request, command, processResult)),
|
|
178466
|
+
cancel: () => task.cancel()
|
|
178478
178467
|
};
|
|
178479
178468
|
}
|
|
178480
178469
|
function processInput(request, command, stripEnv) {
|
|
@@ -178550,36 +178539,6 @@ function workerTimeoutMs(fileCount) {
|
|
|
178550
178539
|
return 30000 + 1000 * fileCount;
|
|
178551
178540
|
}
|
|
178552
178541
|
function runScannerWorkerProcess(input) {
|
|
178553
|
-
const maxOutputBytes = input.maxOutputBytes ?? WORKER_OUTPUT_LIMIT_BYTES;
|
|
178554
|
-
try {
|
|
178555
|
-
const [executable = "", ...args] = input.command;
|
|
178556
|
-
const result = spawnSync(executable, args, {
|
|
178557
|
-
env: workerProcessEnv(input.stripEnv),
|
|
178558
|
-
input: input.stdin,
|
|
178559
|
-
encoding: "utf8",
|
|
178560
|
-
maxBuffer: maxOutputBytes,
|
|
178561
|
-
killSignal: "SIGKILL",
|
|
178562
|
-
...input.timeoutMs === undefined ? {} : { timeout: input.timeoutMs }
|
|
178563
|
-
});
|
|
178564
|
-
return syncWorkerProcessResult(result, input.timeoutMs, maxOutputBytes);
|
|
178565
|
-
} catch (error) {
|
|
178566
|
-
return { ok: false, kind: "start", error, stderr: "" };
|
|
178567
|
-
}
|
|
178568
|
-
}
|
|
178569
|
-
function syncWorkerProcessResult(result, timeoutMs, maxOutputBytes) {
|
|
178570
|
-
const stderr = result.stderr ?? "";
|
|
178571
|
-
if (result.error !== undefined) {
|
|
178572
|
-
return syncSpawnFailure(result.error, workerStarted(result), timeoutMs, maxOutputBytes, stderr);
|
|
178573
|
-
}
|
|
178574
|
-
if (Buffer.byteLength(result.stdout ?? "") + Buffer.byteLength(stderr) > maxOutputBytes) {
|
|
178575
|
-
return { ok: false, kind: "execution", error: outputLimitError(maxOutputBytes), stderr };
|
|
178576
|
-
}
|
|
178577
|
-
if (typeof result.status !== "number") {
|
|
178578
|
-
return { ok: false, kind: "execution", error: signalError(result.signal), stderr };
|
|
178579
|
-
}
|
|
178580
|
-
return { ok: true, exitCode: result.status, stdout: result.stdout ?? "", stderr };
|
|
178581
|
-
}
|
|
178582
|
-
function runScannerWorkerProcessAsync(input) {
|
|
178583
178542
|
const run = deferred();
|
|
178584
178543
|
let settled = false;
|
|
178585
178544
|
let timer;
|
|
@@ -178589,6 +178548,9 @@ function runScannerWorkerProcessAsync(input) {
|
|
|
178589
178548
|
return;
|
|
178590
178549
|
}
|
|
178591
178550
|
settled = true;
|
|
178551
|
+
if (child !== undefined) {
|
|
178552
|
+
liveWorkers.delete(child);
|
|
178553
|
+
}
|
|
178592
178554
|
clearTimeout(timer);
|
|
178593
178555
|
clearTimeout(grace);
|
|
178594
178556
|
complete();
|
|
@@ -178597,24 +178559,34 @@ function runScannerWorkerProcessAsync(input) {
|
|
|
178597
178559
|
let child;
|
|
178598
178560
|
try {
|
|
178599
178561
|
const [executable = "", ...args] = input.command;
|
|
178600
|
-
child = spawn(executable, args, {
|
|
178562
|
+
child = spawn(executable, args, {
|
|
178563
|
+
env: workerProcessEnv(input.stripEnv),
|
|
178564
|
+
detached: ownGroup,
|
|
178565
|
+
windowsHide: true
|
|
178566
|
+
});
|
|
178601
178567
|
} catch (error) {
|
|
178602
178568
|
settle(() => run.resolve({ ok: false, kind: "start", error, stderr: "" }));
|
|
178603
178569
|
return { promise: run.promise, cancel: () => {
|
|
178604
178570
|
return;
|
|
178605
178571
|
} };
|
|
178606
178572
|
}
|
|
178573
|
+
liveWorkers.set(child, ownGroup);
|
|
178607
178574
|
const maxOutputBytes = input.maxOutputBytes ?? WORKER_OUTPUT_LIMIT_BYTES;
|
|
178608
178575
|
const budget = { bytes: 0, limit: maxOutputBytes };
|
|
178609
178576
|
const stdout = new OutputCollector(budget);
|
|
178610
178577
|
const stderr = new OutputCollector(budget);
|
|
178611
178578
|
let failure;
|
|
178612
|
-
|
|
178579
|
+
let cause;
|
|
178580
|
+
let exited = false;
|
|
178581
|
+
const kill = (reason, why) => {
|
|
178613
178582
|
failure ??= reason;
|
|
178614
|
-
|
|
178583
|
+
cause ??= why;
|
|
178584
|
+
if (!exited) {
|
|
178585
|
+
killWorker(child, ownGroup);
|
|
178586
|
+
}
|
|
178615
178587
|
grace ??= setTimeout(() => {
|
|
178616
178588
|
closeStreams(child);
|
|
178617
|
-
settle(() => run.resolve(closedProcessResult(null, null, failure, stdout, stderr)));
|
|
178589
|
+
settle(() => run.resolve(closedProcessResult(null, null, failure, cause, stdout, stderr)));
|
|
178618
178590
|
}, KILLED_WORKER_GRACE_MS);
|
|
178619
178591
|
};
|
|
178620
178592
|
let spawned = false;
|
|
@@ -178630,30 +178602,36 @@ function runScannerWorkerProcessAsync(input) {
|
|
|
178630
178602
|
});
|
|
178631
178603
|
child.stdout.on("data", (chunk) => {
|
|
178632
178604
|
if (!stdout.add(chunk)) {
|
|
178633
|
-
kill(outputLimitError(maxOutputBytes));
|
|
178605
|
+
kill(outputLimitError(maxOutputBytes), { type: "output-limit" });
|
|
178634
178606
|
}
|
|
178635
178607
|
});
|
|
178636
178608
|
child.stderr.on("data", (chunk) => {
|
|
178637
178609
|
if (!stderr.add(chunk)) {
|
|
178638
|
-
kill(outputLimitError(maxOutputBytes));
|
|
178610
|
+
kill(outputLimitError(maxOutputBytes), { type: "output-limit" });
|
|
178639
178611
|
}
|
|
178640
178612
|
});
|
|
178641
178613
|
child.stdin.on("error", () => {
|
|
178642
178614
|
return;
|
|
178643
178615
|
});
|
|
178616
|
+
child.on("exit", () => {
|
|
178617
|
+
exited = true;
|
|
178618
|
+
liveWorkers.delete(child);
|
|
178619
|
+
});
|
|
178644
178620
|
child.on("close", (code, signal) => {
|
|
178645
|
-
settle(() => run.resolve(closedProcessResult(code, signal, failure, stdout, stderr)));
|
|
178621
|
+
settle(() => run.resolve(closedProcessResult(code, signal, failure, cause, stdout, stderr)));
|
|
178646
178622
|
});
|
|
178647
178623
|
child.stdin.end(input.stdin);
|
|
178648
178624
|
const { timeoutMs } = input;
|
|
178649
178625
|
if (timeoutMs !== undefined) {
|
|
178650
|
-
timer = setTimeout(() => kill(timeoutError(timeoutMs)), timeoutMs);
|
|
178626
|
+
timer = setTimeout(() => kill(timeoutError(timeoutMs), { type: "timeout" }), timeoutMs);
|
|
178651
178627
|
}
|
|
178652
178628
|
return {
|
|
178653
178629
|
promise: run.promise,
|
|
178654
178630
|
cancel() {
|
|
178655
178631
|
settle(() => {
|
|
178656
|
-
|
|
178632
|
+
if (!exited) {
|
|
178633
|
+
killWorker(child, ownGroup);
|
|
178634
|
+
}
|
|
178657
178635
|
closeStreams(child);
|
|
178658
178636
|
run.reject(abortError());
|
|
178659
178637
|
});
|
|
@@ -178693,39 +178671,36 @@ class OutputCollector {
|
|
|
178693
178671
|
return Buffer.concat(this.chunks).toString("utf8");
|
|
178694
178672
|
}
|
|
178695
178673
|
}
|
|
178696
|
-
function closedProcessResult(code, signal, failure, stdout, stderr) {
|
|
178674
|
+
function closedProcessResult(code, signal, failure, cause, stdout, stderr) {
|
|
178697
178675
|
if (failure !== undefined) {
|
|
178698
|
-
return {
|
|
178676
|
+
return {
|
|
178677
|
+
ok: false,
|
|
178678
|
+
kind: "execution",
|
|
178679
|
+
error: failure,
|
|
178680
|
+
...cause === undefined ? {} : { cause },
|
|
178681
|
+
stderr: stderr.text()
|
|
178682
|
+
};
|
|
178699
178683
|
}
|
|
178700
178684
|
if (code === null) {
|
|
178701
|
-
return {
|
|
178685
|
+
return {
|
|
178686
|
+
ok: false,
|
|
178687
|
+
kind: "execution",
|
|
178688
|
+
error: signalError(signal),
|
|
178689
|
+
cause: { type: "signal", signal: signal ?? "unknown" },
|
|
178690
|
+
stderr: stderr.text()
|
|
178691
|
+
};
|
|
178702
178692
|
}
|
|
178703
178693
|
return { ok: true, exitCode: code, stdout: stdout.text(), stderr: stderr.text() };
|
|
178704
178694
|
}
|
|
178705
|
-
function workerStarted(result) {
|
|
178706
|
-
return typeof result.status === "number" || typeof result.signal === "string" || typeof result.pid === "number" && result.pid > 0;
|
|
178707
|
-
}
|
|
178708
|
-
function syncSpawnFailure(error, started, timeoutMs, maxOutputBytes, stderr) {
|
|
178709
|
-
const code = error.code;
|
|
178710
|
-
if (code === "ETIMEDOUT") {
|
|
178711
|
-
return { ok: false, kind: "execution", error: timeoutError(timeoutMs ?? 0), stderr };
|
|
178712
|
-
}
|
|
178713
|
-
if (code === "ENOBUFS") {
|
|
178714
|
-
return { ok: false, kind: "execution", error: outputLimitError(maxOutputBytes), stderr };
|
|
178715
|
-
}
|
|
178716
|
-
return { ok: false, kind: started ? "execution" : "start", error, stderr };
|
|
178717
|
-
}
|
|
178718
178695
|
function signalError(signal) {
|
|
178719
178696
|
const name = signal ?? "unknown";
|
|
178720
|
-
return
|
|
178697
|
+
return new Error(`worker terminated by signal ${name}`);
|
|
178721
178698
|
}
|
|
178722
178699
|
function timeoutError(timeoutMs) {
|
|
178723
|
-
return
|
|
178724
|
-
code: "ETIMEDOUT"
|
|
178725
|
-
});
|
|
178700
|
+
return new Error(`worker timed out after ${timeoutMs} ms`);
|
|
178726
178701
|
}
|
|
178727
178702
|
function outputLimitError(maxOutputBytes) {
|
|
178728
|
-
return
|
|
178703
|
+
return new Error(`worker wrote more than ${maxOutputBytes} bytes to stdout and stderr together`);
|
|
178729
178704
|
}
|
|
178730
178705
|
function validateWorkerResponse(value, request) {
|
|
178731
178706
|
const validator = responseValidator();
|
|
@@ -178753,18 +178728,7 @@ function formatSchemaError(errors) {
|
|
|
178753
178728
|
return `worker response does not match scanner-worker.schema.json at ${path}: ${error.message ?? "invalid value"}`;
|
|
178754
178729
|
}
|
|
178755
178730
|
function responseFilesMatchRequest(responseFiles, requestFiles) {
|
|
178756
|
-
|
|
178757
|
-
return false;
|
|
178758
|
-
}
|
|
178759
|
-
return responseFiles.every((file, index) => {
|
|
178760
|
-
if (!isRecord(file)) {
|
|
178761
|
-
return false;
|
|
178762
|
-
}
|
|
178763
|
-
return file.filePath === requestFiles[index]?.filePath;
|
|
178764
|
-
});
|
|
178765
|
-
}
|
|
178766
|
-
function isRecord(value) {
|
|
178767
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
178731
|
+
return responseFiles.length === requestFiles.length && responseFiles.every((file, index) => file.filePath === requestFiles[index]?.filePath);
|
|
178768
178732
|
}
|
|
178769
178733
|
function scannerUnavailableDiagnostic(language, error, executable) {
|
|
178770
178734
|
const label = languageLabel(language);
|
|
@@ -178803,20 +178767,17 @@ function scannerFailedDiagnostic(language, reason) {
|
|
|
178803
178767
|
function languageLabel(language) {
|
|
178804
178768
|
return language.charAt(0).toUpperCase() + language.slice(1);
|
|
178805
178769
|
}
|
|
178770
|
+
function killRunningWorkers() {
|
|
178771
|
+
for (const [child, ownGroup] of liveWorkers) {
|
|
178772
|
+
killWorker(child, ownGroup);
|
|
178773
|
+
}
|
|
178774
|
+
}
|
|
178806
178775
|
|
|
178807
178776
|
// src/scan/code/worker/runtime-probe.ts
|
|
178808
178777
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
178809
178778
|
var PROBE_MAX_OUTPUT_BYTES = 64 * 1024;
|
|
178810
|
-
function probeRuntime(command, stripEnv,
|
|
178811
|
-
const
|
|
178812
|
-
return classifyProbe(spawn2(executable, [...args, "--probe"], {
|
|
178813
|
-
env: workerProcessEnv(stripEnv),
|
|
178814
|
-
timeout: PROBE_TIMEOUT_MS,
|
|
178815
|
-
maxBuffer: PROBE_MAX_OUTPUT_BYTES
|
|
178816
|
-
}));
|
|
178817
|
-
}
|
|
178818
|
-
function probeRuntimeAsync(command, stripEnv, runAsync = runScannerWorkerProcessAsync) {
|
|
178819
|
-
const run = runAsync({
|
|
178779
|
+
function probeRuntime(command, stripEnv, run = runScannerWorkerProcess) {
|
|
178780
|
+
const task = run({
|
|
178820
178781
|
command: [...command, "--probe"],
|
|
178821
178782
|
stdin: "",
|
|
178822
178783
|
stripEnv,
|
|
@@ -178824,49 +178785,34 @@ function probeRuntimeAsync(command, stripEnv, runAsync = runScannerWorkerProcess
|
|
|
178824
178785
|
maxOutputBytes: PROBE_MAX_OUTPUT_BYTES
|
|
178825
178786
|
});
|
|
178826
178787
|
return {
|
|
178827
|
-
promise:
|
|
178828
|
-
cancel: () =>
|
|
178788
|
+
promise: task.promise.then(classifyProbe),
|
|
178789
|
+
cancel: () => task.cancel()
|
|
178829
178790
|
};
|
|
178830
178791
|
}
|
|
178831
|
-
function spawnResultOf(result) {
|
|
178832
|
-
if (result.ok) {
|
|
178833
|
-
return { status: result.exitCode, signal: null, stdout: result.stdout, stderr: result.stderr };
|
|
178834
|
-
}
|
|
178835
|
-
const error = result.error instanceof Error ? result.error : new Error(reasonOf(result.error));
|
|
178836
|
-
const { signal } = error;
|
|
178837
|
-
if (typeof signal === "string") {
|
|
178838
|
-
return { status: null, signal, stdout: "", stderr: result.stderr };
|
|
178839
|
-
}
|
|
178840
|
-
return { status: null, signal: null, stdout: "", stderr: result.stderr, error };
|
|
178841
|
-
}
|
|
178842
178792
|
function classifyProbe(result) {
|
|
178843
|
-
if (result.
|
|
178844
|
-
|
|
178845
|
-
|
|
178846
|
-
|
|
178847
|
-
|
|
178848
|
-
|
|
178849
|
-
|
|
178850
|
-
|
|
178851
|
-
return
|
|
178852
|
-
kind: "failed",
|
|
178853
|
-
reason: `probe exited with status ${result.status}${detail === "" ? "" : `: ${detail}`}`
|
|
178854
|
-
};
|
|
178855
|
-
}
|
|
178856
|
-
return parseProbeOutput(result.stdout);
|
|
178857
|
-
}
|
|
178858
|
-
function classifySpawnError(error) {
|
|
178859
|
-
const code = error.code;
|
|
178860
|
-
if (code === "ETIMEDOUT") {
|
|
178861
|
-
return { kind: "failed", reason: `probe did not finish within ${PROBE_TIMEOUT_MS / 1000} s` };
|
|
178793
|
+
if (result.ok) {
|
|
178794
|
+
if (result.exitCode !== 0) {
|
|
178795
|
+
const detail = firstLine(result.stderr);
|
|
178796
|
+
return {
|
|
178797
|
+
kind: "failed",
|
|
178798
|
+
reason: `probe exited with status ${result.exitCode}${detail === "" ? "" : `: ${detail}`}`
|
|
178799
|
+
};
|
|
178800
|
+
}
|
|
178801
|
+
return parseProbeOutput(result.stdout);
|
|
178862
178802
|
}
|
|
178863
|
-
|
|
178864
|
-
|
|
178865
|
-
kind: "failed",
|
|
178866
|
-
|
|
178867
|
-
|
|
178803
|
+
switch (result.cause?.type) {
|
|
178804
|
+
case "timeout":
|
|
178805
|
+
return { kind: "failed", reason: `probe did not finish within ${PROBE_TIMEOUT_MS / 1000} s` };
|
|
178806
|
+
case "output-limit":
|
|
178807
|
+
return {
|
|
178808
|
+
kind: "failed",
|
|
178809
|
+
reason: `probe printed more than ${PROBE_MAX_OUTPUT_BYTES / 1024} KiB`
|
|
178810
|
+
};
|
|
178811
|
+
case "signal":
|
|
178812
|
+
return { kind: "failed", reason: `probe terminated by signal ${result.cause.signal}` };
|
|
178813
|
+
default:
|
|
178814
|
+
return { kind: "unstartable", reason: reasonOf(result.error) };
|
|
178868
178815
|
}
|
|
178869
|
-
return { kind: "unstartable", reason: reasonOf(error) };
|
|
178870
178816
|
}
|
|
178871
178817
|
function parseProbeOutput(stdout) {
|
|
178872
178818
|
const text = stdout.trim();
|
|
@@ -178876,7 +178822,7 @@ function parseProbeOutput(stdout) {
|
|
|
178876
178822
|
} catch {
|
|
178877
178823
|
return malformed(text);
|
|
178878
178824
|
}
|
|
178879
|
-
if (!
|
|
178825
|
+
if (!isRecord(value)) {
|
|
178880
178826
|
return malformed(text);
|
|
178881
178827
|
}
|
|
178882
178828
|
if (value.ok === true && typeof value.runtime === "string" && typeof value.version === "string") {
|
|
@@ -178894,40 +178840,9 @@ function malformed(text) {
|
|
|
178894
178840
|
function firstLine(text) {
|
|
178895
178841
|
return text.trim().split(/\r?\n/u)[0] ?? "";
|
|
178896
178842
|
}
|
|
178897
|
-
function
|
|
178843
|
+
function isRecord(value) {
|
|
178898
178844
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
178899
178845
|
}
|
|
178900
|
-
function spawnRuntimeProbe(executable, args, options) {
|
|
178901
|
-
try {
|
|
178902
|
-
const result = spawnSync2(executable, args, {
|
|
178903
|
-
env: options.env,
|
|
178904
|
-
timeout: options.timeout,
|
|
178905
|
-
killSignal: "SIGKILL",
|
|
178906
|
-
maxBuffer: options.maxBuffer,
|
|
178907
|
-
input: "",
|
|
178908
|
-
encoding: "utf8",
|
|
178909
|
-
windowsHide: true
|
|
178910
|
-
});
|
|
178911
|
-
const stdout = result.stdout ?? "";
|
|
178912
|
-
const stderr = result.stderr ?? "";
|
|
178913
|
-
const error = result.error === undefined && Buffer.byteLength(stdout) + Buffer.byteLength(stderr) > options.maxBuffer ? Object.assign(new Error("probe output exceeded maxBuffer"), { code: "ENOBUFS" }) : result.error;
|
|
178914
|
-
return {
|
|
178915
|
-
status: result.status,
|
|
178916
|
-
signal: result.signal,
|
|
178917
|
-
stdout,
|
|
178918
|
-
stderr,
|
|
178919
|
-
...error === undefined ? {} : { error }
|
|
178920
|
-
};
|
|
178921
|
-
} catch (error) {
|
|
178922
|
-
return {
|
|
178923
|
-
status: null,
|
|
178924
|
-
signal: null,
|
|
178925
|
-
stdout: "",
|
|
178926
|
-
stderr: "",
|
|
178927
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
178928
|
-
};
|
|
178929
|
-
}
|
|
178930
|
-
}
|
|
178931
178846
|
|
|
178932
178847
|
// src/scan/code/worker/scanner-executable.ts
|
|
178933
178848
|
import { accessSync, chmodSync, constants, existsSync as existsSync2, statSync } from "node:fs";
|
|
@@ -179139,22 +179054,12 @@ function rememberProbe(key, generation, outcome) {
|
|
|
179139
179054
|
function resolveRuntimeWorkerCommand(language, options) {
|
|
179140
179055
|
const env = options.env ?? process.env;
|
|
179141
179056
|
const probe = options.probe ?? probeRuntime;
|
|
179142
|
-
const steps = resolutionSteps(language, options, env);
|
|
179143
|
-
let step = steps.next();
|
|
179144
|
-
while (step.done !== true) {
|
|
179145
|
-
step = steps.next(cachedProbe(step.value, env, probe));
|
|
179146
|
-
}
|
|
179147
|
-
return step.value;
|
|
179148
|
-
}
|
|
179149
|
-
function resolveRuntimeWorkerCommandAsync(language, options) {
|
|
179150
|
-
const env = options.env ?? process.env;
|
|
179151
|
-
const probeAsync = options.probeAsync ?? probeRuntimeAsync;
|
|
179152
179057
|
return cancelableSequence(async (run) => {
|
|
179153
179058
|
const steps = resolutionSteps(language, options, env);
|
|
179154
179059
|
let step = steps.next();
|
|
179155
179060
|
while (step.done !== true) {
|
|
179156
179061
|
const request = step.value;
|
|
179157
|
-
step = steps.next(await run(() =>
|
|
179062
|
+
step = steps.next(await run(() => cachedProbe(request, env, probe)));
|
|
179158
179063
|
}
|
|
179159
179064
|
return step.value;
|
|
179160
179065
|
});
|
|
@@ -179262,24 +179167,13 @@ function isExecutableFile(path, platform) {
|
|
|
179262
179167
|
}
|
|
179263
179168
|
}
|
|
179264
179169
|
function cachedProbe({ command, stripEnv }, env, probe) {
|
|
179265
|
-
const key = probeCacheKey(command, env);
|
|
179266
|
-
const cached = probeCache.get(key);
|
|
179267
|
-
if (cached !== undefined) {
|
|
179268
|
-
return cached;
|
|
179269
|
-
}
|
|
179270
|
-
const generation = probeCacheGeneration;
|
|
179271
|
-
const outcome = probe(command, stripEnv);
|
|
179272
|
-
rememberProbe(key, generation, outcome);
|
|
179273
|
-
return outcome;
|
|
179274
|
-
}
|
|
179275
|
-
function cachedProbeAsync({ command, stripEnv }, env, probeAsync) {
|
|
179276
179170
|
const key = probeCacheKey(command, env);
|
|
179277
179171
|
const cached = probeCache.get(key);
|
|
179278
179172
|
if (cached !== undefined) {
|
|
179279
179173
|
return settledCancelable(cached);
|
|
179280
179174
|
}
|
|
179281
179175
|
const generation = probeCacheGeneration;
|
|
179282
|
-
return mapCancelable(
|
|
179176
|
+
return mapCancelable(probe(command, stripEnv), (outcome) => {
|
|
179283
179177
|
rememberProbe(key, generation, outcome);
|
|
179284
179178
|
return outcome;
|
|
179285
179179
|
});
|
|
@@ -179326,7 +179220,7 @@ function failure(spec, language, code, reason) {
|
|
|
179326
179220
|
diagnostic: {
|
|
179327
179221
|
severity: "error",
|
|
179328
179222
|
code,
|
|
179329
|
-
|
|
179223
|
+
language,
|
|
179330
179224
|
target: language,
|
|
179331
179225
|
message: `${spec.label} scanner worker ${state}: ${reason}`
|
|
179332
179226
|
}
|
|
@@ -179335,16 +179229,12 @@ function failure(spec, language, code, reason) {
|
|
|
179335
179229
|
|
|
179336
179230
|
// src/scan/code/dispatch.ts
|
|
179337
179231
|
function createScannerWorkerAdapter(language, command, adapterOptions = {}) {
|
|
179338
|
-
const
|
|
179339
|
-
const
|
|
179340
|
-
const prepare = (context) => mapCancelable(commandAsync?.(context) ?? settledCancelable(command(context)), (value) => boundWorkerAdapter(language, workerCommand(value), adapterOptions));
|
|
179232
|
+
const resolve3 = (context) => typeof command === "function" ? settledCancelable(command(context)) : command.commandAsync(context);
|
|
179233
|
+
const prepare = (context) => mapCancelable(resolve3(context), (value) => boundWorkerAdapter(language, workerCommand(value), adapterOptions));
|
|
179341
179234
|
const scanBatchAsync = (files, options, context) => {
|
|
179342
179235
|
if (files.length === 0) {
|
|
179343
179236
|
return settledCancelable([]);
|
|
179344
179237
|
}
|
|
179345
|
-
if (commandAsync === undefined) {
|
|
179346
|
-
return bound(context).scanFilesAsync(files, options, context);
|
|
179347
|
-
}
|
|
179348
179238
|
return cancelableSequence(async (step) => {
|
|
179349
179239
|
const { adapter } = await step(() => prepare(context));
|
|
179350
179240
|
return step(() => adapter.scanFilesAsync(files, options, context));
|
|
@@ -179352,8 +179242,6 @@ function createScannerWorkerAdapter(language, command, adapterOptions = {}) {
|
|
|
179352
179242
|
};
|
|
179353
179243
|
return {
|
|
179354
179244
|
language,
|
|
179355
|
-
scanFile: (filePath, content, options, context) => bound(context).scanFile(filePath, content, options, context),
|
|
179356
|
-
scanFiles: (files, options, context) => files.length === 0 ? [] : bound(context).scanFiles(files, options, context),
|
|
179357
179245
|
scanFilesAsync: scanBatchAsync,
|
|
179358
179246
|
prepare
|
|
179359
179247
|
};
|
|
@@ -179363,20 +179251,6 @@ function boundWorkerAdapter(language, resolved, adapterOptions) {
|
|
|
179363
179251
|
const runtime = resolved.ok ? resolved.runtime : [];
|
|
179364
179252
|
const adapter = {
|
|
179365
179253
|
language,
|
|
179366
|
-
scanFile(filePath, content, options, context) {
|
|
179367
|
-
const [scan] = adapter.scanFiles([{ filePath, content }], options, context);
|
|
179368
|
-
return scan ?? emptyScan(language, filePath);
|
|
179369
|
-
},
|
|
179370
|
-
scanFiles(files, options, context) {
|
|
179371
|
-
if (files.length === 0) {
|
|
179372
|
-
return [];
|
|
179373
|
-
}
|
|
179374
|
-
if (!resolved.ok) {
|
|
179375
|
-
return failedBatch(language, files, resolved.diagnostic);
|
|
179376
|
-
}
|
|
179377
|
-
const result = invokeScannerWorker(workerRequest(language, files, options, context, adapterOptions), resolved.command, adapterOptions.run, resolved.stripEnv);
|
|
179378
|
-
return result.ok ? result.codeFiles : failedBatch(language, files, result.diagnostic);
|
|
179379
|
-
},
|
|
179380
179254
|
scanFilesAsync(files, options, context) {
|
|
179381
179255
|
if (files.length === 0) {
|
|
179382
179256
|
return settledCancelable([]);
|
|
@@ -179384,36 +179258,28 @@ function boundWorkerAdapter(language, resolved, adapterOptions) {
|
|
|
179384
179258
|
if (!resolved.ok) {
|
|
179385
179259
|
return settledCancelable(failedBatch(language, files, resolved.diagnostic));
|
|
179386
179260
|
}
|
|
179387
|
-
const task =
|
|
179261
|
+
const task = invokeScannerWorker(workerRequest(language, files, options, context, adapterOptions), resolved.command, adapterOptions.run, resolved.stripEnv);
|
|
179388
179262
|
return mapCancelable(task, (result) => result.ok ? result.codeFiles : failedBatch(language, files, result.diagnostic));
|
|
179389
179263
|
},
|
|
179390
179264
|
prepare: () => settledCancelable({ argv, runtime, adapter })
|
|
179391
179265
|
};
|
|
179392
179266
|
return { argv, runtime, adapter };
|
|
179393
179267
|
}
|
|
179394
|
-
function scanCodeFiles(projectRoot, files, codeInclude, read, options = {}) {
|
|
179395
|
-
const plan = planCodeScan(files, codeInclude, read, options.onContent);
|
|
179396
|
-
const context = scanContext(projectRoot, options);
|
|
179397
|
-
for (const batch of plan.batches) {
|
|
179398
|
-
const adapter = options.adapters?.[batch.language] ?? builtInAdapters[batch.language];
|
|
179399
|
-
fillBatch(plan, batch, adapter.scanFiles(batch.files, batch.options, context));
|
|
179400
|
-
}
|
|
179401
|
-
return assemblePlan(plan);
|
|
179402
|
-
}
|
|
179403
179268
|
function scanContext(projectRoot, options) {
|
|
179404
179269
|
return options.scanners === undefined ? { projectRoot } : { projectRoot, scanners: options.scanners };
|
|
179405
179270
|
}
|
|
179406
|
-
function
|
|
179271
|
+
function scanCodeFiles(projectRoot, files, codeInclude, read, options = {}) {
|
|
179407
179272
|
const plan = planCodeScan(files, codeInclude, read, options.onContent);
|
|
179408
179273
|
const context = scanContext(projectRoot, options);
|
|
179409
179274
|
return cancelableSequence(async (step) => {
|
|
179410
179275
|
const cache = new Map;
|
|
179411
179276
|
for (const batch of plan.batches) {
|
|
179412
179277
|
const base = options.adapters?.[batch.language] ?? builtInAdapters[batch.language];
|
|
179413
|
-
const
|
|
179414
|
-
const
|
|
179415
|
-
const
|
|
179416
|
-
|
|
179278
|
+
const { argv, runtime, adapter } = "scanFilesAsync" in base ? await step(() => base.prepare(context)) : { argv: [], adapter: base };
|
|
179279
|
+
const keys = options.cache === undefined ? [] : batch.files.map((file) => codeScanCacheKey(batch.language, file.filePath, file.content, batch.options, argv, runtime));
|
|
179280
|
+
const cached = options.cache === undefined ? batch.files.map(() => {
|
|
179281
|
+
return;
|
|
179282
|
+
}) : keys.map((key) => options.cache?.get(key));
|
|
179417
179283
|
const missing = batch.files.filter((_, index) => cached[index] === undefined);
|
|
179418
179284
|
const scanned = missing.length === 0 ? [] : await step(() => scanFilesAsync(adapter, missing, batch.options, context));
|
|
179419
179285
|
let next = 0;
|
|
@@ -179421,7 +179287,7 @@ function scanCodeFilesAsync(projectRoot, files, codeInclude, read, options = {})
|
|
|
179421
179287
|
fillBatch(plan, batch, results);
|
|
179422
179288
|
results.forEach((scan, index) => {
|
|
179423
179289
|
const key = keys[index];
|
|
179424
|
-
if (scan !== undefined && key !== undefined && isReusableScan(scan)) {
|
|
179290
|
+
if (options.cache !== undefined && scan !== undefined && key !== undefined && isReusableScan(scan)) {
|
|
179425
179291
|
cache.set(key, scan);
|
|
179426
179292
|
}
|
|
179427
179293
|
});
|
|
@@ -179430,7 +179296,7 @@ function scanCodeFilesAsync(projectRoot, files, codeInclude, read, options = {})
|
|
|
179430
179296
|
});
|
|
179431
179297
|
}
|
|
179432
179298
|
function scanFilesAsync(adapter, files, options, context) {
|
|
179433
|
-
return adapter.scanFilesAsync
|
|
179299
|
+
return "scanFilesAsync" in adapter ? adapter.scanFilesAsync(files, options, context) : settledCancelable(adapter.scanFiles(files, options, context));
|
|
179434
179300
|
}
|
|
179435
179301
|
var builtInAdapters = {
|
|
179436
179302
|
typescript: typeScriptAdapter,
|
|
@@ -179440,14 +179306,17 @@ var builtInAdapters = {
|
|
|
179440
179306
|
go: createScannerWorkerAdapter("go", () => resolveScannerWorkerCommand("go")),
|
|
179441
179307
|
javascript: javaScriptAdapter,
|
|
179442
179308
|
python: runtimeWorkerAdapter("python"),
|
|
179443
|
-
ruby: runtimeWorkerAdapter("ruby")
|
|
179309
|
+
ruby: runtimeWorkerAdapter("ruby"),
|
|
179310
|
+
java: runtimeWorkerAdapter("java")
|
|
179444
179311
|
};
|
|
179445
179312
|
function runtimeWorkerAdapter(language) {
|
|
179446
179313
|
const resolution = ({ projectRoot, scanners }) => {
|
|
179447
179314
|
const command = scanners?.[language]?.command;
|
|
179448
179315
|
return command === undefined ? { projectRoot } : { projectRoot, command };
|
|
179449
179316
|
};
|
|
179450
|
-
return createScannerWorkerAdapter(language,
|
|
179317
|
+
return createScannerWorkerAdapter(language, {
|
|
179318
|
+
commandAsync: (context) => resolveRuntimeWorkerCommand(language, resolution(context))
|
|
179319
|
+
});
|
|
179451
179320
|
}
|
|
179452
179321
|
function planCodeScan(files, codeInclude, read, onContent) {
|
|
179453
179322
|
const slots = [];
|
|
@@ -179768,37 +179637,28 @@ function flushDanglingWith(pending, diagnostics, message) {
|
|
|
179768
179637
|
// src/query/project-scan.ts
|
|
179769
179638
|
function scanProject(options) {
|
|
179770
179639
|
const loaded = loadProjectScan(options, options.keepContent === true);
|
|
179771
|
-
if (!loaded.ok) {
|
|
179772
|
-
return loaded;
|
|
179773
|
-
}
|
|
179774
|
-
const { inputs } = loaded;
|
|
179775
|
-
const codeScan = scanCodeFiles(options.projectRoot, inputs.codeFiles, inputs.config.include.code, inputs.readFile, codeScanOptions(inputs, options));
|
|
179776
|
-
const docReads = readDocFiles(inputs, options);
|
|
179777
|
-
return { ok: true, scan: finishProjectScan(inputs, codeScan, docReads, options.buildGraph) };
|
|
179778
|
-
}
|
|
179779
|
-
function scanProjectAsync(options) {
|
|
179780
|
-
const loaded = loadProjectScan(options, true);
|
|
179781
179640
|
if (!loaded.ok) {
|
|
179782
179641
|
return cancelableSequence(async () => loaded);
|
|
179783
179642
|
}
|
|
179784
179643
|
const { inputs } = loaded;
|
|
179785
|
-
const
|
|
179786
|
-
const
|
|
179787
|
-
|
|
179644
|
+
const previousCache = options.cache;
|
|
179645
|
+
const fingerprint = previousCache === undefined ? undefined : JSON.stringify(inputs.config);
|
|
179646
|
+
const sameConfiguration = previousCache !== undefined && previousCache.fingerprint === fingerprint;
|
|
179647
|
+
if (previousCache !== undefined && !sameConfiguration && previousCache.fingerprint !== "") {
|
|
179788
179648
|
options.onConfigurationChange?.();
|
|
179789
179649
|
}
|
|
179790
|
-
const codeScan =
|
|
179650
|
+
const codeScan = scanCodeFiles(options.projectRoot, inputs.codeFiles, inputs.config.include.code, inputs.readFile, {
|
|
179791
179651
|
...codeScanOptions(inputs, options),
|
|
179792
|
-
...
|
|
179652
|
+
...previousCache === undefined ? {} : { cache: sameConfiguration ? previousCache.entries : new Map }
|
|
179793
179653
|
});
|
|
179794
179654
|
const docReads = readDocFiles(inputs, options);
|
|
179795
179655
|
return cancelableSequence(async (step) => {
|
|
179796
179656
|
const { cache, ...code } = await step(codeScan);
|
|
179797
|
-
const scan = finishProjectScan(inputs, code, docReads,
|
|
179657
|
+
const scan = finishProjectScan(inputs, code, docReads, options.buildGraph);
|
|
179798
179658
|
return {
|
|
179799
179659
|
ok: true,
|
|
179800
179660
|
scan,
|
|
179801
|
-
cache: { fingerprint, entries: cache }
|
|
179661
|
+
cache: { fingerprint: fingerprint ?? "", entries: cache }
|
|
179802
179662
|
};
|
|
179803
179663
|
});
|
|
179804
179664
|
}
|
|
@@ -179903,19 +179763,12 @@ class Project {
|
|
|
179903
179763
|
this.overlay.delete(relPath);
|
|
179904
179764
|
this.overlayRevision += 1;
|
|
179905
179765
|
}
|
|
179906
|
-
resolve() {
|
|
179907
|
-
const outcome = scanProject({
|
|
179908
|
-
...this.scanSources(this.overlay),
|
|
179909
|
-
buildGraph: true,
|
|
179910
|
-
keepContent: true
|
|
179911
|
-
});
|
|
179912
|
-
this.current = resolvedState(outcome);
|
|
179913
|
-
return this.current;
|
|
179914
|
-
}
|
|
179915
179766
|
resolveAsync() {
|
|
179916
179767
|
const revision = this.overlayRevision;
|
|
179917
|
-
const scan =
|
|
179768
|
+
const scan = scanProject({
|
|
179918
179769
|
...this.scanSources(new Map(this.overlay)),
|
|
179770
|
+
buildGraph: true,
|
|
179771
|
+
keepContent: true,
|
|
179919
179772
|
cache: this.cache,
|
|
179920
179773
|
onConfigurationChange: clearRuntimeProbeCache
|
|
179921
179774
|
});
|
|
@@ -180414,12 +180267,12 @@ function fullChangeText(changes) {
|
|
|
180414
180267
|
}
|
|
180415
180268
|
|
|
180416
180269
|
// src/query/check.ts
|
|
180417
|
-
function check(options) {
|
|
180270
|
+
async function check(options) {
|
|
180418
180271
|
const audit = options.audit ?? false;
|
|
180419
|
-
const outcome = scanProject({
|
|
180272
|
+
const outcome = await scanProject({
|
|
180420
180273
|
projectRoot: options.projectRoot,
|
|
180421
180274
|
...options.adapters === undefined ? {} : { adapters: options.adapters }
|
|
180422
|
-
});
|
|
180275
|
+
}).promise;
|
|
180423
180276
|
if (!outcome.ok) {
|
|
180424
180277
|
const sorted = sortDiagnostics(outcome.diagnostics);
|
|
180425
180278
|
return { diagnostics: sorted, summary: summarizeDiagnostics(sorted) };
|
|
@@ -180493,8 +180346,8 @@ function collectGateViolations(result) {
|
|
|
180493
180346
|
}
|
|
180494
180347
|
return violations;
|
|
180495
180348
|
}
|
|
180496
|
-
function related(options) {
|
|
180497
|
-
const outcome = scanProject({ projectRoot: options.projectRoot, buildGraph: true });
|
|
180349
|
+
async function related(options) {
|
|
180350
|
+
const outcome = await scanProject({ projectRoot: options.projectRoot, buildGraph: true }).promise;
|
|
180498
180351
|
if (!outcome.ok) {
|
|
180499
180352
|
return { ok: false, diagnostics: outcome.diagnostics };
|
|
180500
180353
|
}
|
|
@@ -180552,12 +180405,12 @@ function computeContext(graph, contentByFile, inputFiles) {
|
|
|
180552
180405
|
summary: { inputFiles: inputSet.size, contexts: contexts.length }
|
|
180553
180406
|
};
|
|
180554
180407
|
}
|
|
180555
|
-
function context(options) {
|
|
180556
|
-
const outcome = scanProject({
|
|
180408
|
+
async function context(options) {
|
|
180409
|
+
const outcome = await scanProject({
|
|
180557
180410
|
projectRoot: options.projectRoot,
|
|
180558
180411
|
buildGraph: true,
|
|
180559
180412
|
keepContent: true
|
|
180560
|
-
});
|
|
180413
|
+
}).promise;
|
|
180561
180414
|
if (!outcome.ok) {
|
|
180562
180415
|
return { ok: false, diagnostics: outcome.diagnostics };
|
|
180563
180416
|
}
|
|
@@ -180631,12 +180484,12 @@ function compareBlocks(left, right) {
|
|
|
180631
180484
|
}
|
|
180632
180485
|
|
|
180633
180486
|
// src/query/graph-output.ts
|
|
180634
|
-
function graph(options) {
|
|
180635
|
-
const outcome = scanProject({
|
|
180487
|
+
async function graph(options) {
|
|
180488
|
+
const outcome = await scanProject({
|
|
180636
180489
|
projectRoot: options.projectRoot,
|
|
180637
180490
|
buildGraph: true,
|
|
180638
180491
|
keepContent: true
|
|
180639
|
-
});
|
|
180492
|
+
}).promise;
|
|
180640
180493
|
if (!outcome.ok) {
|
|
180641
180494
|
return { ok: false, diagnostics: outcome.diagnostics };
|
|
180642
180495
|
}
|
|
@@ -181131,13 +180984,6 @@ class CliError extends Error {
|
|
|
181131
180984
|
}
|
|
181132
180985
|
}
|
|
181133
180986
|
|
|
181134
|
-
class InitCliError extends CliError {
|
|
181135
|
-
constructor(message, guidance) {
|
|
181136
|
-
super(message, guidance);
|
|
181137
|
-
this.name = "InitCliError";
|
|
181138
|
-
}
|
|
181139
|
-
}
|
|
181140
|
-
|
|
181141
180987
|
class DiagnosticOutputError extends Error {
|
|
181142
180988
|
constructor(message) {
|
|
181143
180989
|
super(message);
|
|
@@ -181743,6 +181589,7 @@ var DART_PATTERNS = ["lib/**/*.dart"];
|
|
|
181743
181589
|
var RUST_PATTERNS = ["src/**/*.rs", "*/src/**/*.rs"];
|
|
181744
181590
|
var GO_PATTERNS = ["*.go", "cmd/**/*.go", "internal/**/*.go", "pkg/**/*.go"];
|
|
181745
181591
|
var RUBY_PATTERNS = ["lib/**/*.rb", "app/**/*.rb"];
|
|
181592
|
+
var JAVA_PATTERNS = ["src/main/java/**/*.java", "src/**/*.java"];
|
|
181746
181593
|
var LANGUAGE_PATTERNS = {
|
|
181747
181594
|
typescript: TYPESCRIPT_PATTERNS,
|
|
181748
181595
|
swift: SWIFT_PATTERNS,
|
|
@@ -181750,7 +181597,8 @@ var LANGUAGE_PATTERNS = {
|
|
|
181750
181597
|
rust: RUST_PATTERNS,
|
|
181751
181598
|
go: GO_PATTERNS,
|
|
181752
181599
|
javascript: JAVASCRIPT_PATTERNS,
|
|
181753
|
-
ruby: RUBY_PATTERNS
|
|
181600
|
+
ruby: RUBY_PATTERNS,
|
|
181601
|
+
java: JAVA_PATTERNS
|
|
181754
181602
|
};
|
|
181755
181603
|
var EXCLUDED_CODE_SEGMENTS = {
|
|
181756
181604
|
typescript: ["__tests__", "tests", "test"],
|
|
@@ -181760,7 +181608,8 @@ var EXCLUDED_CODE_SEGMENTS = {
|
|
|
181760
181608
|
go: ["vendor", "testdata"],
|
|
181761
181609
|
javascript: ["__tests__", "tests", "test"],
|
|
181762
181610
|
python: ["tests", "venv", "dist", "site-packages"],
|
|
181763
|
-
ruby: ["spec", "test", "vendor"]
|
|
181611
|
+
ruby: ["spec", "test", "vendor"],
|
|
181612
|
+
java: ["target", "src/test"]
|
|
181764
181613
|
};
|
|
181765
181614
|
var TEST_FILE_PATTERNS = {
|
|
181766
181615
|
typescript: /\.(?:test|spec)\.[cm]?tsx?$/u,
|
|
@@ -181939,7 +181788,8 @@ function scriptPatterns(language) {
|
|
|
181939
181788
|
}
|
|
181940
181789
|
function activeCodePatterns(projectRoot, language) {
|
|
181941
181790
|
const candidates = language === "python" ? pythonPatterns(projectRoot) : LANGUAGE_PATTERNS[language];
|
|
181942
|
-
|
|
181791
|
+
const active = candidates.filter((pattern) => countCodeFiles(projectRoot, [pattern], language) > 0);
|
|
181792
|
+
return language === "java" ? active.slice(0, 1) : active;
|
|
181943
181793
|
}
|
|
181944
181794
|
function pythonPatterns(projectRoot) {
|
|
181945
181795
|
let entries;
|
|
@@ -181965,7 +181815,8 @@ function countCodeFiles(projectRoot, patterns, language) {
|
|
|
181965
181815
|
function isExcludedCodeFile(filePath, language) {
|
|
181966
181816
|
const lower = filePath.toLowerCase();
|
|
181967
181817
|
const segments = filePath.split("/");
|
|
181968
|
-
|
|
181818
|
+
const delimited = `/${filePath}/`;
|
|
181819
|
+
if (hasExcludedSuffix(language, lower) || TEST_FILE_PATTERNS[language]?.test(lower) === true || EXCLUDED_CODE_SEGMENTS[language].some((run) => delimited.includes(`/${run}/`))) {
|
|
181969
181820
|
return true;
|
|
181970
181821
|
}
|
|
181971
181822
|
if (segments.some((segment) => ["generated", "gen", ".dart_tool", "build"].includes(segment.toLowerCase()))) {
|
|
@@ -182091,7 +181942,6 @@ function readFileOrUndefined(path) {
|
|
|
182091
181942
|
}
|
|
182092
181943
|
|
|
182093
181944
|
// src/setup/init-plan.ts
|
|
182094
|
-
var CONFIG_FILE_NAME2 = "docbridge.config.json";
|
|
182095
181945
|
var INIT_SKILL_NAMES = ["docbridge"];
|
|
182096
181946
|
var LEGACY_SKILL_NAMES = [
|
|
182097
181947
|
"docbridge-adopt",
|
|
@@ -182259,7 +182109,7 @@ function planConfigOperations(input) {
|
|
|
182259
182109
|
return [
|
|
182260
182110
|
{
|
|
182261
182111
|
action,
|
|
182262
|
-
path:
|
|
182112
|
+
path: CONFIG_FILE_NAME,
|
|
182263
182113
|
content,
|
|
182264
182114
|
reason: "Create docbridge.config.json from discovered scope."
|
|
182265
182115
|
}
|
|
@@ -182411,7 +182261,7 @@ function resolveInitWithAgentTarget(discovery, options) {
|
|
|
182411
182261
|
return { target: discovery.agent.defaultTarget, error: undefined };
|
|
182412
182262
|
}
|
|
182413
182263
|
function readExistingConfig(projectRoot) {
|
|
182414
|
-
const configPath = join12(projectRoot,
|
|
182264
|
+
const configPath = join12(projectRoot, CONFIG_FILE_NAME);
|
|
182415
182265
|
let rawText;
|
|
182416
182266
|
try {
|
|
182417
182267
|
rawText = readFileSync7(configPath, "utf8");
|
|
@@ -182489,7 +182339,7 @@ function parseInitOptions(args, command) {
|
|
|
182489
182339
|
if (arg === "--root") {
|
|
182490
182340
|
const root = args[index + 1];
|
|
182491
182341
|
if (root === undefined) {
|
|
182492
|
-
throw new
|
|
182342
|
+
throw new CliError("--root requires a path.", rootPathGuidance(command));
|
|
182493
182343
|
}
|
|
182494
182344
|
options.root = root;
|
|
182495
182345
|
index += 1;
|
|
@@ -182498,22 +182348,22 @@ function parseInitOptions(args, command) {
|
|
|
182498
182348
|
if (arg === "--agent-target") {
|
|
182499
182349
|
const target = args[index + 1];
|
|
182500
182350
|
if (target === undefined) {
|
|
182501
|
-
throw new
|
|
182351
|
+
throw new CliError("--agent-target requires a value.", agentTargetGuidance(command));
|
|
182502
182352
|
}
|
|
182503
182353
|
if (!AGENT_TARGETS.has(target)) {
|
|
182504
|
-
throw new
|
|
182354
|
+
throw new CliError(`Unknown agent target: ${target}. Supported values: codex, claude, both${command === "init" ? ", none" : ""}.`, agentTargetGuidance(command));
|
|
182505
182355
|
}
|
|
182506
182356
|
if (command === "init-with-agent" && target === "none") {
|
|
182507
|
-
throw new
|
|
182357
|
+
throw new CliError("init-with-agent requires an agent target other than none.", agentTargetGuidance(command));
|
|
182508
182358
|
}
|
|
182509
182359
|
options.agentTarget = target;
|
|
182510
182360
|
index += 1;
|
|
182511
182361
|
continue;
|
|
182512
182362
|
}
|
|
182513
182363
|
if (arg.startsWith("--")) {
|
|
182514
|
-
throw new
|
|
182364
|
+
throw new CliError(`Unknown option: ${arg}`, commandHelpGuidance(command));
|
|
182515
182365
|
}
|
|
182516
|
-
throw new
|
|
182366
|
+
throw new CliError(`Unexpected argument: ${arg}`, commandHelpGuidance(command));
|
|
182517
182367
|
}
|
|
182518
182368
|
return options;
|
|
182519
182369
|
}
|
|
@@ -182600,19 +182450,19 @@ function resolveConfirmedScope(input) {
|
|
|
182600
182450
|
};
|
|
182601
182451
|
}
|
|
182602
182452
|
if (!input.prompts.isInteractive) {
|
|
182603
|
-
throw new
|
|
182453
|
+
throw new CliError("Interactive setup requires a TTY. Re-run with --yes for non-interactive mode.");
|
|
182604
182454
|
}
|
|
182605
182455
|
if (input.discovery.docs.ambiguous) {
|
|
182606
182456
|
const choices = input.discovery.docs.candidates.map((candidate) => candidate.pattern);
|
|
182607
182457
|
if (choices.length === 0) {
|
|
182608
|
-
throw new
|
|
182458
|
+
throw new CliError("Docs scope is ambiguous and no candidates were detected. Create docbridge.config.json manually.");
|
|
182609
182459
|
}
|
|
182610
182460
|
const docsPattern2 = input.prompts.select("Choose docs scope:", choices, choices[0] ?? "");
|
|
182611
182461
|
const languages2 = selectLanguages(input.discovery.code.languages, input.prompts);
|
|
182612
182462
|
return { docsPattern: docsPattern2, languages: languages2 };
|
|
182613
182463
|
}
|
|
182614
182464
|
if (input.discovery.docs.recommended === undefined) {
|
|
182615
|
-
throw new
|
|
182465
|
+
throw new CliError("Docs scope could not be determined.");
|
|
182616
182466
|
}
|
|
182617
182467
|
let docsPattern = input.discovery.docs.recommended.pattern;
|
|
182618
182468
|
if (!input.prompts.confirm(`Use docs scope ${docsPattern}?`, true)) {
|
|
@@ -182646,7 +182496,7 @@ function selectLanguages(languages, prompts) {
|
|
|
182646
182496
|
}
|
|
182647
182497
|
}
|
|
182648
182498
|
if (selected.length === 0) {
|
|
182649
|
-
throw new
|
|
182499
|
+
throw new CliError("At least one supported code language must remain in scope.");
|
|
182650
182500
|
}
|
|
182651
182501
|
return selected;
|
|
182652
182502
|
}
|
|
@@ -182676,10 +182526,10 @@ function resolveProjectRoot(root, command) {
|
|
|
182676
182526
|
try {
|
|
182677
182527
|
stats = statSync4(projectRoot);
|
|
182678
182528
|
} catch {
|
|
182679
|
-
throw new
|
|
182529
|
+
throw new CliError(`Root path does not exist: ${root}`, rootPathGuidance(command));
|
|
182680
182530
|
}
|
|
182681
182531
|
if (!stats.isDirectory()) {
|
|
182682
|
-
throw new
|
|
182532
|
+
throw new CliError(`Root path is not a directory: ${root}`, rootPathGuidance(command));
|
|
182683
182533
|
}
|
|
182684
182534
|
return projectRoot;
|
|
182685
182535
|
}
|
|
@@ -182955,8 +182805,7 @@ function planUpgrade(input) {
|
|
|
182955
182805
|
pending,
|
|
182956
182806
|
messages,
|
|
182957
182807
|
nextSteps: buildNextSteps({ mode, cli, options: input.options, pending }),
|
|
182958
|
-
requiresConfirmation: mode === "apply" && !input.options.dryRun && !input.options.yes && operations.some((operation) => operation.action === "overwrite" || operation.action === "remove")
|
|
182959
|
-
exitCode: 0
|
|
182808
|
+
requiresConfirmation: mode === "apply" && !input.options.dryRun && !input.options.yes && operations.some((operation) => operation.action === "overwrite" || operation.action === "remove")
|
|
182960
182809
|
};
|
|
182961
182810
|
}
|
|
182962
182811
|
function planOperations(input) {
|
|
@@ -183139,7 +182988,7 @@ function runUpgrade(options, io, initRuntime, runtime) {
|
|
|
183139
182988
|
});
|
|
183140
182989
|
if (plan.mode === "check" || options.dryRun) {
|
|
183141
182990
|
io.stdout(formatUpgradePlan(plan));
|
|
183142
|
-
return
|
|
182991
|
+
return 0;
|
|
183143
182992
|
}
|
|
183144
182993
|
return applyUpgrade(projectRoot, packageRoot, plan, io, initRuntime);
|
|
183145
182994
|
}
|
|
@@ -183157,7 +183006,7 @@ function applyUpgrade(projectRoot, packageRoot, plan, io, initRuntime) {
|
|
|
183157
183006
|
applySkillOperation(projectRoot, packageRoot, operation);
|
|
183158
183007
|
}
|
|
183159
183008
|
io.stdout(formatUpgradePlan(plan));
|
|
183160
|
-
return
|
|
183009
|
+
return 0;
|
|
183161
183010
|
}
|
|
183162
183011
|
function parseAgentTarget(value) {
|
|
183163
183012
|
if (value === undefined) {
|
|
@@ -183182,6 +183031,31 @@ function resolveProjectRoot2(root) {
|
|
|
183182
183031
|
return projectRoot;
|
|
183183
183032
|
}
|
|
183184
183033
|
|
|
183034
|
+
// src/cli/worker-signals.ts
|
|
183035
|
+
async function killingWorkersOnSignal(scan) {
|
|
183036
|
+
const signals = process.platform === "win32" ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
183037
|
+
const handlers = new Map;
|
|
183038
|
+
const remove = () => {
|
|
183039
|
+
for (const [signal, handler] of handlers) {
|
|
183040
|
+
process.off(signal, handler);
|
|
183041
|
+
}
|
|
183042
|
+
};
|
|
183043
|
+
for (const signal of signals) {
|
|
183044
|
+
const handler = () => {
|
|
183045
|
+
killRunningWorkers();
|
|
183046
|
+
remove();
|
|
183047
|
+
process.kill(process.pid, signal);
|
|
183048
|
+
};
|
|
183049
|
+
handlers.set(signal, handler);
|
|
183050
|
+
process.on(signal, handler);
|
|
183051
|
+
}
|
|
183052
|
+
try {
|
|
183053
|
+
return await scan();
|
|
183054
|
+
} finally {
|
|
183055
|
+
remove();
|
|
183056
|
+
}
|
|
183057
|
+
}
|
|
183058
|
+
|
|
183185
183059
|
// src/cli/index.ts
|
|
183186
183060
|
var VERSION = package_default.version;
|
|
183187
183061
|
function parseCheckOptions(args) {
|
|
@@ -183209,9 +183083,9 @@ function resolveProjectRoot3(root, command) {
|
|
|
183209
183083
|
}
|
|
183210
183084
|
return projectRoot;
|
|
183211
183085
|
}
|
|
183212
|
-
function runCheck(options, io) {
|
|
183086
|
+
async function runCheck(options, io) {
|
|
183213
183087
|
const projectRoot = resolveProjectRoot3(options.root, "check");
|
|
183214
|
-
const result = check({ projectRoot, audit: options.audit });
|
|
183088
|
+
const result = await killingWorkersOnSignal(() => check({ projectRoot, audit: options.audit }));
|
|
183215
183089
|
if (options.json) {
|
|
183216
183090
|
io.stdout(`${JSON.stringify(result, null, 2)}
|
|
183217
183091
|
`);
|
|
@@ -183232,7 +183106,7 @@ See \`docbridge docs show troubleshooting\` for diagnostic codes and fixes.
|
|
|
183232
183106
|
}
|
|
183233
183107
|
return result.summary.errors > 0 ? 1 : 0;
|
|
183234
183108
|
}
|
|
183235
|
-
function runFileCommand(command, options, io, execute, render) {
|
|
183109
|
+
async function runFileCommand(command, options, io, execute, render) {
|
|
183236
183110
|
const projectRoot = resolveProjectRoot3(options.root, command);
|
|
183237
183111
|
const inputFiles = [...options.files];
|
|
183238
183112
|
if (options.stdin) {
|
|
@@ -183240,7 +183114,7 @@ function runFileCommand(command, options, io, execute, render) {
|
|
|
183240
183114
|
inputFiles.push(...readStdin().split(`
|
|
183241
183115
|
`));
|
|
183242
183116
|
}
|
|
183243
|
-
const outcome = execute(projectRoot, inputFiles);
|
|
183117
|
+
const outcome = await killingWorkersOnSignal(async () => execute(projectRoot, inputFiles));
|
|
183244
183118
|
if (!outcome.ok) {
|
|
183245
183119
|
throw new DiagnosticOutputError(outcome.diagnostics.map(formatDiagnostic).join(`
|
|
183246
183120
|
`));
|
|
@@ -183261,7 +183135,7 @@ function writeStructuredResult(result, options) {
|
|
|
183261
183135
|
`);
|
|
183262
183136
|
}
|
|
183263
183137
|
}
|
|
183264
|
-
function runRelated(options, io) {
|
|
183138
|
+
async function runRelated(options, io) {
|
|
183265
183139
|
if (!options.stdin && options.files.length === 0) {
|
|
183266
183140
|
throw new CliError("No input files were provided.", missingInputGuidance("related"));
|
|
183267
183141
|
}
|
|
@@ -183290,7 +183164,7 @@ function runRelated(options, io) {
|
|
|
183290
183164
|
return 0;
|
|
183291
183165
|
});
|
|
183292
183166
|
}
|
|
183293
|
-
function runContext(options, io) {
|
|
183167
|
+
async function runContext(options, io) {
|
|
183294
183168
|
if (!options.stdin && options.files.length === 0) {
|
|
183295
183169
|
throw new CliError("No input files were provided.", missingInputGuidance("context"));
|
|
183296
183170
|
}
|
|
@@ -183304,7 +183178,7 @@ function runContext(options, io) {
|
|
|
183304
183178
|
return 0;
|
|
183305
183179
|
});
|
|
183306
183180
|
}
|
|
183307
|
-
function runGraph(options, io) {
|
|
183181
|
+
async function runGraph(options, io) {
|
|
183308
183182
|
return runFileCommand("graph", options, io, (projectRoot, inputFiles) => graph({ projectRoot, inputFiles, includeContent: options.includeContent }), (result, projectRoot, inputFiles) => {
|
|
183309
183183
|
const normalizedInputFiles = normalizeChangedPaths(projectRoot, inputFiles);
|
|
183310
183184
|
writeStructuredResult(result, {
|
|
@@ -183358,7 +183232,7 @@ var COMMAND_HANDLERS = {
|
|
|
183358
183232
|
return 0;
|
|
183359
183233
|
}
|
|
183360
183234
|
};
|
|
183361
|
-
function run(argv, io = {
|
|
183235
|
+
async function run(argv, io = {
|
|
183362
183236
|
stdout: (text) => process.stdout.write(text),
|
|
183363
183237
|
stderr: (text) => process.stderr.write(text)
|
|
183364
183238
|
}, initRuntime = { prompts: createDefaultPrompts() }, cliRuntime = {}) {
|
|
@@ -183380,7 +183254,7 @@ function run(argv, io = {
|
|
|
183380
183254
|
return 0;
|
|
183381
183255
|
}
|
|
183382
183256
|
if (isSubcommand(command)) {
|
|
183383
|
-
const exitCode = COMMAND_HANDLERS[command](rest, io, initRuntime, cliRuntime);
|
|
183257
|
+
const exitCode = await COMMAND_HANDLERS[command](rest, io, initRuntime, cliRuntime);
|
|
183384
183258
|
writeUpdateNotice(argv, io, initRuntime, cliRuntime);
|
|
183385
183259
|
return exitCode;
|
|
183386
183260
|
}
|
|
@@ -183445,7 +183319,7 @@ if (__require.main == __require.module) {
|
|
|
183445
183319
|
const argv = process.argv.slice(2);
|
|
183446
183320
|
const isTty = process.stderr.isTTY === true;
|
|
183447
183321
|
const latest = await resolveLatestForInvocation(argv, process.env, isTty);
|
|
183448
|
-
process.exitCode = run(argv, {
|
|
183322
|
+
process.exitCode = await run(argv, {
|
|
183449
183323
|
stdout: (text) => process.stdout.write(text),
|
|
183450
183324
|
stderr: (text) => process.stderr.write(text)
|
|
183451
183325
|
}, { prompts: createDefaultPrompts() }, { ...latest !== undefined ? { latest } : {}, env: process.env, isTty });
|