@cortexkit/aft-pi 0.56.1 → 0.57.0

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
@@ -8748,6 +8748,7 @@ class BinaryBridge {
8748
8748
  pending = new Map;
8749
8749
  outstandingBackgroundTaskIds = new Set;
8750
8750
  nextId = 1;
8751
+ processGeneration = 0;
8751
8752
  stdoutBuffer = "";
8752
8753
  stdoutReadOffset = 0;
8753
8754
  stderrBuffer = "";
@@ -9060,6 +9061,7 @@ class BinaryBridge {
9060
9061
  }
9061
9062
  }
9062
9063
  const id = String(this.nextId++);
9064
+ const tool = command === "tool_call" && typeof params.name === "string" ? params.name : command;
9063
9065
  let request;
9064
9066
  if (command === "cancel_request" || Object.hasOwn(params, "command") || Object.hasOwn(params, "method")) {
9065
9067
  const nested = { ...params };
@@ -9113,14 +9115,20 @@ class BinaryBridge {
9113
9115
  return;
9114
9116
  }
9115
9117
  entry.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
9116
- this.handleTimeout(requestSessionId);
9118
+ this.handleTimeout({
9119
+ requestId: id,
9120
+ tool: entry.tool,
9121
+ generation: entry.generation
9122
+ }, requestSessionId);
9117
9123
  }, effectiveTimeoutMs);
9118
9124
  const entry = {
9119
9125
  resolve,
9120
9126
  reject,
9121
9127
  timer,
9122
9128
  onProgress: options?.onProgress,
9123
- command
9129
+ command,
9130
+ tool,
9131
+ generation: this.processGeneration
9124
9132
  };
9125
9133
  this.pending.set(id, entry);
9126
9134
  if (!child?.stdin?.writable) {
@@ -9423,6 +9431,7 @@ class BinaryBridge {
9423
9431
  this.handleCrash();
9424
9432
  });
9425
9433
  this.process = child;
9434
+ this.processGeneration += 1;
9426
9435
  this.spawnedBinaryFingerprint = readBinaryFingerprint(this.binaryPath);
9427
9436
  this.lastBinaryFingerprintCheckAt = Date.now();
9428
9437
  this.stdoutBuffer = "";
@@ -9594,10 +9603,15 @@ class BinaryBridge {
9594
9603
  this.outstandingBackgroundTaskIds.add(taskId);
9595
9604
  }
9596
9605
  }
9597
- handleTimeout(triggeringSessionId) {
9606
+ handleTimeout(trigger, triggeringSessionId) {
9598
9607
  this.consecutiveRequestTimeouts = 0;
9599
9608
  this.spawnedBinaryFingerprint = null;
9600
- this.rejectAllPending(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} bridge killed during sibling timeout — request aborted`));
9609
+ const abortedSiblings = Array.from(this.pending, ([requestId, entry]) => ({
9610
+ request_id: requestId,
9611
+ tool: entry.tool
9612
+ }));
9613
+ const attribution = `triggering_request_id=${trigger.requestId} ` + `triggering_tool=${JSON.stringify(trigger.tool)} ` + `bridge_generation=${trigger.generation} ` + `aborted_siblings=${JSON.stringify(abortedSiblings)}`;
9614
+ this.rejectAllPending(new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} bridge killed during sibling timeout — request aborted; ${attribution}`));
9601
9615
  this.outstandingBackgroundTaskIds.clear();
