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/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.12.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, spawnSync } from "node:child_process";
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
- function createLazyWorkerResponseValidator(compile) {
178454
- let validator;
178455
- return () => {
178456
- validator ??= compile();
178457
- return validator;
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
- return interpretWorkerProcess(request, command, run(processInput(request, command, stripEnv)));
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: run.promise.then((processResult) => interpretWorkerProcess(request, command, processResult)),
178477
- cancel: () => run.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, { env: workerProcessEnv(input.stripEnv), detached: ownGroup });
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
- const kill = (reason) => {
178579
+ let cause;
178580
+ let exited = false;
178581
+ const kill = (reason, why) => {
178613
178582
  failure ??= reason;
178614
- killWorker(child, ownGroup);
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
- killWorker(child, ownGroup);
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 { ok: false, kind: "execution", error: failure, stderr: stderr.text() };
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 { ok: false, kind: "execution", error: signalError(signal), stderr: stderr.text() };
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 Object.assign(new Error(`worker terminated by signal ${name}`), { signal: name });
178697
+ return new Error(`worker terminated by signal ${name}`);
178721
178698
  }
178722
178699
  function timeoutError(timeoutMs) {
178723
- return Object.assign(new Error(`worker timed out after ${timeoutMs} ms`), {
178724
- code: "ETIMEDOUT"
178725
- });
178700
+ return new Error(`worker timed out after ${timeoutMs} ms`);
178726
178701
  }
178727
178702
  function outputLimitError(maxOutputBytes) {
178728
- return Object.assign(new Error(`worker wrote more than ${maxOutputBytes} bytes to stdout and stderr together`), { code: "ENOBUFS" });
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
- if (responseFiles.length !== requestFiles.length) {
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, spawn2 = spawnRuntimeProbe) {
178811
- const [executable = "", ...args] = command;
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: run.promise.then((result) => classifyProbe(spawnResultOf(result))),
178828
- cancel: () => run.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.error !== undefined) {
178844
- return classifySpawnError(result.error);
178845
- }
178846
- if (result.status === null) {
178847
- return { kind: "failed", reason: `probe terminated by signal ${result.signal ?? "unknown"}` };
178848
- }
178849
- if (result.status !== 0) {
178850
- const detail = firstLine(result.stderr);
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
- if (code === "ENOBUFS") {
178864
- return {
178865
- kind: "failed",
178866
- reason: `probe printed more than ${PROBE_MAX_OUTPUT_BYTES / 1024} KiB`
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 (!isRecord2(value)) {
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 isRecord2(value) {
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(() => cachedProbeAsync(request, env, probeAsync)));
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(probeAsync(command, stripEnv), (outcome) => {
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
- ...isCodeLanguage(language) ? { language } : {},
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 { commandAsync } = adapterOptions;
179339
- const bound = (context) => boundWorkerAdapter(language, workerCommand(command(context)), adapterOptions).adapter;
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 = invokeScannerWorkerAsync(workerRequest(language, files, options, context, adapterOptions), resolved.command, adapterOptions.runAsync, resolved.stripEnv);
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 scanCodeFilesAsync(projectRoot, files, codeInclude, read, options = {}) {
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 prepare = base.prepare?.bind(base);
179414
- const { argv, runtime, adapter } = prepare === undefined ? { argv: [], adapter: base } : await step(() => prepare(context));
179415
- const keys = batch.files.map((file) => codeScanCacheKey(batch.language, file.filePath, file.content, batch.options, argv, runtime));
179416
- const cached = keys.map((key) => options.cache?.get(key));
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?.(files, options, context) ?? settledCancelable(adapter.scanFiles(files, options, context));
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, (context) => resolveRuntimeWorkerCommand(language, resolution(context)), { commandAsync: (context) => resolveRuntimeWorkerCommandAsync(language, resolution(context)) });
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 fingerprint = JSON.stringify(inputs.config);
179786
- const sameConfiguration = options.cache.fingerprint === fingerprint;
179787
- if (!sameConfiguration && options.cache.fingerprint !== "") {
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 = scanCodeFilesAsync(options.projectRoot, inputs.codeFiles, inputs.config.include.code, inputs.readFile, {
179650
+ const codeScan = scanCodeFiles(options.projectRoot, inputs.codeFiles, inputs.config.include.code, inputs.readFile, {
179791
179651
  ...codeScanOptions(inputs, options),
179792
- ...sameConfiguration ? { cache: options.cache.entries } : {}
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, true);
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 = scanProjectAsync({
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
- return candidates.filter((pattern) => countCodeFiles(projectRoot, [pattern], language) > 0);
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
- if (hasExcludedSuffix(language, lower) || TEST_FILE_PATTERNS[language]?.test(lower) === true || EXCLUDED_CODE_SEGMENTS[language].some((segment) => segments.includes(segment))) {
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: CONFIG_FILE_NAME2,
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, CONFIG_FILE_NAME2);
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 InitCliError("--root requires a path.", rootPathGuidance(command));
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 InitCliError("--agent-target requires a value.", agentTargetGuidance(command));
182351
+ throw new CliError("--agent-target requires a value.", agentTargetGuidance(command));
182502
182352
  }
182503
182353
  if (!AGENT_TARGETS.has(target)) {
182504
- throw new InitCliError(`Unknown agent target: ${target}. Supported values: codex, claude, both${command === "init" ? ", none" : ""}.`, agentTargetGuidance(command));
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 InitCliError("init-with-agent requires an agent target other than none.", agentTargetGuidance(command));
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 InitCliError(`Unknown option: ${arg}`, commandHelpGuidance(command));
182364
+ throw new CliError(`Unknown option: ${arg}`, commandHelpGuidance(command));
182515
182365
  }
182516
- throw new InitCliError(`Unexpected argument: ${arg}`, commandHelpGuidance(command));
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 InitCliError("Interactive setup requires a TTY. Re-run with --yes for non-interactive mode.");
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 InitCliError("Docs scope is ambiguous and no candidates were detected. Create docbridge.config.json manually.");
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 InitCliError("Docs scope could not be determined.");
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 InitCliError("At least one supported code language must remain in scope.");
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 InitCliError(`Root path does not exist: ${root}`, rootPathGuidance(command));
182529
+ throw new CliError(`Root path does not exist: ${root}`, rootPathGuidance(command));
182680
182530
  }
182681
182531
  if (!stats.isDirectory()) {
182682
- throw new InitCliError(`Root path is not a directory: ${root}`, rootPathGuidance(command));
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 plan.exitCode;
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 plan.exitCode;
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 });