@cortexkit/aft-pi 0.17.0 → 0.17.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
@@ -14174,7 +14174,6 @@ import { createReadStream, statSync as statSync2 } from "node:fs";
14174
14174
  // src/lsp-cache.ts
14175
14175
  import {
14176
14176
  closeSync,
14177
- existsSync as existsSync2,
14178
14177
  mkdirSync,
14179
14178
  openSync,
14180
14179
  readFileSync as readFileSync2,
@@ -14327,11 +14326,34 @@ function isProcessAlive(pid) {
14327
14326
  function releaseInstallLock(lockKey) {
14328
14327
  const lock = lockPath(lockKey);
14329
14328
  try {
14330
- if (existsSync2(lock)) {
14329
+ let owningPid = null;
14330
+ try {
14331
+ const raw = readFileSync2(lock, "utf8");
14332
+ const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
14333
+ const parsed = Number.parseInt(firstLine, 10);
14334
+ if (Number.isFinite(parsed) && parsed > 0)
14335
+ owningPid = parsed;
14336
+ } catch (readErr) {
14337
+ const code = readErr.code;
14338
+ if (code === "ENOENT")
14339
+ return;
14340
+ warn(`[lsp] could not read install lock for ${lockKey} during release: ${readErr}`);
14341
+ return;
14342
+ }
14343
+ if (owningPid !== process.pid) {
14344
+ log(`[lsp] not releasing install lock for ${lockKey}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
14345
+ return;
14346
+ }
14347
+ try {
14331
14348
  unlinkSync(lock);
14349
+ } catch (unlinkErr) {
14350
+ const code = unlinkErr.code;
14351
+ if (code !== "ENOENT") {
14352
+ warn(`[lsp] failed to release install lock for ${lockKey}: ${unlinkErr}`);
14353
+ }
14332
14354
  }
14333
14355
  } catch (err) {
14334
- warn(`[lsp] failed to release install lock for ${lockKey}: ${err}`);
14356
+ warn(`[lsp] unexpected error releasing install lock for ${lockKey}: ${err}`);
14335
14357
  }
14336
14358
  }
14337
14359
  async function withInstallLock(lockKey, task) {
@@ -14433,6 +14455,9 @@ function assertSafeVersion(version2) {
14433
14455
  throw new Error(`unsafe version/tag string ${JSON.stringify(version2)}: must match ${SAFE_VERSION_RE.source}`);
14434
14456
  }
14435
14457
  }
14458
+ function isSafeVersion(version2) {
14459
+ return typeof version2 === "string" && version2.length > 0 && SAFE_VERSION_RE.test(version2);
14460
+ }
14436
14461
  function stripTagV(tag) {
14437
14462
  assertSafeVersion(tag);
14438
14463
  return tag.startsWith("v") ? tag.slice(1) : tag;
@@ -14507,7 +14532,7 @@ var NPM_LSP_TABLE = [
14507
14532
  ];
14508
14533
 
14509
14534
  // src/lsp-project-relevance.ts
14510
- import { existsSync as existsSync3, readdirSync } from "node:fs";
14535
+ import { existsSync as existsSync2, readdirSync } from "node:fs";
14511
14536
  import { join as join4 } from "node:path";
14512
14537
  var MAX_WALK_DIRS = 200;
14513
14538
  var MAX_WALK_DEPTH = 4;
@@ -14525,7 +14550,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
14525
14550
  if (!rootMarkers)
14526
14551
  return false;
14527
14552
  for (const marker of rootMarkers) {
14528
- if (existsSync3(join4(projectRoot, marker)))
14553
+ if (existsSync2(join4(projectRoot, marker)))
14529
14554
  return true;
14530
14555
  }
14531
14556
  return false;
@@ -14659,13 +14684,14 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
14659
14684
  }
14660
14685
  const cached2 = readVersionCheck(spec.npm);
14661
14686
  const weeklyMs = config2.graceDays * 24 * 60 * 60 * 1000;
14662
- if (!shouldRecheckVersion(cached2, weeklyMs) && cached2?.latest_eligible) {
14687
+ const cachedSafe = isSafeVersion(cached2?.latest_eligible ?? null);
14688
+ if (cached2 && !shouldRecheckVersion(cached2, weeklyMs) && cachedSafe) {
14663
14689
  return { version: cached2.latest_eligible, pinned: false, probe: null };
14664
14690
  }
14665
14691
  const probe = await probeRegistry(spec.npm, config2.graceDays, fetchImpl);
14666
14692
  if (!probe) {
14667
14693
  return {
14668
- version: cached2?.latest_eligible ?? null,
14694
+ version: cachedSafe ? cached2?.latest_eligible ?? null : null,
14669
14695
  pinned: false,
14670
14696
  probe: null
14671
14697
  };
@@ -14886,7 +14912,7 @@ import {
14886
14912
  copyFileSync,
14887
14913
  createReadStream as createReadStream2,
14888
14914
  createWriteStream,
14889
- existsSync as existsSync4,
14915
+ existsSync as existsSync3,
14890
14916
  lstatSync,
14891
14917
  mkdirSync as mkdirSync2,
14892
14918
  readdirSync as readdirSync2,
@@ -15111,8 +15137,10 @@ async function resolveTargetTag(spec, config2, fetchImpl, signal) {
15111
15137
  }
15112
15138
  const cached2 = readVersionCheck(spec.githubRepo);
15113
15139
  const weeklyMs = config2.graceDays * 24 * 60 * 60 * 1000;
15114
- if (!shouldRecheckVersion(cached2, weeklyMs) && cached2?.latest_eligible) {
15115
- const release = await fetchReleaseByTag(spec.githubRepo, cached2.latest_eligible, fetchImpl);
15140
+ const cachedTag = cached2?.latest_eligible ?? null;
15141
+ const cachedSafe = isSafeVersion(cachedTag);
15142
+ if (cached2 && !shouldRecheckVersion(cached2, weeklyMs) && cachedSafe) {
15143
+ const release = await fetchReleaseByTag(spec.githubRepo, cachedTag, fetchImpl);
15116
15144
  if (release) {
15117
15145
  return {
15118
15146
  tag: release.tag,
@@ -15149,7 +15177,31 @@ function controlledTimeoutSignal(timeoutMs, parent) {
15149
15177
  }
15150
15178
  };
15151
15179
  }
15180
+ var ALLOWED_DOWNLOAD_HOSTS = new Set([
15181
+ "github.com",
15182
+ "api.github.com",
15183
+ "objects.githubusercontent.com",
15184
+ "release-assets.githubusercontent.com",
15185
+ "raw.githubusercontent.com",
15186
+ "codeload.github.com"
15187
+ ]);
15188
+ function assertAllowedDownloadUrl(rawUrl) {
15189
+ let parsed;
15190
+ try {
15191
+ parsed = new URL(rawUrl);
15192
+ } catch {
15193
+ throw new Error(`download url is not a valid URL: ${rawUrl}`);
15194
+ }
15195
+ if (parsed.protocol !== "https:") {
15196
+ throw new Error(`download url must be https (got ${parsed.protocol}): ${rawUrl}`);
15197
+ }
15198
+ if (!ALLOWED_DOWNLOAD_HOSTS.has(parsed.hostname.toLowerCase())) {
15199
+ throw new Error(`download url host ${parsed.hostname} is not in the GitHub allowlist: ${rawUrl}`);
15200
+ }
15201
+ return parsed;
15202
+ }
15152
15203
  async function downloadFile(url2, destPath, fetchImpl, assetSize, signal) {
15204
+ assertAllowedDownloadUrl(url2);
15153
15205
  if (assetSize !== undefined && assetSize > MAX_DOWNLOAD_BYTES) {
15154
15206
  throw new Error(`asset size ${assetSize} exceeds max ${MAX_DOWNLOAD_BYTES} (set lsp.versions to pin a smaller release if this is wrong)`);
15155
15207
  }
@@ -15346,7 +15398,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
15346
15398
  } catch {}
15347
15399
  }
15348
15400
  const innerBinaryPath = join5(extractDir, spec.binaryPathInArchive(platform, arch, version2));
15349
- if (!existsSync4(innerBinaryPath)) {
15401
+ if (!existsSync3(innerBinaryPath)) {
15350
15402
  error48(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
15351
15403
  return null;
15352
15404
  }
@@ -15427,7 +15479,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
15427
15479
  if (!host) {
15428
15480
  for (const spec of GITHUB_LSP_TABLE) {
15429
15481
  try {
15430
- if (existsSync4(ghBinDir(spec))) {
15482
+ if (existsSync3(ghBinDir(spec))) {
15431
15483
  cachedBinDirs.push(ghBinDir(spec));
15432
15484
  }
15433
15485
  } catch {}
@@ -15522,7 +15574,7 @@ function discoverRelevantGithubServers(projectRoot) {
15522
15574
  }
15523
15575
 
15524
15576
  // src/notifications.ts
15525
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
15577
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
15526
15578
  import { join as join6 } from "node:path";
15527
15579
  var WARNING_MARKER = "\uD83D\uDD27 AFT: ⚠️";
15528
15580
  var WARNED_TOOLS_FILE = "warned_tools.json";
@@ -15541,7 +15593,7 @@ function sendIgnoredMessage(client, _sessionId, text) {
15541
15593
  function readWarnedTools(storageDir) {
15542
15594
  try {
15543
15595
  const warnedToolsPath = join6(storageDir, WARNED_TOOLS_FILE);
15544
- if (!existsSync5(warnedToolsPath))
15596
+ if (!existsSync4(warnedToolsPath))
15545
15597
  return {};
15546
15598
  const parsed = JSON.parse(readFileSync3(warnedToolsPath, "utf-8"));
15547
15599
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
@@ -15620,10 +15672,37 @@ async function deliverConfigureWarnings(opts, warnings) {
15620
15672
  }
15621
15673
 
15622
15674
  // src/onnx-runtime.ts
15623
- import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync4, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "node:fs";
15624
- import { join as join7 } from "node:path";
15675
+ import { execFileSync as execFileSync2 } from "node:child_process";
15676
+ import { createHash as createHash3 } from "node:crypto";
15677
+ import {
15678
+ chmodSync,
15679
+ closeSync as closeSync2,
15680
+ copyFileSync as copyFileSync2,
15681
+ createWriteStream as createWriteStream2,
15682
+ existsSync as existsSync5,
15683
+ lstatSync as lstatSync2,
15684
+ mkdirSync as mkdirSync4,
15685
+ openSync as openSync2,
15686
+ readdirSync as readdirSync3,
15687
+ readFileSync as readFileSync4,
15688
+ readlinkSync as readlinkSync2,
15689
+ realpathSync as realpathSync2,
15690
+ rmSync as rmSync2,
15691
+ statSync as statSync4,
15692
+ symlinkSync,
15693
+ unlinkSync as unlinkSync3,
15694
+ writeFileSync as writeFileSync3
15695
+ } from "node:fs";
15696
+ import { dirname as dirname2, join as join7, relative as relative2, resolve as resolve2 } from "node:path";
15697
+ import { Readable as Readable2 } from "node:stream";
15698
+ import { pipeline as pipeline2 } from "node:stream/promises";
15625
15699
  var ORT_VERSION = "1.24.4";
15626
15700
  var ORT_REPO = "microsoft/onnxruntime";
15701
+ var MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
15702
+ var MAX_EXTRACT_BYTES2 = 1 * 1024 * 1024 * 1024;
15703
+ var ONNX_LOCK_FILE = ".aft-onnx-installing";
15704
+ var ONNX_INSTALLED_META_FILE = ".aft-onnx-installed";
15705
+ var STALE_LOCK_MS2 = 30 * 60 * 1000;
15627
15706
  var ORT_PLATFORM_MAP = {
15628
15707
  darwin: {
15629
15708
  arm64: {
@@ -15676,9 +15755,25 @@ async function ensureOnnxRuntime(storageDir) {
15676
15755
  const info = getPlatformInfo();
15677
15756
  const ortDir = join7(storageDir, "onnxruntime", ORT_VERSION);
15678
15757
  const libPath = join7(ortDir, info?.libName ?? "libonnxruntime.dylib");
15679
- if (existsSync6(libPath)) {
15680
- log(`ONNX Runtime found at ${ortDir}`);
15681
- return ortDir;
15758
+ if (existsSync5(libPath)) {
15759
+ const meta3 = readOnnxInstalledMeta(ortDir);
15760
+ if (meta3?.sha256) {
15761
+ try {
15762
+ const currentHash = sha256File(libPath);
15763
+ if (currentHash !== meta3.sha256) {
15764
+ error48(`ONNX Runtime at ${ortDir}: TOFU sha256 mismatch — refusing to use ` + `tampered binary. Recorded ${meta3.sha256}, current ${currentHash}. ` + `Run \`aft doctor --clear\` to re-download from scratch.`);
15765
+ } else {
15766
+ log(`ONNX Runtime found at ${ortDir} (TOFU verified)`);
15767
+ return ortDir;
15768
+ }
15769
+ } catch (err) {
15770
+ warn(`Could not verify ONNX Runtime hash at ${ortDir}: ${err}`);
15771
+ return ortDir;
15772
+ }
15773
+ } else {
15774
+ log(`ONNX Runtime found at ${ortDir} (no recorded hash, accepting)`);
15775
+ return ortDir;
15776
+ }
15682
15777
  }
15683
15778
  const systemPath = findSystemOnnxRuntime(info?.libName);
15684
15779
  if (systemPath) {
@@ -15689,7 +15784,18 @@ async function ensureOnnxRuntime(storageDir) {
15689
15784
  warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
15690
15785
  return null;
15691
15786
  }
15692
- return downloadOnnxRuntime(info, ortDir);
15787
+ const onnxBaseDir = join7(storageDir, "onnxruntime");
15788
+ mkdirSync4(onnxBaseDir, { recursive: true });
15789
+ const lockPath2 = join7(onnxBaseDir, ONNX_LOCK_FILE);
15790
+ if (!acquireLock(lockPath2)) {
15791
+ warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath2}). Skipping.`);
15792
+ return null;
15793
+ }
15794
+ try {
15795
+ return await downloadOnnxRuntime(info, ortDir);
15796
+ } finally {
15797
+ releaseLock(lockPath2);
15798
+ }
15693
15799
  }
15694
15800
  function findSystemOnnxRuntime(libName) {
15695
15801
  if (!libName)
@@ -15701,36 +15807,115 @@ function findSystemOnnxRuntime(libName) {
15701
15807
  searchPaths.push("/usr/lib", "/usr/lib/x86_64-linux-gnu", "/usr/lib/aarch64-linux-gnu", "/usr/local/lib");
15702
15808
  }
15703
15809
  for (const dir of searchPaths) {
15704
- if (existsSync6(join7(dir, libName))) {
15810
+ if (existsSync5(join7(dir, libName))) {
15705
15811
  return dir;
15706
15812
  }
15707
15813
  }
15708
15814
  return null;
15709
15815
  }
15816
+ async function downloadFileWithCap(url2, destPath) {
15817
+ const controller = new AbortController;
15818
+ const timeout = setTimeout(() => controller.abort(), 300000);
15819
+ try {
15820
+ const res = await fetch(url2, {
15821
+ headers: { accept: "application/octet-stream" },
15822
+ redirect: "follow",
15823
+ signal: controller.signal
15824
+ });
15825
+ if (!res.ok || !res.body) {
15826
+ throw new Error(`download failed (HTTP ${res.status})`);
15827
+ }
15828
+ const advertised = Number.parseInt(res.headers.get("content-length") ?? "", 10);
15829
+ if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
15830
+ throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
15831
+ }
15832
+ mkdirSync4(dirname2(destPath), { recursive: true });
15833
+ let bytesWritten = 0;
15834
+ const guard = new TransformStream({
15835
+ transform(chunk, transformController) {
15836
+ bytesWritten += chunk.byteLength;
15837
+ if (bytesWritten > MAX_DOWNLOAD_BYTES2) {
15838
+ transformController.error(new Error(`download exceeded ${MAX_DOWNLOAD_BYTES2} bytes after streaming (server lied about size or sent unbounded body)`));
15839
+ return;
15840
+ }
15841
+ transformController.enqueue(chunk);
15842
+ }
15843
+ });
15844
+ const guarded = res.body.pipeThrough(guard);
15845
+ const nodeStream = Readable2.fromWeb(guarded);
15846
+ await pipeline2(nodeStream, createWriteStream2(destPath), { signal: controller.signal });
15847
+ } catch (err) {
15848
+ try {
15849
+ unlinkSync3(destPath);
15850
+ } catch {}
15851
+ throw err;
15852
+ } finally {
15853
+ clearTimeout(timeout);
15854
+ }
15855
+ }
15856
+ function validateExtractedTree(stagingRoot) {
15857
+ const realRoot = realpathSync2(stagingRoot);
15858
+ let totalBytes = 0;
15859
+ const walk = (dir) => {
15860
+ const entries = readdirSync3(dir);
15861
+ for (const entry of entries) {
15862
+ const fullPath = join7(dir, entry);
15863
+ const lst = lstatSync2(fullPath);
15864
+ if (lst.isSymbolicLink()) {
15865
+ const linkTarget = readlinkSync2(fullPath);
15866
+ const resolvedTarget = resolve2(dirname2(fullPath), linkTarget);
15867
+ const rel2 = relative2(realRoot, resolvedTarget);
15868
+ if (rel2.startsWith("..") || process.platform !== "win32" && rel2.startsWith("/")) {
15869
+ throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
15870
+ }
15871
+ continue;
15872
+ }
15873
+ const rel = relative2(realRoot, fullPath);
15874
+ if (rel.startsWith("..") || process.platform !== "win32" && rel.startsWith("/")) {
15875
+ throw new Error(`extracted entry ${fullPath} escapes staging root`);
15876
+ }
15877
+ if (lst.isDirectory()) {
15878
+ walk(fullPath);
15879
+ continue;
15880
+ }
15881
+ if (lst.isFile()) {
15882
+ totalBytes += lst.size;
15883
+ if (totalBytes > MAX_EXTRACT_BYTES2) {
15884
+ throw new Error(`extracted size ${totalBytes} exceeds max ${MAX_EXTRACT_BYTES2} (decompression bomb defense)`);
15885
+ }
15886
+ }
15887
+ }
15888
+ };
15889
+ walk(realRoot);
15890
+ }
15710
15891
  async function downloadOnnxRuntime(info, targetDir) {
15711
15892
  const url2 = `https://github.com/${ORT_REPO}/releases/download/v${ORT_VERSION}/${info.assetName}.${info.archiveType === "tgz" ? "tgz" : "zip"}`;
15712
15893
  log(`Downloading ONNX Runtime v${ORT_VERSION} for ${process.platform}/${process.arch}...`);
15894
+ const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
15713
15895
  try {
15714
- const tmpDir = `${targetDir}.tmp.${process.pid}`;
15715
15896
  mkdirSync4(tmpDir, { recursive: true });
15716
15897
  const archivePath = join7(tmpDir, `onnxruntime.${info.archiveType}`);
15717
- const { execFileSync: execFileSync2 } = await import("node:child_process");
15718
- execFileSync2("curl", ["-fsSL", url2, "-o", archivePath], {
15719
- stdio: "pipe",
15720
- timeout: 120000
15721
- });
15898
+ await downloadFileWithCap(url2, archivePath);
15899
+ const archiveSha256 = sha256File(archivePath);
15900
+ log(`ONNX Runtime archive sha256=${archiveSha256}`);
15722
15901
  if (info.archiveType === "tgz") {
15723
- execFileSync2("tar", ["xzf", archivePath, "-C", tmpDir], { stdio: "pipe" });
15902
+ execFileSync2("tar", ["xzf", archivePath, "-C", tmpDir], {
15903
+ stdio: "pipe",
15904
+ timeout: 120000
15905
+ });
15724
15906
  } else {
15725
15907
  await extractZipArchive(archivePath, tmpDir);
15726
15908
  }
15909
+ try {
15910
+ unlinkSync3(archivePath);
15911
+ } catch {}
15912
+ validateExtractedTree(tmpDir);
15727
15913
  const extractedDir = join7(tmpDir, info.assetName, "lib");
15728
- if (!existsSync6(extractedDir)) {
15914
+ if (!existsSync5(extractedDir)) {
15729
15915
  throw new Error(`Expected directory not found: ${extractedDir}`);
15730
15916
  }
15731
15917
  mkdirSync4(targetDir, { recursive: true });
15732
15918
  const libFiles = readdirSync3(extractedDir).filter((f) => f.startsWith("libonnxruntime") || f.startsWith("onnxruntime"));
15733
- const { lstatSync: lstatSync2, symlinkSync, readlinkSync: readlinkSync2, copyFileSync: cpFile } = await import("node:fs");
15734
15919
  const realFiles = [];
15735
15920
  const symlinks = [];
15736
15921
  for (const libFile of libFiles) {
@@ -15752,7 +15937,7 @@ async function downloadOnnxRuntime(info, targetDir) {
15752
15937
  const src = join7(extractedDir, libFile);
15753
15938
  const dst = join7(targetDir, libFile);
15754
15939
  try {
15755
- cpFile(src, dst);
15940
+ copyFileSync2(src, dst);
15756
15941
  if (process.platform !== "win32") {
15757
15942
  chmodSync(dst, 493);
15758
15943
  }
@@ -15767,21 +15952,29 @@ async function downloadOnnxRuntime(info, targetDir) {
15767
15952
  } catch {}
15768
15953
  symlinkSync(link.target, dst);
15769
15954
  }
15770
- const { rmSync: rmSync2 } = await import("node:fs");
15955
+ const libPath = join7(targetDir, info.libName);
15956
+ let libHash = null;
15957
+ try {
15958
+ libHash = sha256File(libPath);
15959
+ } catch (err) {
15960
+ warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
15961
+ }
15962
+ writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
15771
15963
  rmSync2(tmpDir, { recursive: true, force: true });
15772
15964
  log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
15773
15965
  return targetDir;
15774
15966
  } catch (err) {
15775
15967
  error48(`Failed to download ONNX Runtime: ${err}`);
15776
15968
  try {
15777
- const { rmSync: rmSync2 } = await import("node:fs");
15778
- rmSync2(`${targetDir}.tmp.${process.pid}`, { recursive: true, force: true });
15969
+ rmSync2(tmpDir, { recursive: true, force: true });
15970
+ } catch {}
15971
+ try {
15972
+ rmSync2(targetDir, { recursive: true, force: true });
15779
15973
  } catch {}
15780
15974
  return null;
15781
15975
  }
15782
15976
  }
15783
15977
  async function extractZipArchive(archivePath, destinationDir) {
15784
- const { execFileSync: execFileSync2 } = await import("node:child_process");
15785
15978
  if (process.platform === "win32") {
15786
15979
  execFileSync2("tar.exe", ["-xf", archivePath, "-C", destinationDir], {
15787
15980
  stdio: "pipe",
@@ -15794,9 +15987,136 @@ async function extractZipArchive(archivePath, destinationDir) {
15794
15987
  timeout: 120000
15795
15988
  });
15796
15989
  }
15990
+ function writeOnnxInstalledMeta(installDir, version2, sha256, archiveSha256) {
15991
+ try {
15992
+ const meta3 = {
15993
+ version: version2,
15994
+ installedAt: new Date().toISOString(),
15995
+ ...sha256 ? { sha256 } : {},
15996
+ archiveSha256
15997
+ };
15998
+ writeFileSync3(join7(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
15999
+ } catch (err) {
16000
+ log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
16001
+ }
16002
+ }
16003
+ function readOnnxInstalledMeta(installDir) {
16004
+ const path2 = join7(installDir, ONNX_INSTALLED_META_FILE);
16005
+ try {
16006
+ if (!statSync4(path2).isFile())
16007
+ return null;
16008
+ const raw = readFileSync4(path2, "utf8");
16009
+ const parsed = JSON.parse(raw);
16010
+ if (typeof parsed.version !== "string" || parsed.version.length === 0)
16011
+ return null;
16012
+ return {
16013
+ version: parsed.version,
16014
+ installedAt: typeof parsed.installedAt === "string" ? parsed.installedAt : "",
16015
+ ...typeof parsed.sha256 === "string" && parsed.sha256.length > 0 ? { sha256: parsed.sha256 } : {},
16016
+ ...typeof parsed.archiveSha256 === "string" && parsed.archiveSha256.length > 0 ? { archiveSha256: parsed.archiveSha256 } : {}
16017
+ };
16018
+ } catch {
16019
+ return null;
16020
+ }
16021
+ }
16022
+ function sha256File(path2) {
16023
+ const hash2 = createHash3("sha256");
16024
+ hash2.update(readFileSync4(path2));
16025
+ return hash2.digest("hex");
16026
+ }
16027
+ function acquireLock(lockPath2) {
16028
+ const tryClaim = () => {
16029
+ try {
16030
+ const fd = openSync2(lockPath2, "wx");
16031
+ try {
16032
+ writeFileSync3(fd, `${process.pid}
16033
+ ${new Date().toISOString()}
16034
+ `);
16035
+ } finally {
16036
+ closeSync2(fd);
16037
+ }
16038
+ return true;
16039
+ } catch (err) {
16040
+ const code = err.code;
16041
+ if (code === "EEXIST")
16042
+ return false;
16043
+ warn(`[onnx] unexpected error acquiring lock ${lockPath2}: ${err}`);
16044
+ return false;
16045
+ }
16046
+ };
16047
+ if (tryClaim())
16048
+ return true;
16049
+ let owningPid = null;
16050
+ let lockMtimeMs = 0;
16051
+ try {
16052
+ const raw = readFileSync4(lockPath2, "utf8");
16053
+ const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
16054
+ const parsed = Number.parseInt(firstLine, 10);
16055
+ if (Number.isFinite(parsed) && parsed > 0)
16056
+ owningPid = parsed;
16057
+ lockMtimeMs = statSync4(lockPath2).mtimeMs;
16058
+ } catch {
16059
+ return tryClaim();
16060
+ }
16061
+ const age = Date.now() - lockMtimeMs;
16062
+ const ageWithinFresh = Math.abs(age) < STALE_LOCK_MS2;
16063
+ const skipLiveness = process.platform === "win32";
16064
+ const ownerAlive = !skipLiveness && owningPid !== null && isProcessAlive2(owningPid);
16065
+ if (skipLiveness ? ageWithinFresh : ownerAlive && ageWithinFresh) {
16066
+ return false;
16067
+ }
16068
+ log(`[onnx] reclaiming install lock (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
16069
+ try {
16070
+ unlinkSync3(lockPath2);
16071
+ } catch {}
16072
+ return tryClaim();
16073
+ }
16074
+ function releaseLock(lockPath2) {
16075
+ try {
16076
+ let owningPid = null;
16077
+ try {
16078
+ const raw = readFileSync4(lockPath2, "utf8");
16079
+ const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
16080
+ const parsed = Number.parseInt(firstLine, 10);
16081
+ if (Number.isFinite(parsed) && parsed > 0)
16082
+ owningPid = parsed;
16083
+ } catch (readErr) {
16084
+ const code = readErr.code;
16085
+ if (code === "ENOENT")
16086
+ return;
16087
+ warn(`[onnx] could not read lock ${lockPath2} during release: ${readErr}`);
16088
+ return;
16089
+ }
16090
+ if (owningPid !== process.pid) {
16091
+ log(`[onnx] not releasing lock ${lockPath2}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
16092
+ return;
16093
+ }
16094
+ try {
16095
+ unlinkSync3(lockPath2);
16096
+ } catch (unlinkErr) {
16097
+ const code = unlinkErr.code;
16098
+ if (code !== "ENOENT") {
16099
+ warn(`[onnx] failed to release lock ${lockPath2}: ${unlinkErr}`);
16100
+ }
16101
+ }
16102
+ } catch (err) {
16103
+ warn(`[onnx] unexpected error releasing lock ${lockPath2}: ${err}`);
16104
+ }
16105
+ }
16106
+ function isProcessAlive2(pid) {
16107
+ try {
16108
+ process.kill(pid, 0);
16109
+ return true;
16110
+ } catch (err) {
16111
+ const code = err.code;
16112
+ if (code === "ESRCH")
16113
+ return false;
16114
+ return true;
16115
+ }
16116
+ }
15797
16117
 
15798
16118
  // src/pool.ts
15799
- import { realpathSync as realpathSync2 } from "node:fs";
16119
+ import { realpathSync as realpathSync3 } from "node:fs";
15800
16120
 
15801
16121
  // src/bridge.ts
15802
16122
  import { spawn as spawn2 } from "node:child_process";
@@ -15943,14 +16263,14 @@ class BinaryBridge {
15943
16263
  const line = `${JSON.stringify(request)}
15944
16264
  `;
15945
16265
  const effectiveTimeoutMs = options?.timeoutMs ?? this.timeoutMs;
15946
- return new Promise((resolve2, reject) => {
16266
+ return new Promise((resolve3, reject) => {
15947
16267
  const timer = setTimeout(() => {
15948
16268
  this.pending.delete(id);
15949
16269
  warn(`Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms — restarting bridge`);
15950
16270
  reject(new Error(`[aft-pi] Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
15951
16271
  this.handleTimeout();
15952
16272
  }, effectiveTimeoutMs);
15953
- this.pending.set(id, { resolve: resolve2, reject, timer });
16273
+ this.pending.set(id, { resolve: resolve3, reject, timer });
15954
16274
  if (!this.process?.stdin?.writable) {
15955
16275
  this.pending.delete(id);
15956
16276
  clearTimeout(timer);
@@ -15993,15 +16313,15 @@ class BinaryBridge {
15993
16313
  if (this.process) {
15994
16314
  const proc = this.process;
15995
16315
  this.process = null;
15996
- return new Promise((resolve2) => {
16316
+ return new Promise((resolve3) => {
15997
16317
  const forceKillTimer = setTimeout(() => {
15998
16318
  proc.kill("SIGKILL");
15999
- resolve2();
16319
+ resolve3();
16000
16320
  }, 5000);
16001
16321
  proc.once("exit", () => {
16002
16322
  clearTimeout(forceKillTimer);
16003
16323
  log("Process exited during shutdown");
16004
- resolve2();
16324
+ resolve3();
16005
16325
  });
16006
16326
  proc.kill("SIGTERM");
16007
16327
  });
@@ -16313,7 +16633,7 @@ class BridgePool {
16313
16633
  function canonicalKey(directory) {
16314
16634
  const stripped = directory.replace(/[/\\]+$/, "");
16315
16635
  try {
16316
- return realpathSync2(stripped);
16636
+ return realpathSync3(stripped);
16317
16637
  } catch {
16318
16638
  return stripped;
16319
16639
  }
@@ -16321,13 +16641,13 @@ function canonicalKey(directory) {
16321
16641
 
16322
16642
  // src/resolver.ts
16323
16643
  import { execSync, spawnSync } from "node:child_process";
16324
- import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync6, renameSync as renameSync2 } from "node:fs";
16644
+ import { chmodSync as chmodSync3, copyFileSync as copyFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync6, renameSync as renameSync2 } from "node:fs";
16325
16645
  import { createRequire as createRequire2 } from "node:module";
16326
16646
  import { homedir as homedir5 } from "node:os";
16327
16647
  import { join as join10 } from "node:path";
16328
16648
 
16329
16649
  // src/downloader.ts
16330
- import { chmodSync as chmodSync2, existsSync as existsSync7, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "node:fs";
16650
+ import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "node:fs";
16331
16651
  import { homedir as homedir4 } from "node:os";
16332
16652
  import { join as join9 } from "node:path";
16333
16653
 
@@ -16363,7 +16683,7 @@ function getCachedBinaryPath(version2) {
16363
16683
  if (!version2)
16364
16684
  return null;
16365
16685
  const binaryPath = join9(getCacheDir(), version2, getBinaryName());
16366
- return existsSync7(binaryPath) ? binaryPath : null;
16686
+ return existsSync6(binaryPath) ? binaryPath : null;
16367
16687
  }
16368
16688
  async function downloadBinary(version2) {
16369
16689
  const platformKey = `${process.platform}-${process.arch}`;
@@ -16380,14 +16700,14 @@ async function downloadBinary(version2) {
16380
16700
  const versionedCacheDir = join9(getCacheDir(), tag);
16381
16701
  const binaryName = getBinaryName();
16382
16702
  const binaryPath = join9(versionedCacheDir, binaryName);
16383
- if (existsSync7(binaryPath)) {
16703
+ if (existsSync6(binaryPath)) {
16384
16704
  return binaryPath;
16385
16705
  }
16386
16706
  const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
16387
16707
  const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
16388
16708
  log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
16389
16709
  try {
16390
- if (!existsSync7(versionedCacheDir)) {
16710
+ if (!existsSync6(versionedCacheDir)) {
16391
16711
  mkdirSync5(versionedCacheDir, { recursive: true });
16392
16712
  }
16393
16713
  const [binaryResponse, checksumResponse] = await Promise.all([
@@ -16408,15 +16728,15 @@ async function downloadBinary(version2) {
16408
16728
  warn(`Checksum verification failed: checksums.sha256 found but no entry for ${assetName}. ` + "Binary download aborted for security reasons.");
16409
16729
  return null;
16410
16730
  }
16411
- const { createHash: createHash3 } = await import("node:crypto");
16412
- const actualHash = createHash3("sha256").update(Buffer.from(arrayBuffer)).digest("hex");
16731
+ const { createHash: createHash4 } = await import("node:crypto");
16732
+ const actualHash = createHash4("sha256").update(Buffer.from(arrayBuffer)).digest("hex");
16413
16733
  if (actualHash !== expectedHash) {
16414
16734
  throw new Error(`Checksum mismatch for ${assetName}: expected ${expectedHash}, got ${actualHash}. The binary may have been tampered with.`);
16415
16735
  }
16416
16736
  log(`Checksum verified (SHA-256: ${actualHash.slice(0, 16)}...)`);
16417
16737
  const tmpPath = `${binaryPath}.tmp`;
16418
- const { writeFileSync: writeFileSync3 } = await import("node:fs");
16419
- writeFileSync3(tmpPath, Buffer.from(arrayBuffer));
16738
+ const { writeFileSync: writeFileSync4 } = await import("node:fs");
16739
+ writeFileSync4(tmpPath, Buffer.from(arrayBuffer));
16420
16740
  if (process.platform !== "win32") {
16421
16741
  chmodSync2(tmpPath, 493);
16422
16742
  }
@@ -16428,7 +16748,7 @@ async function downloadBinary(version2) {
16428
16748
  const msg = err instanceof Error ? err.message : String(err);
16429
16749
  error48(`Failed to download AFT binary: ${msg}`);
16430
16750
  const tmpPath = `${binaryPath}.tmp`;
16431
- if (existsSync7(tmpPath)) {
16751
+ if (existsSync6(tmpPath)) {
16432
16752
  try {
16433
16753
  unlinkSync4(tmpPath);
16434
16754
  } catch {}
@@ -16498,11 +16818,11 @@ function copyToVersionedCache(npmBinaryPath) {
16498
16818
  const versionedDir = join10(cacheDir, tag);
16499
16819
  const ext = process.platform === "win32" ? ".exe" : "";
16500
16820
  const cachedPath = join10(versionedDir, `aft${ext}`);
16501
- if (existsSync8(cachedPath))
16821
+ if (existsSync7(cachedPath))
16502
16822
  return cachedPath;
16503
16823
  mkdirSync6(versionedDir, { recursive: true });
16504
16824
  const tmpPath = `${cachedPath}.tmp`;
16505
- copyFileSync2(npmBinaryPath, tmpPath);
16825
+ copyFileSync3(npmBinaryPath, tmpPath);
16506
16826
  if (process.platform !== "win32") {
16507
16827
  chmodSync3(tmpPath, 493);
16508
16828
  }
@@ -16545,7 +16865,7 @@ function findBinarySync() {
16545
16865
  const packageBin = `@cortexkit/aft-${key}/bin/aft${ext}`;
16546
16866
  const req = createRequire2(import.meta.url);
16547
16867
  const resolved = req.resolve(packageBin);
16548
- if (existsSync8(resolved)) {
16868
+ if (existsSync7(resolved)) {
16549
16869
  const copied = copyToVersionedCache(resolved);
16550
16870
  return copied ?? resolved;
16551
16871
  }
@@ -16560,7 +16880,7 @@ function findBinarySync() {
16560
16880
  return result;
16561
16881
  } catch {}
16562
16882
  const cargoPath = join10(homedir5(), ".cargo", "bin", `aft${ext}`);
16563
- if (existsSync8(cargoPath))
16883
+ if (existsSync7(cargoPath))
16564
16884
  return cargoPath;
16565
16885
  return null;
16566
16886
  }
@@ -17163,7 +17483,7 @@ function registerFsTools(pi, ctx, surface) {
17163
17483
  // src/tools/hoisted.ts
17164
17484
  import { stat } from "node:fs/promises";
17165
17485
  import { homedir as homedir7 } from "node:os";
17166
- import { resolve as resolve2 } from "node:path";
17486
+ import { resolve as resolve3 } from "node:path";
17167
17487
  import {
17168
17488
  renderDiff as renderDiff2
17169
17489
  } from "@mariozechner/pi-coding-agent";
@@ -17522,7 +17842,7 @@ function shortenPath2(path2) {
17522
17842
  return path2;
17523
17843
  }
17524
17844
  async function resolvePathArg(cwd, path2) {
17525
- const abs = resolve2(cwd, path2);
17845
+ const abs = resolve3(cwd, path2);
17526
17846
  try {
17527
17847
  await stat(abs);
17528
17848
  return abs;
@@ -17705,7 +18025,7 @@ function registerLspTools(pi, ctx) {
17705
18025
  pi.registerTool({
17706
18026
  name: "lsp_diagnostics",
17707
18027
  label: "lsp diagnostics",
17708
- description: "On-demand LSP file/scope check. Spawns the relevant language server (if registered for the extension), opens the document, prefers LSP 3.17 pull diagnostics where supported, falls back to push + waitMs otherwise. NOT a project-wide type checker — for full coverage run `tsc --noEmit`, `cargo check`, `pyright`, etc.\n\nResponse fields: `diagnostics`, `total`, `files_with_errors`, `complete` (true = trustable absence), `lsp_servers_used` (per-server status, e.g. `pull_ok`, `push_only`, `binary_not_installed: bash-language-server`, `no_root_marker (...)`), and (directory mode) `unchecked_files`.\n\nReading honestly: `total: 0` + empty `lsp_servers_used` means **nothing was checked** install the relevant LSP server. `total: 0` + `pull_ok` means the file is genuinely clean.\n\nProvide `filePath` for a single file, `directory` for files under a path (workspace pull from active servers + 200-file walk for unchecked listing), or omit both to dump cached diagnostics.",
18028
+ description: "On-demand LSP file/scope check. Spawns the relevant language server (if registered for the extension), opens the document, prefers LSP 3.17 pull diagnostics where supported, falls back to push + waitMs otherwise. NOT a project-wide type checker — for full coverage run `tsc --noEmit`, `cargo check`, `pyright`, etc.\n\nResponse fields: `diagnostics`, `total`, `files_with_errors`, `complete` (true = trustable absence), `lsp_servers_used` (per-server status, e.g. `pull_ok`, `push_only`, `binary_not_installed: <name>`, `no_root_marker (...)`), and (directory mode) `unchecked_files`.\n\nReading honestly:\n- `total: 0` + empty `lsp_servers_used` **nothing was checked** (no server registered for this extension). Tell the user, don't claim 'no errors'.\n- `total: 0` + `pull_ok` the file is genuinely clean.\n- `binary_not_installed: <name>` → server matched the extension but its binary isn't on PATH. Tell the user to install it.\n- `no_root_marker (...)` → server is registered but couldn't find a workspace root marker. The user's project layout doesn't match what the server expects.\n\nProvide `filePath` for a single file, `directory` for files under a path (workspace pull from active servers + 200-file walk for unchecked listing), or omit both to dump cached diagnostics.\n\n**When this tool gives an unhelpful answer**, run `bunx --bun @cortexkit/aft doctor lsp <filePath>` from a terminal to get a full per-server breakdown (registered servers, binary resolution, root-marker resolution, spawn outcome).",
17709
18029
  parameters: LspDiagnosticsParams,
17710
18030
  async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
17711
18031
  const hasFile = typeof params.filePath === "string" && params.filePath.length > 0;
@@ -17896,7 +18216,7 @@ function registerNavigateTool(pi, ctx) {
17896
18216
 
17897
18217
  // src/tools/reading.ts
17898
18218
  import { stat as stat2 } from "node:fs/promises";
17899
- import { resolve as resolve3 } from "node:path";
18219
+ import { resolve as resolve4 } from "node:path";
17900
18220
  import { Type as Type8 } from "@sinclair/typebox";
17901
18221
 
17902
18222
  // src/shared/discover-files.ts
@@ -18089,14 +18409,14 @@ function registerReadingTools(pi, ctx, surface) {
18089
18409
  let dirArg = hasDirectory ? params.directory : undefined;
18090
18410
  if (!dirArg && hasFilePath) {
18091
18411
  try {
18092
- const resolved = resolve3(extCtx.cwd, params.filePath);
18412
+ const resolved = resolve4(extCtx.cwd, params.filePath);
18093
18413
  const st = await stat2(resolved);
18094
18414
  if (st.isDirectory())
18095
18415
  dirArg = params.filePath;
18096
18416
  } catch {}
18097
18417
  }
18098
18418
  if (dirArg) {
18099
- const dirPath = resolve3(extCtx.cwd, dirArg);
18419
+ const dirPath = resolve4(extCtx.cwd, dirArg);
18100
18420
  const files = await discoverSourceFiles(dirPath);
18101
18421
  if (files.length === 0) {
18102
18422
  return textResult(`No source files found under ${dirArg}`);
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAsBH,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,kGAAkG;IAClG,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;;;;;;OASG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAkDD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM/D;AAiSD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,EACzB,SAAS,GAAE,OAAO,KAAa,GAC9B,iBAAiB,CAqEnB"}
1
+ {"version":3,"file":"lsp-auto-install.d.ts","sourceRoot":"","sources":["../src/lsp-auto-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAsBH,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,kGAAkG;IAClG,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;;;;;;OASG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAkDD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM/D;AAsSD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,EACzB,SAAS,GAAE,OAAO,KAAa,GAC9B,iBAAiB,CAqEnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-cache.d.ts","sourceRoot":"","sources":["../src/lsp-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAgBH;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAYrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,+CAA+C;AAC/C,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CASvE;AAOD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAY/F;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiB5E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAE7F;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAE1E;AAeD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiE3D;AAmBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CASxD;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOnB;AAED,wDAAwD;AACxD,UAAU,kBAAkB;IAC1B,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAID,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAe9E;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQjF;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,GAAG,IAAI,EACjC,qBAAqB,SAA0B,GAC9C,OAAO,CAKT"}
1
+ {"version":3,"file":"lsp-cache.d.ts","sourceRoot":"","sources":["../src/lsp-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAeH;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAYrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,+CAA+C;AAC/C,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CASvE;AAOD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAY/F;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiB5E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAE7F;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAE1E;AAeD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiE3D;AAmBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAqCxD;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAOnB;AAED,wDAAwD;AACxD,UAAU,kBAAkB;IAC1B,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAID,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAe9E;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQjF;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,GAAG,IAAI,EACjC,qBAAqB,SAA0B,GAC9C,OAAO,CAKT"}
@@ -39,6 +39,7 @@ export interface GithubInstallConfig {
39
39
  versions: Readonly<Record<string, string>>;
40
40
  disabled: ReadonlySet<string>;
41
41
  }
42
+ declare function assertAllowedDownloadUrl(rawUrl: string): URL;
42
43
  /**
43
44
  * Recursively validate that every entry under `stagingRoot` is contained
44
45
  * within it (audit #3: zip-slip + symlink containment).
@@ -86,5 +87,6 @@ export declare function runGithubAutoInstall(relevantServers: ReadonlySet<string
86
87
  * monorepos with nested source files.
87
88
  */
88
89
  export declare function discoverRelevantGithubServers(projectRoot: string): Set<string>;
89
- export { type Arch, detectHostPlatform, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform, };
90
+ /** Audit-3 v0.17 #5: test-only re-export. Production code uses it inline. */
91
+ export { type Arch, assertAllowedDownloadUrl as _assertAllowedDownloadUrlForTesting, detectHostPlatform, findGithubServerById, GITHUB_LSP_TABLE, type GithubServerSpec, type Platform, };
90
92
  //# sourceMappingURL=lsp-github-install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-github-install.d.ts","sourceRoot":"","sources":["../src/lsp-github-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAiCH,OAAO,EACL,KAAK,IAAI,EACT,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACd,MAAM,uBAAuB,CAAC;AAqB/B,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAG/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CASrF;AASD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAwUD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA0E5D;AAmSD,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAsBD,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAMjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,EACpC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,GAAE,OAAO,KAAa,GAC9B,uBAAuB,CAiFzB;AAID;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAyC9E;AAID,OAAO,EACL,KAAK,IAAI,EACT,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,GACd,CAAC"}
1
+ {"version":3,"file":"lsp-github-install.d.ts","sourceRoot":"","sources":["../src/lsp-github-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAsCH,OAAO,EACL,KAAK,IAAI,EACT,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACd,MAAM,uBAAuB,CAAC;AAqB/B,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAG/E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CASrF;AASD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC/B;AAoRD,iBAAS,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAgBrD;AA0ED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA0E5D;AAmSD,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAsBD,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAMjE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,EACpC,MAAM,EAAE,mBAAmB,EAC3B,SAAS,GAAE,OAAO,KAAa,GAC9B,uBAAuB,CAiFzB;AAID;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAyC9E;AAID,6EAA6E;AAC7E,OAAO,EACL,KAAK,IAAI,EACT,wBAAwB,IAAI,mCAAmC,EAC/D,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,GACd,CAAC"}
@@ -54,6 +54,8 @@ export declare function probeGithubReleases(githubRepo: string, graceDays: numbe
54
54
  * Throw if `version` contains anything outside the safe allowlist.
55
55
  */
56
56
  export declare function assertSafeVersion(version: string): void;
57
+ /** Audit-3 v0.17 #2: non-throwing predicate for cache-miss-on-corruption flow. */
58
+ export declare function isSafeVersion(version: string | null | undefined): version is string;
57
59
  /**
58
60
  * Strip a leading `v` from a release tag to get a clean version for asset
59
61
  * templates that don't include the `v` prefix.
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-github-probe.d.ts","sourceRoot":"","sources":["../src/lsp-github-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,oBAAoB,EAAE,MAAM,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,yEAAyE;IACzE,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,mEAAmE;IACnE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,GACvB,uBAAuB,CA4BzB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAyBzC;AAiBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C"}
1
+ {"version":3,"file":"lsp-github-probe.d.ts","sourceRoot":"","sources":["../src/lsp-github-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,oBAAoB,EAAE,MAAM,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,yEAAyE;IACzE,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,mEAAmE;IACnE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAmB,GACvB,uBAAuB,CA4BzB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAyBzC;AAiBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,IAAI,MAAM,CAEnF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C"}
@@ -4,6 +4,23 @@
4
4
  * Downloads the CPU-only ONNX Runtime from Microsoft's GitHub releases.
5
5
  * The library is cached in the storage directory alongside semantic index data.
6
6
  *
7
+ * Audit-3 v0.17 #1 hardening (v0.17.1): the previous implementation used
8
+ * `curl` with no size cap, no archive containment validation, no install
9
+ * lock, and no integrity verification — leaving an entire parallel install
10
+ * path that bypassed every defense the LSP GitHub installer had earned in
11
+ * Phase A through Phase E. This rewrite brings ONNX onto the same security
12
+ * floor:
13
+ *
14
+ * - Streaming size cap via fetch + ReadableStream transformer (`MAX_DOWNLOAD_BYTES`).
15
+ * - Streaming SHA-256 of the downloaded archive, persisted in `.aft-onnx-installed`.
16
+ * - Atomic O_EXCL install lock with PID-aware stale-lock recovery.
17
+ * - Containment-checked extraction: every file under the staging dir
18
+ * must be inside the staging root, no symlinks allowed before move.
19
+ * - Total extracted size cap (`MAX_EXTRACT_BYTES`) to defeat decompression
20
+ * bombs.
21
+ * - TOFU verification: if `.aft-onnx-installed` already records a hash for
22
+ * this version, refuse to use a binary that doesn't match.
23
+ *
7
24
  * Supported platforms:
8
25
  * - macOS ARM64 (osx-arm64)
9
26
  * - Linux x64 (linux-x64)
@@ -23,9 +40,10 @@ export declare function getManualInstallHint(): string;
23
40
  * or null if unavailable.
24
41
  *
25
42
  * Resolution order:
26
- * 1. Cached in storageDir/onnxruntime/<version>/
27
- * 2. Auto-download from GitHub releases (if platform supported)
28
- * 3. null (user needs manual install)
43
+ * 1. Cached in storageDir/onnxruntime/<version>/ (with TOFU verification)
44
+ * 2. System install (brew, apt, etc.)
45
+ * 3. Auto-download from GitHub releases (if platform supported)
46
+ * 4. null (user needs manual install)
29
47
  */
30
48
  export declare function ensureOnnxRuntime(storageDir: string): Promise<string | null>;
31
49
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"onnx-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA0DH,4DAA4D;AAC5D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4BlF;AAmKD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3D"}
1
+ {"version":3,"file":"onnx-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AA6FH,4DAA4D;AAC5D,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6ElF;AAqeD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAS3D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft-pi",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
6
6
  "main": "dist/index.js",
@@ -26,11 +26,11 @@
26
26
  "zod": "^4.1.8"
27
27
  },
28
28
  "optionalDependencies": {
29
- "@cortexkit/aft-darwin-arm64": "0.17.0",
30
- "@cortexkit/aft-darwin-x64": "0.17.0",
31
- "@cortexkit/aft-linux-arm64": "0.17.0",
32
- "@cortexkit/aft-linux-x64": "0.17.0",
33
- "@cortexkit/aft-win32-x64": "0.17.0"
29
+ "@cortexkit/aft-darwin-arm64": "0.17.1",
30
+ "@cortexkit/aft-darwin-x64": "0.17.1",
31
+ "@cortexkit/aft-linux-arm64": "0.17.1",
32
+ "@cortexkit/aft-linux-x64": "0.17.1",
33
+ "@cortexkit/aft-win32-x64": "0.17.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@mariozechner/pi-coding-agent": "*",