9602
9616
  if (this.process) {
9603
9617
  this.process.kill("SIGKILL");
@@ -9607,17 +9621,11 @@ class BinaryBridge {
9607
9621
  this.configured = false;
9608
9622
  const tail = this.formatStderrTail();
9609
9623
  this.stderrTail = [];
9610
- const killedMsg = tail ? `Bridge killed after timeout.${tail}` : `Bridge killed after timeout (see ${this.getLogFilePathVia()})`;
9611
- if (tail) {
9612
- if (triggeringSessionId) {
9613
- this.sessionErrorVia(triggeringSessionId, killedMsg);
9614
- } else {
9615
- this.errorVia(killedMsg);
9616
- }
9617
- } else if (triggeringSessionId) {
9618
- this.sessionWarnVia(triggeringSessionId, killedMsg);
9624
+ const killedMsg = tail ? `Bridge killed after timeout; ${attribution}.${tail}` : `Bridge killed after timeout; ${attribution} (see ${this.getLogFilePathVia()})`;
9625
+ if (triggeringSessionId) {
9626
+ this.sessionErrorVia(triggeringSessionId, killedMsg);
9619
9627
  } else {
9620
- this.warnVia(killedMsg);
9628
+ this.errorVia(killedMsg);
9621
9629
  }
9622
9630
  }
9623
9631
  handleCrash(cause) {
@@ -15760,12 +15768,36 @@ function npmSpawnEnv(resolved, baseEnv = process.env, platform = process.platfor
15760
15768
  return withPathPrepended(baseEnv, resolved.binDir, platform);
15761
15769
  }
15762
15770
  // ../aft-bridge/dist/onnx-runtime.js
15763
- import { execFileSync } from "node:child_process";
15771
+ import { execFileSync as execFileSync2 } from "node:child_process";
15764
15772
  import { createHash as createHash3 } from "node:crypto";
15765
- import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync9, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
15766
- import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute5, join as join12, relative as relative2, resolve as resolve7, win32 } from "node:path";
15773
+ import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
15774
+ import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute5, join as join13, relative as relative2, resolve as resolve7, win32 } from "node:path";
15767
15775
  import { Readable as Readable2 } from "node:stream";
15768
15776
  import { pipeline as pipeline2 } from "node:stream/promises";
15777
+
15778
+ // ../aft-bridge/dist/tar-executable.js
15779
+ import { execFileSync } from "node:child_process";
15780
+ import { existsSync as existsSync9 } from "node:fs";
15781
+ import { join as join12 } from "node:path";
15782
+ function windowsTarExecutable(options = {}) {
15783
+ const platform = options.platform ?? process.platform;
15784
+ if (platform !== "win32")
15785
+ return "tar";
15786
+ const env = options.env ?? process.env;
15787
+ const systemTar = join12(env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe");
15788
+ return (options.exists ?? existsSync9)(systemTar) ? systemTar : "tar";
15789
+ }
15790
+ function execTarExtractionSync(args, timeout) {
15791
+ const executable = windowsTarExecutable();
15792
+ try {
15793
+ execFileSync(executable, args, { stdio: "pipe", timeout });
15794
+ } catch (cause) {
15795
+ const detail = cause instanceof Error ? cause.message : String(cause);
15796
+ throw new Error(`tar extraction failed using ${executable}: ${detail}`, { cause });
15797
+ }
15798
+ }
15799
+
15800
+ // ../aft-bridge/dist/onnx-runtime.js
15769
15801
  var ORT_VERSION = "1.24.4";
15770
15802
  var ORT_REPO = "microsoft/onnxruntime";
15771
15803
  var MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
@@ -15826,11 +15858,11 @@ function getManualInstallHint() {
15826
15858
  }
15827
15859
  async function ensureOnnxRuntime(storageDir) {
15828
15860
  const info = getPlatformInfo();
15829
- const ortVersionDir = join12(storageDir, "onnxruntime", ORT_VERSION);
15861
+ const ortVersionDir = join13(storageDir, "onnxruntime", ORT_VERSION);
15830
15862
  const libName = info?.libName ?? "libonnxruntime.dylib";
15831
15863
  const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
15832
- const libPath = join12(resolvedOrtDir, libName);
15833
- if (existsSync9(libPath)) {
15864
+ const libPath = join13(resolvedOrtDir, libName);
15865
+ if (existsSync10(libPath)) {
15834
15866
  const meta = readOnnxInstalledMeta(ortVersionDir);
15835
15867
  if (meta?.sha256) {
15836
15868
  try {
@@ -15859,9 +15891,9 @@ async function ensureOnnxRuntime(storageDir) {
15859
15891
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
15860
15892
  return null;
15861
15893
  }
15862
- const onnxBaseDir = join12(storageDir, "onnxruntime");
15894
+ const onnxBaseDir = join13(storageDir, "onnxruntime");
15863
15895
  mkdirSync5(onnxBaseDir, { recursive: true });
15864
- const lockPath = join12(onnxBaseDir, ONNX_LOCK_FILE);
15896
+ const lockPath = join13(onnxBaseDir, ONNX_LOCK_FILE);
15865
15897
  cleanupAbandonedStagingDirs(onnxBaseDir);
15866
15898
  if (!acquireLock(lockPath)) {
15867
15899
  warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
@@ -15880,7 +15912,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
15880
15912
  for (const entry of entries) {
15881
15913
  if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
15882
15914
  continue;
15883
- const stagingDir = join12(onnxBaseDir, entry);
15915
+ const stagingDir = join13(onnxBaseDir, entry);
15884
15916
  const parts = entry.split(".");
15885
15917
  const pidStr = parts[parts.length - 2];
15886
15918
  const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
@@ -15917,7 +15949,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
15917
15949
  }
15918
15950
  function cleanupIncompleteTargetIfUnowned(ortDir) {
15919
15951
  try {
15920
- if (existsSync9(ortDir) && !existsSync9(join12(ortDir, ONNX_INSTALLED_META_FILE))) {
15952
+ if (existsSync10(ortDir) && !existsSync10(join13(ortDir, ONNX_INSTALLED_META_FILE))) {
15921
15953
  log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
15922
15954
  rmSync3(ortDir, { recursive: true, force: true });
15923
15955
  }
@@ -15961,8 +15993,8 @@ function detectOnnxVersion(libDir, libName) {
15961
15993
  if (version)
15962
15994
  return version;
15963
15995
  }
15964
- const base = join12(libDir, libName);
15965
- if (existsSync9(base)) {
15996
+ const base = join13(libDir, libName);
15997
+ if (existsSync10(base)) {
15966
15998
  try {
15967
15999
  const real = realpathSync2(base);
15968
16000
  const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
@@ -16028,10 +16060,10 @@ function directoryContainsLibrary(dir, libName) {
16028
16060
  }
16029
16061
  }
16030
16062
  function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
16031
- if (existsSync9(join12(ortVersionDir, libName)))
16063
+ if (existsSync10(join13(ortVersionDir, libName)))
16032
16064
  return ortVersionDir;
16033
- const libSubdir = join12(ortVersionDir, "lib");
16034
- if (existsSync9(join12(libSubdir, libName)))
16065
+ const libSubdir = join13(ortVersionDir, "lib");
16066
+ if (existsSync10(join13(libSubdir, libName)))
16035
16067
  return libSubdir;
16036
16068
  return ortVersionDir;
16037
16069
  }
@@ -16046,13 +16078,13 @@ function findSystemOnnxRuntime(libName) {
16046
16078
  } else if (process.platform === "win32") {
16047
16079
  const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
16048
16080
  const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
16049
- searchPaths.push(join12(programFiles, "onnxruntime", "lib"), join12(programFiles, "Microsoft ONNX Runtime", "lib"), join12(programFiles, "Microsoft Machine Learning", "lib"), join12(programFilesX86, "onnxruntime", "lib"), ...(() => {
16081
+ searchPaths.push(join13(programFiles, "onnxruntime", "lib"), join13(programFiles, "Microsoft ONNX Runtime", "lib"), join13(programFiles, "Microsoft Machine Learning", "lib"), join13(programFilesX86, "onnxruntime", "lib"), ...(() => {
16050
16082
  const nugetPaths = [];
16051
16083
  const userProfile = process.env.USERPROFILE ?? "";
16052
16084
  if (!userProfile)
16053
16085
  return nugetPaths;
16054
- const nugetPackageDir = join12(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
16055
- if (!existsSync9(nugetPackageDir))
16086
+ const nugetPackageDir = join13(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
16087
+ if (!existsSync10(nugetPackageDir))
16056
16088
  return nugetPaths;
16057
16089
  try {
16058
16090
  for (const entry of readdirSync3(nugetPackageDir, { withFileTypes: true })) {
@@ -16060,7 +16092,7 @@ function findSystemOnnxRuntime(libName) {
16060
16092
  continue;
16061
16093
  if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
16062
16094
  continue;
16063
- nugetPaths.push(join12(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join12(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
16095
+ nugetPaths.push(join13(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join13(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
16064
16096
  }
16065
16097
  } catch (err) {
16066
16098
  warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
@@ -16082,11 +16114,11 @@ function findSystemOnnxRuntime(libName) {
16082
16114
  });
16083
16115
  const unknownVersionPaths = [];
16084
16116
  for (const dir of uniquePaths) {
16085
- const libPath = join12(dir, libName);
16117
+ const libPath = join13(dir, libName);
16086
16118
  if (process.platform === "win32") {
16087
16119
  if (!directoryContainsLibrary(dir, libName))
16088
16120
  continue;
16089
- } else if (!existsSync9(libPath)) {
16121
+ } else if (!existsSync10(libPath)) {
16090
16122
  continue;
16091
16123
  }
16092
16124
  const version = detectOnnxVersion(dir, libName);
@@ -16152,7 +16184,7 @@ function validateExtractedTree(stagingRoot) {
16152
16184
  const walk = (dir) => {
16153
16185
  const entries = readdirSync3(dir);
16154
16186
  for (const entry of entries) {
16155
- const fullPath = join12(dir, entry);
16187
+ const fullPath = join13(dir, entry);
16156
16188
  const lst = lstatSync(fullPath);
16157
16189
  if (lst.isSymbolicLink()) {
16158
16190
  const linkTarget = readlinkSync(fullPath);
@@ -16185,34 +16217,32 @@ async function downloadOnnxRuntime(info, targetDir) {
16185
16217
  const url = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
16186
16218
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
16187
16219
  const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
16220
+ const extractionRoot = join13(tmpDir, "extract");
16221
+ const stagedInstallDir = join13(tmpDir, "install");
16188
16222
  try {
16189
- mkdirSync5(tmpDir, { recursive: true });
16190
- const archivePath = join12(tmpDir, `onnxruntime.${info.archiveType}`);
16223
+ mkdirSync5(extractionRoot, { recursive: true });
16224
+ const archivePath = join13(tmpDir, `onnxruntime.${info.archiveType}`);
16191
16225
  await downloadFileWithCap(url, archivePath);
16192
16226
  const archiveSha256 = sha256File(archivePath);
16193
16227
  log(`ONNX Runtime archive sha256=${archiveSha256}`);
16194
16228
  if (info.archiveType === "tgz") {
16195
- execFileSync("tar", ["xzf", archivePath, "-C", tmpDir], {
16196
- stdio: "pipe",
16197
- timeout: 120000
16198
- });
16229
+ execTarExtractionSync(["xzf", archivePath, "-C", extractionRoot], 120000);
16199
16230
  } else {
16200
- await extractZipArchive(archivePath, tmpDir);
16231
+ await extractZipArchive(archivePath, extractionRoot);
16201
16232
  }
16202
16233
  try {
16203
16234
  unlinkSync4(archivePath);
16204
16235
  } catch {}
16205
- validateExtractedTree(tmpDir);
16206
- const extractedDir = join12(tmpDir, info.assetName, "lib");
16207
- if (!existsSync9(extractedDir)) {
16236
+ validateExtractedTree(extractionRoot);
16237
+ const extractedDir = join13(extractionRoot, info.assetName, "lib");
16238
+ if (!existsSync10(extractedDir)) {
16208
16239
  throw new Error(`Expected directory not found: ${extractedDir}`);
16209
16240
  }
16210
- mkdirSync5(targetDir, { recursive: true });
16211
16241
  const libFiles = readdirSync3(extractedDir).filter((f) => f.startsWith("libonnxruntime") || f.startsWith("onnxruntime"));
16212
16242
  const realFiles = [];
16213
16243
  const symlinks = [];
16214
16244
  for (const libFile of libFiles) {
16215
- const src = join12(extractedDir, libFile);
16245
+ const src = join13(extractedDir, libFile);
16216
16246
  try {
16217
16247
  const stat = lstatSync(src);
16218
16248
  log(`ORT extract: ${libFile} — isSymlink=${stat.isSymbolicLink()}, isFile=${stat.isFile()}, size=${stat.size}`);
@@ -16226,15 +16256,11 @@ async function downloadOnnxRuntime(info, targetDir) {
16226
16256
  realFiles.push(libFile);
16227
16257
  }
16228
16258
  }
16229
- copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
16230
- const libPath = join12(targetDir, info.libName);
16231
- let libHash = null;
16232
- try {
16233
- libHash = sha256File(libPath);
16234
- } catch (err) {
16235
- warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
16236
- }
16237
- writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
16259
+ copyOnnxLibraries(info, extractedDir, stagedInstallDir, realFiles, symlinks);
16260
+ const libPath = join13(stagedInstallDir, info.libName);
16261
+ const libHash = sha256File(libPath);
16262
+ writeOnnxInstalledMeta(stagedInstallDir, ORT_VERSION, libHash, archiveSha256);
16263
+ publishOnnxRuntime(stagedInstallDir, targetDir);
16238
16264
  rmSync3(tmpDir, { recursive: true, force: true });
16239
16265
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
16240
16266
  return targetDir;
@@ -16243,17 +16269,39 @@ async function downloadOnnxRuntime(info, targetDir) {
16243
16269
  try {
16244
16270
  rmSync3(tmpDir, { recursive: true, force: true });
16245
16271
  } catch {}
16246
- try {
16247
- rmSync3(targetDir, { recursive: true, force: true });
16248
- } catch {}
16249
16272
  return null;
16250
16273
  }
16251
16274
  }
16275
+ function publishOnnxRuntime(stagedInstallDir, targetDir) {
16276
+ const backupDir = `${targetDir}.backup.${process.pid}.${Date.now().toString(36)}`;
16277
+ const hadTarget = existsSync10(targetDir);
16278
+ if (hadTarget)
16279
+ renameSync5(targetDir, backupDir);
16280
+ try {
16281
+ renameSync5(stagedInstallDir, targetDir);
16282
+ } catch (installError) {
16283
+ if (hadTarget) {
16284
+ try {
16285
+ renameSync5(backupDir, targetDir);
16286
+ } catch (restoreError) {
16287
+ throw new Error(`ONNX Runtime replacement failed and the previous runtime could not be restored from ${backupDir}: ${restoreError}`, { cause: installError });
16288
+ }
16289
+ }
16290
+ throw installError;
16291
+ }
16292
+ if (hadTarget) {
16293
+ try {
16294
+ rmSync3(backupDir, { recursive: true, force: true });
16295
+ } catch (err) {
16296
+ warn(`Could not remove replaced ONNX Runtime backup at ${backupDir}: ${err}`);
16297
+ }
16298
+ }
16299
+ }
16252
16300
  function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
16253
16301
  const requiredLibs = new Set([info.libName]);
16254
16302
  for (const libFile of realFiles) {
16255
- const src = join12(extractedDir, libFile);
16256
- const dst = join12(targetDir, libFile);
16303
+ const src = join13(extractedDir, libFile);
16304
+ const dst = join13(targetDir, libFile);
16257
16305
  try {
16258
16306
  copyFile(src, dst);
16259
16307
  if (process.platform !== "win32") {
@@ -16269,11 +16317,11 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
16269
16317
  }
16270
16318
  const targetRoot = realpathSync2(targetDir);
16271
16319
  for (const link of symlinks) {
16272
- const dst = join12(targetDir, link.name);
16320
+ const dst = join13(targetDir, link.name);
16273
16321
  try {
16274
16322
  unlinkSync4(dst);
16275
16323
  } catch {}
16276
- const dstForContainment = join12(targetRoot, link.name);
16324
+ const dstForContainment = join13(targetRoot, link.name);
16277
16325
  const resolvedTarget = resolve7(dirname5(dstForContainment), link.target);
16278
16326
  if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
16279
16327
  const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
@@ -16294,21 +16342,18 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
16294
16342
  log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
16295
16343
  }
16296
16344
  }
16297
- const requiredPath = join12(targetDir, info.libName);
16298
- if (!existsSync9(requiredPath)) {
16345
+ const requiredPath = join13(targetDir, info.libName);
16346
+ if (!existsSync10(requiredPath)) {
16299
16347
  rmSync3(targetDir, { recursive: true, force: true });
16300
16348
  throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
16301
16349
  }
16302
16350
  }
16303
16351
  async function extractZipArchive(archivePath, destinationDir) {
16304
16352
  if (process.platform === "win32") {
16305
- execFileSync("tar.exe", ["-xf", archivePath, "-C", destinationDir], {
16306
- stdio: "pipe",
16307
- timeout: 120000
16308
- });
16353
+ execTarExtractionSync(["-xf", archivePath, "-C", destinationDir], 120000);
16309
16354
  return;
16310
16355
  }
16311
- execFileSync("unzip", ["-q", archivePath, "-d", destinationDir], {
16356
+ execFileSync2("unzip", ["-q", archivePath, "-d", destinationDir], {
16312
16357
  stdio: "pipe",
16313
16358
  timeout: 120000
16314
16359
  });
@@ -16321,13 +16366,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
16321
16366
  ...sha256 ? { sha256 } : {},
16322
16367
  archiveSha256
16323
16368
  };
16324
- writeFileSync3(join12(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
16369
+ writeFileSync3(join13(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
16325
16370
  } catch (err) {
16326
16371
  log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
16327
16372
  }
16328
16373
  }
16329
16374
  function readOnnxInstalledMeta(installDir) {
16330
- const path = join12(installDir, ONNX_INSTALLED_META_FILE);
16375
+ const path = join13(installDir, ONNX_INSTALLED_META_FILE);
16331
16376
  try {
16332
16377
  if (!statSync6(path).isFile())
16333
16378
  return null;
@@ -16439,7 +16484,7 @@ function isWindowsProcessAlive(pid) {
16439
16484
  if (!Number.isInteger(pid) || pid <= 0)
16440
16485
  return false;
16441
16486
  try {
16442
- const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
16487
+ const output = execFileSync2("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
16443
16488
  encoding: "utf8",
16444
16489
  timeout: 2000,
16445
16490
  windowsHide: true
@@ -16660,10 +16705,8 @@ function prepareCanonicalEditArguments(toolName, rawArguments) {
16660
16705
  if (unknownRootKeys.length > 0) {
16661
16706
  throw new InvalidRequestError(formatUnknownKeys(unknownRootKeys));
16662
16707
  }
16708
+ validateSymbolModePair(record);
16663
16709
  const modes = editModesPresent(record);
16664
- if (hasOrphanedSymbolContent(record)) {
16665
- throw new InvalidRequestError("edit: 'content' requires a non-empty string 'symbol' when symbol mode is selected");
16666
- }
16667
16710
  if (modes.length > 1) {
16668
16711
  throw new InvalidRequestError(`edit: conflicting modes: ${modes.join(", ")}. ${OMIT_OPTIONAL_FIELDS_STEERING}`);
16669
16712
  }
@@ -16683,7 +16726,7 @@ function prepareCanonicalEditArguments(toolName, rawArguments) {
16683
16726
  throw new InvalidRequestError("edit: 'symbol' must be a string when symbol mode is selected");
16684
16727
  }
16685
16728
  if (!hasOwn(record, "content") || typeof record.content !== "string") {
16686
- throw new InvalidRequestError("edit: symbol mode requires both 'symbol' and 'content' string properties");
16729
+ throw new InvalidRequestError("edit: incomplete symbol mode: property 'content' must be a string. " + "Retry with `symbol` + `content`, or use `edits[]`.");
16687
16730
  }
16688
16731
  } else {
16689
16732
  const item = {};
@@ -16736,6 +16779,29 @@ function validateEditPath(record) {
16736
16779
  function formatUnknownKeys(keys) {
16737
16780
  return `Unrecognized keys: ${keys.map((key) => `"${key}"`).join(", ")}`;
16738
16781
  }
16782
+ function validateSymbolModePair(record) {
16783
+ const completeShapes = "Retry with `symbol` + `content`, or use `edits[]`.";
16784
+ const hasSymbol = isNonEmptyString(record.symbol);
16785
+ const hasContent = isNonEmptyString(record.content);
16786
+ if (hasSymbol) {
16787
+ if (!hasOwn(record, "content")) {
16788
+ throw new InvalidRequestError(`edit: incomplete symbol mode: missing property 'content'. ${completeShapes}`);
16789
+ }
16790
+ if (record.content === null) {
16791
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'content' is null. ${completeShapes}`);
16792
+ }
16793
+ return;
16794
+ }
16795
+ if (!hasContent)
16796
+ return;
16797
+ if (!hasOwn(record, "symbol")) {
16798
+ throw new InvalidRequestError(`edit: incomplete symbol mode: missing property 'symbol'. ${completeShapes}`);
16799
+ }
16800
+ if (record.symbol === null) {
16801
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'symbol' is null. ${completeShapes}`);
16802
+ }
16803
+ throw new InvalidRequestError(`edit: incomplete symbol mode: property 'symbol' must be a non-empty string. ${completeShapes}`);
16804
+ }
16739
16805
  function editModesPresent(record) {
16740
16806
  const hasAppendContent = isNonEmptyString(record.appendContent);
16741
16807
  if (!hasAppendContent)
@@ -16821,9 +16887,6 @@ function normalizeEditArraySentinels(record) {
16821
16887
  return true;
16822
16888
  }
16823
16889
  }
16824
- function hasOrphanedSymbolContent(record) {
16825
- return isNonEmptyString(record.content) && !isNonEmptyString(record.symbol);
16826
- }
16827
16890
  function parseEditArray(value) {
16828
16891
  if (typeof value === "string") {
16829
16892
  let parsed;
@@ -17006,6 +17069,48 @@ function copyOwnProperties(source) {
17006
17069
  copy[key] = source[key];
17007
17070
  return copy;
17008
17071
  }
17072
+ // ../aft-bridge/dist/semantic-status.js
17073
+ var MISSING_ONNX_RUNTIME_MARKER = "ONNX Runtime not found.";
17074
+ var MISSING_ONNX_RUNTIME_LABEL = "unavailable — ONNX Runtime missing (npx @cortexkit/aft doctor --fix)";
17075
+ var REBUILDING_LABEL = "Rebuilding (model changed)";
17076
+ var SEMANTIC_PROGRESS_STATUSES = new Set(["building", "loading"]);
17077
+ var SEMANTIC_READY_STATUSES = new Set(["ready", "empty"]);
17078
+ var SEMANTIC_INACTIVE_STATUSES = new Set(["disabled", "busy"]);
17079
+ var SEMANTIC_FAILURE_LABELS = {
17080
+ backend_unavailable: "backend unavailable",
17081
+ degraded: "degraded",
17082
+ error: "error",
17083
+ failed: "failed",
17084
+ unavailable: "unavailable"
17085
+ };
17086
+ function semanticIndexStatusKind(status) {
17087
+ if (SEMANTIC_READY_STATUSES.has(status))
17088
+ return "ready";
17089
+ if (SEMANTIC_PROGRESS_STATUSES.has(status))
17090
+ return "progress";
17091
+ if (status in SEMANTIC_FAILURE_LABELS)
17092
+ return "failure";
17093
+ if (SEMANTIC_INACTIVE_STATUSES.has(status))
17094
+ return "inactive";
17095
+ return "unrecognized";
17096
+ }
17097
+ function mentionsMissingOnnxRuntime(...values) {
17098
+ return values.some((value) => typeof value === "string" && value.includes(MISSING_ONNX_RUNTIME_MARKER));
17099
+ }
17100
+ function semanticFailureLabel(status, stage, error) {
17101
+ if (mentionsMissingOnnxRuntime(error, stage))
17102
+ return MISSING_ONNX_RUNTIME_LABEL;
17103
+ return SEMANTIC_FAILURE_LABELS[status] ?? null;
17104
+ }
17105
+ function formatSemanticIndexStatus(status, stage, error) {
17106
+ const failure = semanticFailureLabel(status, stage, error);
17107
+ if (failure)
17108
+ return failure;
17109
+ if (semanticIndexStatusKind(status) === "progress" && stage === "fingerprint_change") {
17110
+ return REBUILDING_LABEL;
17111
+ }
17112
+ return status;
17113
+ }
17009
17114
  // ../aft-bridge/dist/tool-format.js
17010
17115
  function asPlainObject(value) {
17011
17116
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -18049,7 +18154,7 @@ import {
18049
18154
  // package.json
18050
18155
  var package_default = {
18051
18156
  name: "@cortexkit/aft-pi",
18052
- version: "0.56.1",
18157
+ version: "0.57.0",
18053
18158
  type: "module",
18054
18159
  description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
18055
18160
  main: "dist/index.js",
@@ -18072,19 +18177,19 @@ var package_default = {
18072
18177
  "test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
18073
18178
  },
18074
18179
  dependencies: {
18075
- "@cortexkit/aft-bridge": "0.56.1",
18180
+ "@cortexkit/aft-bridge": "0.57.0",
18076
18181
  "comment-json": "^5.0.0",
18077
18182
  diff: "^8.0.4",
18078
18183
  typebox: "1.1.38",
18079
18184
  zod: "^4.4.3"
18080
18185
  },
18081
18186
  optionalDependencies: {
18082
- "@cortexkit/aft-darwin-arm64": "0.56.1",
18083
- "@cortexkit/aft-darwin-x64": "0.56.1",
18084
- "@cortexkit/aft-linux-arm64": "0.56.1",
18085
- "@cortexkit/aft-linux-x64": "0.56.1",
18086
- "@cortexkit/aft-win32-arm64": "0.56.1",
18087
- "@cortexkit/aft-win32-x64": "0.56.1"
18187
+ "@cortexkit/aft-darwin-arm64": "0.57.0",
18188
+ "@cortexkit/aft-darwin-x64": "0.57.0",
18189
+ "@cortexkit/aft-linux-arm64": "0.57.0",
18190
+ "@cortexkit/aft-linux-x64": "0.57.0",
18191
+ "@cortexkit/aft-win32-arm64": "0.57.0",
18192
+ "@cortexkit/aft-win32-x64": "0.57.0"
18088
18193
  },
18089
18194
  devDependencies: {
18090
18195
  "@earendil-works/pi-coding-agent": "^0.80.2",
@@ -18185,12 +18290,6 @@ function formatCacheRoleLabel(role) {
18185
18290
  }
18186
18291
  return role;
18187
18292
  }
18188
- function formatSemanticIndexStatus(status, stage) {
18189
- if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
18190
- return "Rebuilding (model changed)";
18191
- }
18192
- return status;
18193
- }
18194
18293
  function formatSemanticRefreshing(refreshingCount) {
18195
18294
  if (!Number.isFinite(refreshingCount) || refreshingCount <= 0)
18196
18295
  return null;
@@ -18291,7 +18390,7 @@ function formatStatusDialogMessage(status) {
18291
18390
  `Cache role: ${formatCacheRoleLabel(status.cache_role)}`
18292
18391
  ];
18293
18392
  appendDegradedStatus(lines, status, false);
18294
- lines.push("", "Enabled features", `- format_on_edit: ${formatFlag(status.features.format_on_edit)}`, `- search_index: ${formatFlag(status.features.search_index)}`, `- semantic_search: ${formatFlag(status.features.semantic_search)}`, `- callgraph_store: ${formatFlag(status.features.callgraph_store)}`, "", "Search index", `- status: ${status.search_index.status}`, `- files: ${formatCount(status.search_index.files)}`, `- trigrams: ${formatCount(status.search_index.trigrams)}`, "", "Semantic index", `- status: ${formatSemanticIndexStatus(status.semantic_index.status, status.semantic_index.stage)}`);
18393
+ lines.push("", "Enabled features", `- format_on_edit: ${formatFlag(status.features.format_on_edit)}`, `- search_index: ${formatFlag(status.features.search_index)}`, `- semantic_search: ${formatFlag(status.features.semantic_search)}`, `- callgraph_store: ${formatFlag(status.features.callgraph_store)}`, "", "Search index", `- status: ${status.search_index.status}`, `- files: ${formatCount(status.search_index.files)}`, `- trigrams: ${formatCount(status.search_index.trigrams)}`, "", "Semantic index", `- status: ${formatSemanticIndexStatus(status.semantic_index.status, status.semantic_index.stage, status.semantic_index.error)}`);
18295
18394
  const refreshing = formatSemanticRefreshing(status.semantic_index.refreshing_count);
18296
18395
  if (refreshing) {
18297
18396
  lines.push(`- ${refreshing}`);
@@ -18352,7 +18451,7 @@ function appendDegradedStatus(lines, status, markdown) {
18352
18451
  }
18353
18452
 
18354
18453
  // src/tools/_shared.ts
18355
- import { existsSync as existsSync10 } from "node:fs";
18454
+ import { existsSync as existsSync11 } from "node:fs";
18356
18455
  import { Type } from "typebox";
18357
18456
  var optionalInt = (min, max, description = "(integer)") => Type.Optional(Type.Union([Type.Integer({ minimum: min, maximum: max }), Type.String()], {
18358
18457
  description
@@ -18411,7 +18510,7 @@ function prepareToolDefinitionForRegistration(tool, harness = "pi", presentation
18411
18510
  };
18412
18511
  }
18413
18512
  function bridgeFor(ctx, cwd) {
18414
- if (!existsSync10(cwd)) {
18513
+ if (!existsSync11(cwd)) {
18415
18514
  throw new Error(`project directory no longer exists: ${cwd} (stale restored session?)`);
18416
18515
  }
18417
18516
  return ctx.pool.getBridge(cwd);
@@ -18785,7 +18884,7 @@ function registerStatusCommand(pi, ctx) {
18785
18884
  }
18786
18885
 
18787
18886
  // src/config.ts
18788
- import { existsSync as existsSync11, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
18887
+ import { existsSync as existsSync12, readFileSync as readFileSync7, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
18789
18888
  import { homedir as homedir12 } from "node:os";
18790
18889
  import { isAbsolute as isAbsolute6 } from "node:path";
18791
18890
  var import_comment_json = __toESM(require_src2(), 1);
@@ -23692,6 +23791,7 @@ var InspectConfigSchema = object({
23692
23791
  enabled: boolean2().optional(),
23693
23792
  diagnostics_timeout_ms: number2().int().positive().optional().transform((value) => value === undefined ? undefined : clampInspectDiagnosticsTimeoutMs(value)),
23694
23793
  tier2_idle_minutes: number2().min(0).optional(),
23794
+ tier2_pass_timeout_ms: number2().int().positive().optional(),
23695
23795
  categories: record(string2(), boolean2()).optional(),
23696
23796
  tier2_soft_deadline_ms: number2().int().positive().optional(),
23697
23797
  max_drill_down_items: number2().int().positive().max(100).optional(),
@@ -23912,7 +24012,7 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
23912
24012
  return movedKeys;
23913
24013
  }
23914
24014
  function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
23915
- if (!existsSync11(configPath)) {
24015
+ if (!existsSync12(configPath)) {
23916
24016
  return { migrated: false, oldKeys: [] };
23917
24017
  }
23918
24018
  let tmpPath = null;
@@ -23935,7 +24035,7 @@ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 })
23935
24035
  ${serialized}` : serialized;
23936
24036
  tmpPath = `${configPath}.tmp.${process.pid}`;
23937
24037
  writeFileSync4(tmpPath, nextContent, "utf-8");
23938
- renameSync5(tmpPath, configPath);
24038
+ renameSync6(tmpPath, configPath);
23939
24039
  logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
23940
24040
  return { migrated: true, oldKeys };
23941
24041
  } catch (err) {
@@ -23971,7 +24071,7 @@ function warnIgnoredHarnessSpecificConfigKeys(config, configPath) {
23971
24071
  }
23972
24072
  function loadConfigFromPath(configPath) {
23973
24073
  try {
23974
- if (!existsSync11(configPath))
24074
+ if (!existsSync12(configPath))
23975
24075
  return null;
23976
24076
  const content = readFileSync7(configPath, "utf-8");
23977
24077
  const rawConfig = import_comment_json.parse(content);
@@ -24328,15 +24428,15 @@ import { spawn as spawn4 } from "node:child_process";
24328
24428
  import { createHash as createHash4 } from "node:crypto";
24329
24429
  import {
24330
24430
  createReadStream,
24331
- existsSync as existsSync13,
24431
+ existsSync as existsSync14,
24332
24432
  mkdirSync as mkdirSync7,
24333
24433
  readFileSync as readFileSync10,
24334
- renameSync as renameSync7,
24434
+ renameSync as renameSync8,
24335
24435
  rmSync as rmSync5,
24336
24436
  statSync as statSync8,
24337
24437
  writeFileSync as writeFileSync6
24338
24438
  } from "node:fs";
24339
- import { join as join15 } from "node:path";
24439
+ import { join as join16 } from "node:path";
24340
24440
 
24341
24441
  // src/lsp-cache.ts
24342
24442
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -24345,13 +24445,13 @@ import {
24345
24445
  mkdirSync as mkdirSync6,
24346
24446
  openSync as openSync5,
24347
24447
  readFileSync as readFileSync8,
24348
- renameSync as renameSync6,
24448
+ renameSync as renameSync7,
24349
24449
  rmSync as rmSync4,
24350
24450
  statSync as statSync7,
24351
24451
  unlinkSync as unlinkSync6,
24352
24452
  writeFileSync as writeFileSync5
24353
24453
  } from "node:fs";
24354
- import { join as join13 } from "node:path";
24454
+ import { join as join14 } from "node:path";
24355
24455
  function aftCacheBase() {
24356
24456
  return getAftCacheRoot();
24357
24457
  }
@@ -24359,18 +24459,18 @@ function lspCacheRoot() {
24359
24459
  return getAftLspPackagesDir();
24360
24460
  }
24361
24461
  function lspPackageDir(npmPackage) {
24362
- return join13(lspCacheRoot(), encodeURIComponent(npmPackage));
24462
+ return join14(lspCacheRoot(), encodeURIComponent(npmPackage));
24363
24463
  }
24364
24464
  function lspBinaryPath(npmPackage, binary) {
24365
- return join13(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
24465
+ return join14(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
24366
24466
  }
24367
24467
  function lspBinDir(npmPackage) {
24368
- return join13(lspPackageDir(npmPackage), "node_modules", ".bin");
24468
+ return join14(lspPackageDir(npmPackage), "node_modules", ".bin");
24369
24469
  }
24370
24470
  function isInstalled(npmPackage, binary) {
24371
24471
  for (const candidate of lspBinaryCandidates(binary)) {
24372
24472
  try {
24373
- if (statSync7(join13(lspBinDir(npmPackage), candidate)).isFile())
24473
+ if (statSync7(join14(lspBinDir(npmPackage), candidate)).isFile())
24374
24474
  return true;
24375
24475
  } catch {}
24376
24476
  }
@@ -24390,13 +24490,13 @@ function writeInstalledMetaIn(installDir, version, sha256) {
24390
24490
  installedAt: new Date().toISOString(),
24391
24491
  ...sha256 ? { sha256 } : {}
24392
24492
  };
24393
- writeFileSync5(join13(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
24493
+ writeFileSync5(join14(installDir, INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
24394
24494
  } catch (err) {
24395
24495
  log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
24396
24496
  }
24397
24497
  }
24398
24498
  function readInstalledMetaIn(installDir) {
24399
- const path = join13(installDir, INSTALLED_META_FILE);
24499
+ const path = join14(installDir, INSTALLED_META_FILE);
24400
24500
  try {
24401
24501
  if (!statSync7(path).isFile())
24402
24502
  return null;
@@ -24420,7 +24520,7 @@ function readInstalledMeta(packageKey) {
24420
24520
  return readInstalledMetaIn(lspPackageDir(packageKey));
24421
24521
  }
24422
24522
  function lockPath(npmPackage) {
24423
- return join13(lspPackageDir(npmPackage), ".aft-installing");
24523
+ return join14(lspPackageDir(npmPackage), ".aft-installing");
24424
24524
  }
24425
24525
  var STALE_LOCK_MS2 = 30 * 60 * 1000;
24426
24526
  function acquireInstallLock(lockKey) {
@@ -24551,7 +24651,7 @@ var AUTO_INSTALL_STAMP_FILE = "last-lsp-autoinstall.json";
24551
24651
  var AUTO_INSTALL_WINDOW_MS = 60 * 1000;
24552
24652
  var AUTO_INSTALL_LOCK_STALE_MS = 30 * 60 * 1000;
24553
24653
  function autoInstallStampPath() {
24554
- return join13(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
24654
+ return join14(aftCacheBase(), AUTO_INSTALL_STAMP_FILE);
24555
24655
  }
24556
24656
  function hasRecentAutoInstallStamp(path) {
24557
24657
  try {
@@ -24637,7 +24737,7 @@ function claimLspAutoInstallPass() {
24637
24737
  encoding: "utf8",
24638
24738
  mode: 384
24639
24739
  });
24640
- renameSync6(tempPath, stampPath);
24740
+ renameSync7(tempPath, stampPath);
24641
24741
  return { release };
24642
24742
  } catch (err) {
24643
24743
  if (claimed) {
@@ -24652,7 +24752,7 @@ function claimLspAutoInstallPass() {
24652
24752
  }
24653
24753
  var VERSION_CHECK_FILE = ".aft-version-check";
24654
24754
  function readVersionCheck(npmPackage) {
24655
- const file = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
24755
+ const file = join14(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
24656
24756
  try {
24657
24757
  const raw = readFileSync8(file, "utf8");
24658
24758
  const parsed = JSON.parse(raw);
@@ -24669,7 +24769,7 @@ function readVersionCheck(npmPackage) {
24669
24769
  }
24670
24770
  function writeVersionCheck(npmPackage, latest) {
24671
24771
  mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
24672
- const file = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
24772
+ const file = join14(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
24673
24773
  const record = {
24674
24774
  last_checked: new Date().toISOString(),
24675
24775
  latest_eligible: latest
@@ -24831,8 +24931,8 @@ var NPM_LSP_TABLE = [
24831
24931
  ];
24832
24932
 
24833
24933
  // src/lsp-project-relevance.ts
24834
- import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
24835
- import { join as join14 } from "node:path";
24934
+ import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
24935
+ import { join as join15 } from "node:path";
24836
24936
  var MAX_WALK_DIRS = 200;
24837
24937
  var MAX_WALK_DEPTH = 4;
24838
24938
  var NOISE_DIRS = new Set([
@@ -24849,7 +24949,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
24849
24949
  if (!rootMarkers)
24850
24950
  return false;
24851
24951
  for (const marker of rootMarkers) {
24852
- if (existsSync12(join14(projectRoot, marker)))
24952
+ if (existsSync13(join15(projectRoot, marker)))
24853
24953
  return true;
24854
24954
  }
24855
24955
  return false;
@@ -24873,7 +24973,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
24873
24973
  }
24874
24974
  function readPackageJson(projectRoot) {
24875
24975
  try {
24876
- const raw = readFileSync9(join14(projectRoot, "package.json"), "utf8");
24976
+ const raw = readFileSync9(join15(projectRoot, "package.json"), "utf8");
24877
24977
  const parsed = JSON.parse(raw);
24878
24978
  if (typeof parsed !== "object" || parsed === null)
24879
24979
  return null;
@@ -24903,7 +25003,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
24903
25003
  for (const entry of entries) {
24904
25004
  if (entry.isDirectory()) {
24905
25005
  if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
24906
- queue.push({ dir: join14(current.dir, entry.name), depth: current.depth + 1 });
25006
+ queue.push({ dir: join15(current.dir, entry.name), depth: current.depth + 1 });
24907
25007
  }
24908
25008
  continue;
24909
25009
  }
@@ -25031,8 +25131,8 @@ async function resolveTargetVersion(spec, config, fetchImpl = fetch) {
25031
25131
  }
25032
25132
  function ensureInstallAnchor(cwd) {
25033
25133
  try {
25034
- const stub = join15(cwd, "package.json");
25035
- if (!existsSync13(stub)) {
25134
+ const stub = join16(cwd, "package.json");
25135
+ if (!existsSync14(stub)) {
25036
25136
  writeFileSync6(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
25037
25137
  `);
25038
25138
  }
@@ -25258,12 +25358,12 @@ function sha256OfFileSync(path) {
25258
25358
  }
25259
25359
  function quarantineCachedNpmInstall(spec, reason) {
25260
25360
  const packageDir = lspPackageDir(spec.npm);
25261
- const dest = join15(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
25361
+ const dest = join16(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
25262
25362
  warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
25263
25363
  try {
25264
- mkdirSync7(join15(dest, ".."), { recursive: true });
25364
+ mkdirSync7(join16(dest, ".."), { recursive: true });
25265
25365
  rmSync5(dest, { recursive: true, force: true });
25266
- renameSync7(packageDir, dest);
25366
+ renameSync8(packageDir, dest);
25267
25367
  } catch (err) {
25268
25368
  warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
25269
25369
  }
@@ -25343,26 +25443,26 @@ async function pushLspPathsAfterAutoInstall(pool, projectRoot, cachedBinDirs) {
25343
25443
  }
25344
25444
 
25345
25445
  // src/lsp-github-install.ts
25346
- import { execFileSync as execFileSync2 } from "node:child_process";
25446
+ import { execFileSync as execFileSync3 } from "node:child_process";
25347
25447
  import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
25348
25448
  import {
25349
25449
  copyFileSync as copyFileSync4,
25350
25450
  createReadStream as createReadStream2,
25351
25451
  createWriteStream as createWriteStream3,
25352
- existsSync as existsSync14,
25452
+ existsSync as existsSync15,
25353
25453
  lstatSync as lstatSync2,
25354
25454
  mkdirSync as mkdirSync8,
25355
25455
  readdirSync as readdirSync5,
25356
25456
  readFileSync as readFileSync11,
25357
25457
  readlinkSync as readlinkSync2,
25358
25458
  realpathSync as realpathSync3,
25359
- renameSync as renameSync8,
25459
+ renameSync as renameSync9,
25360
25460
  rmSync as rmSync6,
25361
25461
  statSync as statSync9,
25362
25462
  unlinkSync as unlinkSync7,
25363
25463
  writeFileSync as writeFileSync7
25364
25464
  } from "node:fs";
25365
- import { dirname as dirname6, join as join16, relative as relative3, resolve as resolve8 } from "node:path";
25465
+ import { dirname as dirname6, join as join17, relative as relative3, resolve as resolve8 } from "node:path";
25366
25466
  import { Readable as Readable3 } from "node:stream";
25367
25467
  import { pipeline as pipeline3 } from "node:stream/promises";
25368
25468
 
@@ -25455,19 +25555,19 @@ function ghCacheRoot() {
25455
25555
  return getAftLspBinariesDir();
25456
25556
  }
25457
25557
  function ghPackageDir(spec) {
25458
- return join16(ghCacheRoot(), spec.id);
25558
+ return join17(ghCacheRoot(), spec.id);
25459
25559
  }
25460
25560
  function ghBinDir(spec) {
25461
- return join16(ghPackageDir(spec), "bin");
25561
+ return join17(ghPackageDir(spec), "bin");
25462
25562
  }
25463
25563
  function ghExtractDir(spec) {
25464
- return join16(ghPackageDir(spec), "extracted");
25564
+ return join17(ghPackageDir(spec), "extracted");
25465
25565
  }
25466
25566
  var INSTALLED_META_FILE2 = ".aft-installed";
25467
25567
  var INSTALL_FAILED_FILE = ".aft-install-failed.json";
25468
25568
  var INSTALL_FAILURE_BACKOFF_MS = 6 * 60 * 60 * 1000;
25469
25569
  function installFailureMarkerPath(spec) {
25470
- return join16(ghPackageDir(spec), INSTALL_FAILED_FILE);
25570
+ return join17(ghPackageDir(spec), INSTALL_FAILED_FILE);
25471
25571
  }
25472
25572
  function readInstallFailureMarker(spec) {
25473
25573
  try {
@@ -25488,7 +25588,7 @@ function writeInstallFailureMarker(spec, release, sha256, installError) {
25488
25588
  mkdirSync8(dirname6(path), { recursive: true });
25489
25589
  writeFileSync7(tempPath, `${JSON.stringify({ release, sha256, error: markerError, at: new Date().toISOString() })}
25490
25590
  `, { encoding: "utf8", mode: 384 });
25491
- renameSync8(tempPath, path);
25591
+ renameSync9(tempPath, path);
25492
25592
  } catch (err) {
25493
25593
  try {
25494
25594
  rmSync6(tempPath, { force: true });
@@ -25509,12 +25609,12 @@ function isFreshInstallFailure(marker) {
25509
25609
  }
25510
25610
  function ghBinaryPath(spec, platform) {
25511
25611
  const ext = platform === "win32" ? ".exe" : "";
25512
- return join16(ghBinDir(spec), `${spec.binary}${ext}`);
25612
+ return join17(ghBinDir(spec), `${spec.binary}${ext}`);
25513
25613
  }
25514
25614
  function isGithubInstalled(spec, platform) {
25515
25615
  for (const candidate of ghBinaryCandidates(spec, platform)) {
25516
25616
  try {
25517
- if (statSync9(join16(ghBinDir(spec), candidate)).isFile())
25617
+ if (statSync9(join17(ghBinDir(spec), candidate)).isFile())
25518
25618
  return true;
25519
25619
  } catch {}
25520
25620
  }
@@ -25527,7 +25627,7 @@ function ghBinaryCandidates(spec, platform) {
25527
25627
  }
25528
25628
  function readGithubInstalledMetaIn(installDir) {
25529
25629
  try {
25530
- const path = join16(installDir, INSTALLED_META_FILE2);
25630
+ const path = join17(installDir, INSTALLED_META_FILE2);
25531
25631
  if (!statSync9(path).isFile())
25532
25632
  return null;
25533
25633
  const parsed = JSON.parse(readFileSync11(path, "utf8"));
@@ -25554,7 +25654,7 @@ function writeGithubInstalledMetaIn(installDir, version, binarySha256, archiveSh
25554
25654
  binarySha256,
25555
25655
  ...archiveSha256 ? { archiveSha256 } : {}
25556
25656
  };
25557
- writeFileSync7(join16(installDir, INSTALLED_META_FILE2), JSON.stringify(meta), "utf8");
25657
+ writeFileSync7(join17(installDir, INSTALLED_META_FILE2), JSON.stringify(meta), "utf8");
25558
25658
  } catch (err) {
25559
25659
  warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
25560
25660
  }
@@ -25803,7 +25903,7 @@ function validateExtraction(stagingRoot) {
25803
25903
  throw new Error(`failed to read staging dir ${dir}: ${err}`);
25804
25904
  }
25805
25905
  for (const entry of entries) {
25806
- const full = join16(dir, entry);
25906
+ const full = join17(dir, entry);
25807
25907
  let lst;
25808
25908
  try {
25809
25909
  lst = lstatSync2(full);
@@ -25849,7 +25949,7 @@ function assertArchiveEntryPath(entry) {
25849
25949
  }
25850
25950
  function precheckWithTar(archivePath, command) {
25851
25951
  let totalBytes = 0;
25852
- const verbose = execFileSync2(command, ["-tvf", archivePath], { encoding: "utf8" });
25952
+ const verbose = execFileSync3(command, ["-tvf", archivePath], { encoding: "utf8" });
25853
25953
  for (const line of verbose.split(`
25854
25954
  `)) {
25855
25955
  if (line.startsWith("h")) {
@@ -25862,7 +25962,7 @@ function precheckWithTar(archivePath, command) {
25862
25962
  totalBytes += Math.max(...numeric);
25863
25963
  }
25864
25964
  }
25865
- const names = execFileSync2(command, ["-tf", archivePath], { encoding: "utf8" });
25965
+ const names = execFileSync3(command, ["-tf", archivePath], { encoding: "utf8" });
25866
25966
  for (const entry of names.split(`
25867
25967
  `)) {
25868
25968
  if (entry.length > 0)
@@ -25873,19 +25973,18 @@ function precheckWithTar(archivePath, command) {
25873
25973
  function precheckArchiveContents(archivePath, archiveType, zipListingMode = "platform") {
25874
25974
  let totalBytes = 0;
25875
25975
  if (archiveType === "zip" && zipListingMode === "platform" && process.platform !== "win32") {
25876
- const out = execFileSync2("unzip", ["-l", archivePath], { encoding: "utf8" });
25976
+ const out = execFileSync3("unzip", ["-l", archivePath], { encoding: "utf8" });
25877
25977
  const match = out.match(/^\s*(\d+)\s+\d+\s+files?\s*$/m);
25878
25978
  if (match)
25879
25979
  totalBytes = Number.parseInt(match[1] ?? "0", 10);
25880
- const names = execFileSync2("unzip", ["-Z1", archivePath], { encoding: "utf8" });
25980
+ const names = execFileSync3("unzip", ["-Z1", archivePath], { encoding: "utf8" });
25881
25981
  for (const entry of names.split(`
25882
25982
  `)) {
25883
25983
  if (entry.length > 0)
25884
25984
  assertArchiveEntryPath(entry);
25885
25985
  }
25886
25986
  } else {
25887
- const command = process.platform === "win32" ? "tar.exe" : "tar";
25888
- totalBytes = precheckWithTar(archivePath, command);
25987
+ totalBytes = precheckWithTar(archivePath, windowsTarExecutable());
25889
25988
  }
25890
25989
  if (totalBytes > MAX_EXTRACT_BYTES2) {
25891
25990
  throw new Error(`archive uncompressed size ${totalBytes} exceeds ${MAX_EXTRACT_BYTES2}`);
@@ -25905,7 +26004,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
25905
26004
  try {
25906
26005
  rmSync6(destDir, { recursive: true, force: true });
25907
26006
  } catch {}
25908
- renameSync8(stagingDir, destDir);
26007
+ renameSync9(stagingDir, destDir);
25909
26008
  } catch (err) {
25910
26009
  try {
25911
26010
  rmSync6(stagingDir, { recursive: true, force: true });
@@ -25915,12 +26014,12 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
25915
26014
  }
25916
26015
  function quarantineCachedGithubInstall(spec, reason) {
25917
26016
  const packageDir = ghPackageDir(spec);
25918
- const dest = join16(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
26017
+ const dest = join17(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
25919
26018
  warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
25920
26019
  try {
25921
26020
  mkdirSync8(dirname6(dest), { recursive: true });
25922
26021
  rmSync6(dest, { recursive: true, force: true });
25923
- renameSync8(packageDir, dest);
26022
+ renameSync9(packageDir, dest);
25924
26023
  } catch (err) {
25925
26024
  warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
25926
26025
  }
@@ -25928,7 +26027,7 @@ function quarantineCachedGithubInstall(spec, reason) {
25928
26027
  function validateCachedGithubInstall(spec, platform) {
25929
26028
  const packageDir = ghPackageDir(spec);
25930
26029
  const meta = readGithubInstalledMetaIn(packageDir);
25931
- const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join16(ghBinDir(spec), candidate)).find((candidate) => {
26030
+ const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join17(ghBinDir(spec), candidate)).find((candidate) => {
25932
26031
  try {
25933
26032
  return statSync9(candidate).isFile();
25934
26033
  } catch {
@@ -25964,30 +26063,21 @@ function validateCachedGithubInstall(spec, platform) {
25964
26063
  function runPlatformExtractor(archivePath, destDir, archiveType) {
25965
26064
  if (archiveType === "zip") {
25966
26065
  if (process.platform === "win32") {
25967
- execFileSync2("tar.exe", ["-xf", archivePath, "-C", destDir], {
25968
- stdio: "pipe",
25969
- timeout: 180000
25970
- });
26066
+ execTarExtractionSync(["-xf", archivePath, "-C", destDir], 180000);
25971
26067
  return;
25972
26068
  }
25973
- execFileSync2("unzip", ["-q", "-o", archivePath, "-d", destDir], {
26069
+ execFileSync3("unzip", ["-q", "-o", archivePath, "-d", destDir], {
25974
26070
  stdio: "pipe",
25975
26071
  timeout: 180000
25976
26072
  });
25977
26073
  return;
25978
26074
  }
25979
26075
  if (archiveType === "tar.gz") {
25980
- execFileSync2("tar", ["-xzf", archivePath, "-C", destDir], {
25981
- stdio: "pipe",
25982
- timeout: 180000
25983
- });
26076
+ execTarExtractionSync(["-xzf", archivePath, "-C", destDir], 180000);
25984
26077
  return;
25985
26078
  }
25986
26079
  if (archiveType === "tar.xz") {
25987
- execFileSync2("tar", ["-xf", archivePath, "-C", destDir], {
25988
- stdio: "pipe",
25989
- timeout: 180000
25990
- });
26080
+ execTarExtractionSync(["-xf", archivePath, "-C", destDir], 180000);
25991
26081
  return;
25992
26082
  }
25993
26083
  throw new Error(`unsupported archive type: ${archiveType}`);
@@ -26008,7 +26098,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
26008
26098
  }
26009
26099
  const pkgDir = ghPackageDir(spec);
26010
26100
  const extractDir = ghExtractDir(spec);
26011
- const archivePath = join16(pkgDir, expected.name);
26101
+ const archivePath = join17(pkgDir, expected.name);
26012
26102
  log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
26013
26103
  try {
26014
26104
  await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
@@ -26050,8 +26140,8 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
26050
26140
  unlinkSync7(archivePath);
26051
26141
  } catch {}
26052
26142
  }
26053
- const innerBinaryPath = join16(extractDir, spec.binaryPathInArchive(platform, arch, version));
26054
- if (!existsSync14(innerBinaryPath)) {
26143
+ const innerBinaryPath = join17(extractDir, spec.binaryPathInArchive(platform, arch, version));
26144
+ if (!existsSync15(innerBinaryPath)) {
26055
26145
  const message = `extracted binary not found at ${innerBinaryPath}`;
26056
26146
  error2(`[lsp] ${spec.id}: ${message}`);
26057
26147
  return { ok: false, sha256: archiveSha256, error: message };
@@ -26156,7 +26246,7 @@ function runGithubAutoInstall(relevantServers, config, fetchImpl = fetch) {
26156
26246
  if (!host) {
26157
26247
  for (const spec of GITHUB_LSP_TABLE) {
26158
26248
  try {
26159
- if (existsSync14(ghBinDir(spec))) {
26249
+ if (existsSync15(ghBinDir(spec))) {
26160
26250
  cachedBinDirs.push(ghBinDir(spec));
26161
26251
  }
26162
26252
  } catch {}
@@ -27022,9 +27112,11 @@ var EditParams = Type2.Object({
27022
27112
  path: Type2.String({
27023
27113
  description: "Path to the file to edit (absolute or relative to project root)"
27024
27114
  }),
27025
- symbol: Type2.Optional(Type2.String({ description: "Named symbol to replace (function, class, type)" })),
27115
+ symbol: Type2.Optional(Type2.String({
27116
+ description: "Named symbol to replace; only meaningful together with `content`. A call carrying one without the other is incomplete."
27117
+ })),
27026
27118
  content: Type2.Optional(Type2.String({
27027
- description: "Replacement content for symbol mode. For whole-file writes, use the `write` tool."
27119
+ description: "Replacement content for symbol mode; only meaningful together with `symbol`. A call carrying one without the other is incomplete. For whole-file writes, use the `write` tool."
27028
27120
  })),
27029
27121
  appendContent: Type2.Optional(Type2.String({
27030
27122
  description: "Append text to the end of the file (creates the file if missing, parent dirs auto-created). When set, other edit modes are ignored."
@@ -27293,7 +27385,7 @@ PDFs aren't supported on the Pi harness yet.`, response);
27293
27385
  pi.registerTool(withPathAliasPreparation({
27294
27386
  name: editName,
27295
27387
  label: editName,
27296
- description: "Edit part of a file via `appendContent`, batch `edits[]`, or symbol plus `content`. Batch `{ oldString, newString, replaceAll: true }` replaces every match. Provide exactly one mode per call: appendContent, edits[], or symbol plus content (mixing modes is rejected)." + (resolveGithubConfig(ctx.config).write ? ' GitHub conversation comments can be edited with `edit("issue://N/comments/K", edits=[{oldString, newString}])` or the equivalent `pr://` path.' : ""),
27388
+ description: "Edit part of a file via `appendContent`, batch `edits[]`, or symbol plus `content`. `symbol` and `content` are only meaningful together; a call carrying one without the other is incomplete. Batch `{ oldString, newString, replaceAll: true }` replaces every match. Provide exactly one mode per call: appendContent, edits[], or symbol plus content (mixing modes is rejected)." + (resolveGithubConfig(ctx.config).write ? ' GitHub conversation comments can be edited with `edit("issue://N/comments/K", edits=[{oldString, newString}])` or the equivalent `pr://` path.' : ""),
27297
27389
  promptSnippet: "Partial file edits via appendContent, edits[], or symbol plus content (exactly one mode per call).",
27298
27390
  promptGuidelines: [
27299
27391
  `Prefer ${editName} over ${writeName} when changing part of an existing file.`,
@@ -29068,7 +29160,7 @@ var InspectParams = Type8.Object({
29068
29160
  description: "Categories to include in detailed drill-down (e.g. 'todos' or ['todos', 'dead_code', 'cycles']). Use 'all' for every active category. Omit for summary-only mode. `sections` changes detail, not the categories verified."
29069
29161
  })),
29070
29162
  scope: Type8.Optional(Type8.Union([Type8.String(), Type8.Array(Type8.String())], {
29071
- description: "Restrict returned results to paths under this scope (file or directory, absolute or relative to project root). `scope=` narrows results and limits Rust LSP startup to owning Cargo workspaces; it does not trigger per-file diagnostic collection. Scoped files no producer has authoritatively analyzed are reported as named gaps (complete: false), never as a clean empty result."
29163
+ description: "Restrict returned results to paths under this scope (one path, or an array of paths — not a space-separated list; file or directory; absolute or relative to project root). `scope=` narrows results and limits Rust LSP startup to owning Cargo workspaces; it does not trigger per-file diagnostic collection. Scoped files no producer has authoritatively analyzed are reported as named gaps (complete: false), never as a clean empty result."
29072
29164
  })),
29073
29165
  topK: Type8.Optional(Type8.Integer({
29074
29166
  minimum: 1,
@@ -29911,11 +30003,11 @@ var SafetyParams = Type11.Object({
29911
30003
  description: "Safety operation"
29912
30004
  }),
29913
30005
  path: Type11.Optional(Type11.String({
29914
- description: "File path (required for history, optional for undo). Absolute or relative to project root."
30006
+ description: "File path (required for history, optional for undo, optional for restore — restores only that file). Absolute or relative to project root."
29915
30007
  })),
29916
30008
  name: Type11.Optional(Type11.String({ description: "Checkpoint name (required for checkpoint, restore)" })),
29917
30009
  files: Type11.Optional(Type11.Array(Type11.String(), {
29918
- description: "Specific files for checkpoint (optional, defaults to all backup-tracked files; explicit files may be untracked or gitignored)"
30010
+ description: "Specific files for checkpoint, or to restore from a checkpoint (optional; restore without path/files restores the whole checkpoint; explicit checkpoint files may be untracked or gitignored)"
29919
30011
  }))
29920
30012
  });
29921
30013
  function buildSafetySections(args, payload, theme) {
@@ -30014,7 +30106,7 @@ function registerSafetyTool(pi, ctx) {
30014
30106
  pi.registerTool(withPathAliasPreparation({
30015
30107
  name: "aft_safety",
30016
30108
  label: "safety",
30017
- description: "File safety and recovery operations. Ops: `undo` (omit path to undo the entire last tool call; pass path to pop latest snapshot for one file — irreversible), `history` (list snapshots for a file), `checkpoint` (save named snapshot), `restore` (restore named checkpoint), `list` (list checkpoints). Per-file undo stack is capped at 20.",
30109
+ description: "File safety and recovery operations. Ops: `undo` (omit path to undo the entire last tool call; pass path to pop latest snapshot for one file — irreversible), `history` (list snapshots for a file), `checkpoint` (save named snapshot), `restore` (restore named checkpoint; optional path/files scopes it), `list` (list checkpoints). Per-file undo stack is capped at 20.",
30018
30110
  parameters: SafetyParams,
30019
30111
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
30020
30112
  if (params.op === "history" && !params.path) {
@@ -30144,9 +30236,9 @@ var SearchParams2 = Type12.Object({
30144
30236
  }),
30145
30237
  topK: Type12.Optional(Type12.Integer({
30146
30238
  minimum: 1,
30147
- maximum: 100,
30239
+ maximum: 50,
30148
30240
  default: 10,
30149
- description: "Maximum number of results (default: 10, max: 100)"
30241
+ description: "Maximum number of results (default: 10, max: 50)"
30150
30242
  })),
30151
30243
  offset: Type12.Optional(Type12.Integer({
30152
30244
  minimum: 0,
@@ -30274,19 +30366,20 @@ function registerSemanticTool(pi, ctx) {
30274
30366
  }
30275
30367
  const bridge = bridgeFor(ctx, extCtx.cwd);
30276
30368
  const req = { query: params.query };
30369
+ const includeTests = !isEmptyParam(params.includeTests) ? coerceBoolean(params.includeTests) : undefined;
30277
30370
  if (params.topK !== undefined)
30278
30371
  req.topK = params.topK;
30279
30372
  if (params.offset !== undefined)
30280
30373
  req.offset = params.offset;
30281
- if (params.includeTests !== undefined)
30282
- req.includeTests = params.includeTests;
30374
+ if (includeTests !== undefined)
30375
+ req.includeTests = includeTests;
30283
30376
  if (params.path !== undefined)
30284
30377
  req.path = params.path;
30285
30378
  const response = await callToolCall(bridge, "search", req, extCtx, signal ? { abortSignal: signal } : undefined);
30286
30379
  if (response.success === false) {
30287
30380
  throw new Error(response.text || response.message || "search failed");
30288
30381
  }
30289
- const text = surfaceSearchText(response, continuity, resolveSessionId(extCtx) ?? "unknown-session", continuityKey(selectedProjectRoot(extCtx.cwd, params.path), params.query, params.includeTests, params.topK));
30382
+ const text = surfaceSearchText(response, continuity, resolveSessionId(extCtx) ?? "unknown-session", continuityKey(selectedProjectRoot(extCtx.cwd, params.path), params.query, includeTests, params.topK));
30290
30383
  return textResult(text, text === response.text ? response : { ...response, text });
30291
30384
  },
30292
30385
  renderCall(args, theme, context) {
@@ -30625,11 +30718,11 @@ var PLUGIN_VERSION = (() => {
30625
30718
  return "0.0.0";
30626
30719
  }
30627
30720
  })();
30628
- var ANNOUNCEMENT_VERSION = "0.56.0";
30721
+ var ANNOUNCEMENT_VERSION = "0.57.0";
30629
30722
  var ANNOUNCEMENT_FEATURES = [
30630
- "Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
30631
- "aft_zoom handles real-world .jsonc: files with comment banners above the opening brace now resolve, and not-found errors point at the segment that actually failed (thanks @iceteaSA).",
30632
- "Disk hygiene: stale per-checkout inspect caches from old worktrees are now swept automatically — one machine reclaimed 21 GB."
30723
+ "OpenCode 2 is supported: tools, permission prompts, the sidebar and cancellation all work on the GA host, and an end-to-end matrix guards them.",
30724
+ "`doctor` configures a machine that has only OpenCode 2 installed, and `--fix` no longer skips unrelated repairs when it cannot decide the generation.",
30725
+ "A code-health scan no longer starts while the same project is still building its call graph, which cost about 90 MB of peak memory on large repositories."
30633
30726
  ];
30634
30727
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
30635
30728
  var pendingEagerWarnings = new Map;