@cortexkit/aft-pi 0.58.0 → 0.58.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/config-error-state.d.ts +8 -0
- package/dist/config-error-state.d.ts.map +1 -1
- package/dist/config-live-reload.d.ts +28 -0
- package/dist/config-live-reload.d.ts.map +1 -0
- package/dist/config.d.ts +71 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +783 -167
- package/dist/lsp-auto-install.d.ts.map +1 -1
- package/dist/lsp-npm-table.d.ts +1 -1
- package/dist/lsp-npm-table.d.ts.map +1 -1
- package/dist/tool-registration.d.ts +8 -1
- package/dist/tool-registration.d.ts.map +1 -1
- package/dist/tools/bash.d.ts +3 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/workflow-hints.d.ts +1 -0
- package/dist/workflow-hints.d.ts.map +1 -1
- package/package.json +12 -10
package/dist/index.js
CHANGED
|
@@ -7938,6 +7938,9 @@ function isTerminalStatus(status) {
|
|
|
7938
7938
|
function sleep(ms) {
|
|
7939
7939
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7940
7940
|
}
|
|
7941
|
+
function monotonicNowMs() {
|
|
7942
|
+
return performance.now();
|
|
7943
|
+
}
|
|
7941
7944
|
// ../aft-bridge/dist/bash-hints.js
|
|
7942
7945
|
import * as fs from "node:fs";
|
|
7943
7946
|
import * as os from "node:os";
|
|
@@ -7948,6 +7951,10 @@ function resolveWatchTimeoutMs(requestedMs, role, capMs) {
|
|
|
7948
7951
|
const fallback = role === "worker" ? capMs : DEFAULT_PRIMARY_WATCH_TIMEOUT_MS;
|
|
7949
7952
|
return Math.min(requestedMs ?? fallback, capMs);
|
|
7950
7953
|
}
|
|
7954
|
+
function formatWatchWaited(elapsedMs, limitMs, capMs) {
|
|
7955
|
+
const limit = limitMs >= capMs ? `limit ${limitMs}ms, the bash.watch_sync_max_ms cap` : `limit ${limitMs}ms`;
|
|
7956
|
+
return `Waited ${Math.round(elapsedMs)}ms (${limit})`;
|
|
7957
|
+
}
|
|
7951
7958
|
function watchTimeoutSteer(role, capMs, timeoutParam = "timeoutMs") {
|
|
7952
7959
|
if (role === "worker") {
|
|
7953
7960
|
return `The command is still running; this is not a failure. Watch again (${timeoutParam} up to ${capMs}) and don't report a result until it finishes.`;
|
|
@@ -8334,7 +8341,7 @@ import { existsSync } from "node:fs";
|
|
|
8334
8341
|
import { join as join3 } from "node:path";
|
|
8335
8342
|
|
|
8336
8343
|
// ../aft-bridge/dist/child-process.js
|
|
8337
|
-
import { execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
|
|
8344
|
+
import { execFile as nodeExecFile, execFileSync as nodeExecFileSync, execSync as nodeExecSync, spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
|
|
8338
8345
|
var HIDDEN = { windowsHide: true };
|
|
8339
8346
|
function withWindowsHidden(args, takesArgv) {
|
|
8340
8347
|
const out = [...args];
|
|
@@ -8356,6 +8363,7 @@ function hidden(resolve, takesArgv) {
|
|
|
8356
8363
|
}
|
|
8357
8364
|
var spawn = hidden(() => nodeSpawn, true);
|
|
8358
8365
|
var spawnSync = hidden(() => nodeSpawnSync, true);
|
|
8366
|
+
var execFile = hidden(() => nodeExecFile, true);
|
|
8359
8367
|
var execFileSync = hidden(() => nodeExecFileSync, true);
|
|
8360
8368
|
var execSync = hidden(() => nodeExecSync, false);
|
|
8361
8369
|
|
|
@@ -9682,17 +9690,30 @@ class BinaryBridge {
|
|
|
9682
9690
|
}
|
|
9683
9691
|
}
|
|
9684
9692
|
onStderrData(data) {
|
|
9685
|
-
|
|
9686
|
-
let
|
|
9687
|
-
while (
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9693
|
+
const partialLimit = 64 * 1024;
|
|
9694
|
+
let offset = 0;
|
|
9695
|
+
while (offset < data.length) {
|
|
9696
|
+
const newline = data.indexOf(`
|
|
9697
|
+
`, offset);
|
|
9698
|
+
const end = newline < 0 ? data.length : newline;
|
|
9699
|
+
while (offset < end) {
|
|
9700
|
+
const count = Math.min(partialLimit - this.stderrBuffer.length, end - offset);
|
|
9701
|
+
this.stderrBuffer += data.slice(offset, offset + count);
|
|
9702
|
+
offset += count;
|
|
9703
|
+
if (this.stderrBuffer.length === partialLimit) {
|
|
9704
|
+
const last = this.stderrBuffer.charCodeAt(this.stderrBuffer.length - 1);
|
|
9705
|
+
const carry = last >= 55296 && last <= 56319 ? this.stderrBuffer.slice(-1) : "";
|
|
9706
|
+
const fragment = carry ? this.stderrBuffer.slice(0, -1) : this.stderrBuffer;
|
|
9707
|
+
const tagged = tagStderrLine(`${fragment} [stderr record truncated into bounded fragments; ${Buffer.byteLength(fragment)} bytes shown, continuation follows]`);
|
|
9708
|
+
this.stderrBuffer = carry;
|
|
9709
|
+
this.logVia(tagged);
|
|
9710
|
+
this.pushStderrLine(tagged);
|
|
9711
|
+
}
|
|
9712
|
+
}
|
|
9713
|
+
if (newline < 0)
|
|
9714
|
+
break;
|
|
9715
|
+
this.flushStderrBuffer();
|
|
9716
|
+
offset = newline + 1;
|
|
9696
9717
|
}
|
|
9697
9718
|
}
|
|
9698
9719
|
flushStderrBuffer() {
|
|
@@ -10438,9 +10459,366 @@ function formatDroppedKeyWarnings(dropped) {
|
|
|
10438
10459
|
}
|
|
10439
10460
|
return dropped.map((item) => `Ignoring ${item.key} from ${item.tier} config (${item.reason})`);
|
|
10440
10461
|
}
|
|
10462
|
+
// ../aft-bridge/dist/config-watch.js
|
|
10463
|
+
import { readFileSync as readFileSync3, statSync as statSync3, watch } from "node:fs";
|
|
10464
|
+
import { basename, dirname } from "node:path";
|
|
10465
|
+
var CONFIG_WATCH_DEBOUNCE_MS = 150;
|
|
10466
|
+
var CONFIG_LIVE_KEEP_NOTE = "AFT keeps using the last valid configuration until the file is fixed.";
|
|
10467
|
+
function pathKey(name) {
|
|
10468
|
+
const segments = name.split(".");
|
|
10469
|
+
return {
|
|
10470
|
+
name,
|
|
10471
|
+
read(config) {
|
|
10472
|
+
let value = config;
|
|
10473
|
+
for (const segment of segments) {
|
|
10474
|
+
if (value === null || typeof value !== "object")
|
|
10475
|
+
return;
|
|
10476
|
+
value = value[segment];
|
|
10477
|
+
}
|
|
10478
|
+
return value;
|
|
10479
|
+
},
|
|
10480
|
+
write(config, value) {
|
|
10481
|
+
const set = (target, index) => {
|
|
10482
|
+
const copy = target !== null && typeof target === "object" && !Array.isArray(target) ? { ...target } : {};
|
|
10483
|
+
const segment = segments[index];
|
|
10484
|
+
if (index === segments.length - 1) {
|
|
10485
|
+
if (value === undefined)
|
|
10486
|
+
delete copy[segment];
|
|
10487
|
+
else
|
|
10488
|
+
copy[segment] = value;
|
|
10489
|
+
} else {
|
|
10490
|
+
copy[segment] = set(copy[segment], index + 1);
|
|
10491
|
+
}
|
|
10492
|
+
return copy;
|
|
10493
|
+
};
|
|
10494
|
+
return set(config, 0);
|
|
10495
|
+
}
|
|
10496
|
+
};
|
|
10497
|
+
}
|
|
10498
|
+
function bashKey(name, resolveBash) {
|
|
10499
|
+
return {
|
|
10500
|
+
name: `bash.${name}`,
|
|
10501
|
+
read: (config) => resolveBash(config)[name],
|
|
10502
|
+
write(config, value) {
|
|
10503
|
+
const resolved = { ...resolveBash(config), [name]: value };
|
|
10504
|
+
for (const key of Object.keys(resolved)) {
|
|
10505
|
+
if (resolved[key] === undefined)
|
|
10506
|
+
delete resolved[key];
|
|
10507
|
+
}
|
|
10508
|
+
return { ...config, bash: resolved };
|
|
10509
|
+
}
|
|
10510
|
+
};
|
|
10511
|
+
}
|
|
10512
|
+
function aftLiveConfigKeys(resolveBash) {
|
|
10513
|
+
return [
|
|
10514
|
+
pathKey("configure_warnings_delivery"),
|
|
10515
|
+
pathKey("restrict_to_project_root"),
|
|
10516
|
+
pathKey("inspect.diagnostics_timeout_ms"),
|
|
10517
|
+
pathKey("inspect.tier2_idle_minutes"),
|
|
10518
|
+
bashKey("foreground_wait_window_ms", resolveBash),
|
|
10519
|
+
bashKey("host_fallback", resolveBash),
|
|
10520
|
+
bashKey("subagent_background", resolveBash),
|
|
10521
|
+
bashKey("watch_sync_max_ms", resolveBash)
|
|
10522
|
+
];
|
|
10523
|
+
}
|
|
10524
|
+
function sameValue(a, b) {
|
|
10525
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
10526
|
+
}
|
|
10527
|
+
function flattenLeaves(value, prefix, out) {
|
|
10528
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
10529
|
+
const entries = Object.entries(value);
|
|
10530
|
+
if (entries.length === 0 && prefix)
|
|
10531
|
+
out.set(prefix, "{}");
|
|
10532
|
+
for (const [key, child] of entries) {
|
|
10533
|
+
flattenLeaves(child, prefix ? `${prefix}.${key}` : key, out);
|
|
10534
|
+
}
|
|
10535
|
+
return;
|
|
10536
|
+
}
|
|
10537
|
+
if (prefix)
|
|
10538
|
+
out.set(prefix, JSON.stringify(value));
|
|
10539
|
+
}
|
|
10540
|
+
function applyLiveConfigKeys(current, next, keys, baseline = current) {
|
|
10541
|
+
let config = current;
|
|
10542
|
+
const applied = [];
|
|
10543
|
+
for (const key of keys) {
|
|
10544
|
+
const value = key.read(next);
|
|
10545
|
+
if (sameValue(key.read(current), value))
|
|
10546
|
+
continue;
|
|
10547
|
+
config = key.write(config, value);
|
|
10548
|
+
applied.push(key.name);
|
|
10549
|
+
}
|
|
10550
|
+
const before = new Map;
|
|
10551
|
+
const after = new Map;
|
|
10552
|
+
flattenLeaves(baseline, "", before);
|
|
10553
|
+
flattenLeaves(next, "", after);
|
|
10554
|
+
const liveNames = keys.map((key) => key.name);
|
|
10555
|
+
const isLive = (leaf) => liveNames.some((name) => leaf === name || leaf.startsWith(`${name}.`));
|
|
10556
|
+
const deferred = new Set;
|
|
10557
|
+
for (const leaf of new Set([...before.keys(), ...after.keys()])) {
|
|
10558
|
+
if (before.get(leaf) === after.get(leaf) || isLive(leaf))
|
|
10559
|
+
continue;
|
|
10560
|
+
deferred.add(leaf);
|
|
10561
|
+
}
|
|
10562
|
+
return { config, applied, deferred: [...deferred].sort() };
|
|
10563
|
+
}
|
|
10564
|
+
function readTextOrNull(path) {
|
|
10565
|
+
try {
|
|
10566
|
+
return readFileSync3(path, "utf8");
|
|
10567
|
+
} catch {
|
|
10568
|
+
return null;
|
|
10569
|
+
}
|
|
10570
|
+
}
|
|
10571
|
+
var CONFIG_WATCH_REVALIDATE_MS = 2000;
|
|
10572
|
+
var CONFIG_WATCH_REJECTED_RETRIES = 3;
|
|
10573
|
+
var CONFIG_WATCH_MAX_DELAY_MS = 1000;
|
|
10574
|
+
function identityOf(dir) {
|
|
10575
|
+
try {
|
|
10576
|
+
const stat = statSync3(dir, { bigint: true });
|
|
10577
|
+
const base = `${stat.dev}:${stat.ino}`;
|
|
10578
|
+
return process.platform === "win32" ? base : `${base}:${stat.birthtimeNs}`;
|
|
10579
|
+
} catch {
|
|
10580
|
+
return null;
|
|
10581
|
+
}
|
|
10582
|
+
}
|
|
10583
|
+
function watchDirFor(file) {
|
|
10584
|
+
let dir = dirname(file);
|
|
10585
|
+
while (dir !== dirname(dir) && identityOf(dir) === null)
|
|
10586
|
+
dir = dirname(dir);
|
|
10587
|
+
return dir;
|
|
10588
|
+
}
|
|
10589
|
+
function watchAftConfigFiles(options) {
|
|
10590
|
+
const debounceMs = options.debounceMs ?? CONFIG_WATCH_DEBOUNCE_MS;
|
|
10591
|
+
const lastSeen = new Map;
|
|
10592
|
+
for (const path of options.paths) {
|
|
10593
|
+
if (options.initialTexts)
|
|
10594
|
+
lastSeen.set(path, options.initialTexts[path] ?? null);
|
|
10595
|
+
else
|
|
10596
|
+
lastSeen.set(path, options.checkAtStart ? undefined : readTextOrNull(path));
|
|
10597
|
+
}
|
|
10598
|
+
let timer = null;
|
|
10599
|
+
let firstPendingAt = null;
|
|
10600
|
+
let stopped = false;
|
|
10601
|
+
const watchers = new Map;
|
|
10602
|
+
const watchImpl = options.watchImpl ?? watch;
|
|
10603
|
+
let rejectedRetries = 0;
|
|
10604
|
+
const check = () => {
|
|
10605
|
+
timer = null;
|
|
10606
|
+
firstPendingAt = null;
|
|
10607
|
+
if (stopped)
|
|
10608
|
+
return;
|
|
10609
|
+
revalidate();
|
|
10610
|
+
const seen = new Map;
|
|
10611
|
+
for (const path of options.paths) {
|
|
10612
|
+
const text = readTextOrNull(path);
|
|
10613
|
+
if (text !== lastSeen.get(path))
|
|
10614
|
+
seen.set(path, text);
|
|
10615
|
+
}
|
|
10616
|
+
if (seen.size === 0)
|
|
10617
|
+
return;
|
|
10618
|
+
const outcome = options.onChange();
|
|
10619
|
+
if (outcome === false) {
|
|
10620
|
+
if (rejectedRetries < CONFIG_WATCH_REJECTED_RETRIES) {
|
|
10621
|
+
rejectedRetries += 1;
|
|
10622
|
+
retryTimer = setTimeout(check, CONFIG_WATCH_MAX_DELAY_MS);
|
|
10623
|
+
retryTimer.unref?.();
|
|
10624
|
+
}
|
|
10625
|
+
return;
|
|
10626
|
+
}
|
|
10627
|
+
rejectedRetries = 0;
|
|
10628
|
+
if (outcome instanceof Map) {
|
|
10629
|
+
for (const path of options.paths)
|
|
10630
|
+
lastSeen.set(path, outcome.get(path) ?? null);
|
|
10631
|
+
} else {
|
|
10632
|
+
for (const [path, text] of seen)
|
|
10633
|
+
lastSeen.set(path, text);
|
|
10634
|
+
}
|
|
10635
|
+
};
|
|
10636
|
+
let retryTimer = null;
|
|
10637
|
+
const schedule = () => {
|
|
10638
|
+
if (stopped)
|
|
10639
|
+
return;
|
|
10640
|
+
const now = Date.now();
|
|
10641
|
+
firstPendingAt ??= now;
|
|
10642
|
+
if (timer)
|
|
10643
|
+
clearTimeout(timer);
|
|
10644
|
+
const delay = Math.max(0, Math.min(debounceMs, firstPendingAt + CONFIG_WATCH_MAX_DELAY_MS - now));
|
|
10645
|
+
timer = setTimeout(check, delay);
|
|
10646
|
+
timer.unref?.();
|
|
10647
|
+
};
|
|
10648
|
+
function revalidate() {
|
|
10649
|
+
const wanted = new Set(options.paths.map(watchDirFor));
|
|
10650
|
+
let moved = false;
|
|
10651
|
+
for (const [dir, entry] of watchers) {
|
|
10652
|
+
if (!wanted.has(dir) || entry.stale || identityOf(dir) !== entry.identity) {
|
|
10653
|
+
entry.watcher.close();
|
|
10654
|
+
watchers.delete(dir);
|
|
10655
|
+
moved = true;
|
|
10656
|
+
}
|
|
10657
|
+
}
|
|
10658
|
+
for (const dir of wanted) {
|
|
10659
|
+
if (watchers.has(dir))
|
|
10660
|
+
continue;
|
|
10661
|
+
try {
|
|
10662
|
+
const identity = identityOf(dir);
|
|
10663
|
+
options.beforeWatchForTest?.(dir);
|
|
10664
|
+
const name = basename(dir);
|
|
10665
|
+
const watcher = watchImpl(dir, { persistent: false }, (event, filename) => {
|
|
10666
|
+
if (event === "rename" && filename === name) {
|
|
10667
|
+
const current = watchers.get(dir);
|
|
10668
|
+
if (current && current.watcher === watcher)
|
|
10669
|
+
current.stale = true;
|
|
10670
|
+
}
|
|
10671
|
+
schedule();
|
|
10672
|
+
});
|
|
10673
|
+
if (identityOf(dir) !== identity) {
|
|
10674
|
+
watcher.close();
|
|
10675
|
+
moved = true;
|
|
10676
|
+
continue;
|
|
10677
|
+
}
|
|
10678
|
+
const entry = { watcher, identity, stale: false };
|
|
10679
|
+
entry.watcher.on("error", () => {
|
|
10680
|
+
entry.watcher.close();
|
|
10681
|
+
if (watchers.get(dir) === entry)
|
|
10682
|
+
watchers.delete(dir);
|
|
10683
|
+
schedule();
|
|
10684
|
+
});
|
|
10685
|
+
watchers.set(dir, entry);
|
|
10686
|
+
moved = true;
|
|
10687
|
+
} catch {}
|
|
10688
|
+
}
|
|
10689
|
+
return moved;
|
|
10690
|
+
}
|
|
10691
|
+
revalidate();
|
|
10692
|
+
if (options.checkAtStart)
|
|
10693
|
+
check();
|
|
10694
|
+
const revalidateTimer = setInterval(() => {
|
|
10695
|
+
if (!stopped && revalidate())
|
|
10696
|
+
schedule();
|
|
10697
|
+
}, CONFIG_WATCH_REVALIDATE_MS);
|
|
10698
|
+
revalidateTimer.unref?.();
|
|
10699
|
+
return () => {
|
|
10700
|
+
stopped = true;
|
|
10701
|
+
if (timer)
|
|
10702
|
+
clearTimeout(timer);
|
|
10703
|
+
if (retryTimer)
|
|
10704
|
+
clearTimeout(retryTimer);
|
|
10705
|
+
clearInterval(revalidateTimer);
|
|
10706
|
+
for (const entry of watchers.values())
|
|
10707
|
+
entry.watcher.close();
|
|
10708
|
+
watchers.clear();
|
|
10709
|
+
};
|
|
10710
|
+
}
|
|
10711
|
+
function aftLiveSecurityKeys(keys) {
|
|
10712
|
+
const byName = new Map(keys.map((key) => [key.name, key]));
|
|
10713
|
+
const pick = (name) => {
|
|
10714
|
+
const key = byName.get(name);
|
|
10715
|
+
if (!key)
|
|
10716
|
+
throw new Error(`unknown live config key ${name}`);
|
|
10717
|
+
return key;
|
|
10718
|
+
};
|
|
10719
|
+
return [
|
|
10720
|
+
{
|
|
10721
|
+
key: pick("restrict_to_project_root"),
|
|
10722
|
+
loosens: (current, next) => current === true && next !== true
|
|
10723
|
+
},
|
|
10724
|
+
{
|
|
10725
|
+
key: pick("bash.host_fallback"),
|
|
10726
|
+
loosens: (current, next) => current !== true && next === true
|
|
10727
|
+
}
|
|
10728
|
+
];
|
|
10729
|
+
}
|
|
10730
|
+
function liveConfigReloadLogLine(applied, deferred) {
|
|
10731
|
+
let line = "config reload";
|
|
10732
|
+
if (applied.length > 0)
|
|
10733
|
+
line += ` applied=[${applied.join(",")}]`;
|
|
10734
|
+
if (deferred.length > 0) {
|
|
10735
|
+
line += ` deferred=[${deferred.join(",")}] (deferred keys apply on next connect/restart)`;
|
|
10736
|
+
}
|
|
10737
|
+
return line;
|
|
10738
|
+
}
|
|
10739
|
+
function startLiveConfigReload(options) {
|
|
10740
|
+
const baseline = options.getConfig();
|
|
10741
|
+
let lastError = null;
|
|
10742
|
+
let acceptedSources = new Set(options.initialSources);
|
|
10743
|
+
let acceptedProjectText = options.initialProjectText ?? null;
|
|
10744
|
+
let acceptedTexts;
|
|
10745
|
+
const reload = () => {
|
|
10746
|
+
let loaded = options.load();
|
|
10747
|
+
if (loaded.ok) {
|
|
10748
|
+
const read = new Set(loaded.sources);
|
|
10749
|
+
const deleted = [...acceptedSources].find((path) => !read.has(path));
|
|
10750
|
+
if (deleted !== undefined) {
|
|
10751
|
+
loaded = { ok: false, message: `AFT config at ${deleted} was deleted` };
|
|
10752
|
+
} else {
|
|
10753
|
+
acceptedSources = read;
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
if (!loaded.ok) {
|
|
10757
|
+
const message = `${loaded.message.trim().replace(/[.!?]?$/, ".")} ${CONFIG_LIVE_KEEP_NOTE}`;
|
|
10758
|
+
if (message !== lastError) {
|
|
10759
|
+
lastError = message;
|
|
10760
|
+
options.reportError(message);
|
|
10761
|
+
}
|
|
10762
|
+
return null;
|
|
10763
|
+
}
|
|
10764
|
+
lastError = null;
|
|
10765
|
+
acceptedTexts = loaded.texts;
|
|
10766
|
+
const current = options.getConfig();
|
|
10767
|
+
let next = loaded.config;
|
|
10768
|
+
const held = [];
|
|
10769
|
+
const projectText = loaded.projectText ?? null;
|
|
10770
|
+
if (loaded.projectText !== undefined && projectText !== acceptedProjectText) {
|
|
10771
|
+
for (const security of options.securityKeys ?? []) {
|
|
10772
|
+
const now = security.key.read(current);
|
|
10773
|
+
if (security.loosens(now, security.key.read(next))) {
|
|
10774
|
+
next = security.key.write(next, now);
|
|
10775
|
+
held.push(security.key.name);
|
|
10776
|
+
}
|
|
10777
|
+
}
|
|
10778
|
+
if (held.length === 0)
|
|
10779
|
+
acceptedProjectText = projectText;
|
|
10780
|
+
}
|
|
10781
|
+
const result = applyLiveConfigKeys(current, next, options.keys, baseline);
|
|
10782
|
+
if (result.applied.length > 0)
|
|
10783
|
+
options.setConfig(result.config);
|
|
10784
|
+
if (result.applied.length > 0 || result.deferred.length > 0 || held.length > 0) {
|
|
10785
|
+
let line = liveConfigReloadLogLine(result.applied, result.deferred);
|
|
10786
|
+
if (held.length > 0) {
|
|
10787
|
+
line += ` held=[${held.join(",")}] (not loosened while the project file differs from the one the published values came from; the next restart applies them)`;
|
|
10788
|
+
}
|
|
10789
|
+
options.log(line);
|
|
10790
|
+
}
|
|
10791
|
+
return { ...result, held };
|
|
10792
|
+
};
|
|
10793
|
+
const safeReload = () => {
|
|
10794
|
+
try {
|
|
10795
|
+
acceptedTexts = undefined;
|
|
10796
|
+
if (reload() === null)
|
|
10797
|
+
return false;
|
|
10798
|
+
const texts = acceptedTexts;
|
|
10799
|
+
if (!texts)
|
|
10800
|
+
return true;
|
|
10801
|
+
return new Map(options.paths.map((path) => [path, texts[path] ?? null]));
|
|
10802
|
+
} catch (err) {
|
|
10803
|
+
options.reportError(`AFT config reload failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
10804
|
+
return false;
|
|
10805
|
+
}
|
|
10806
|
+
};
|
|
10807
|
+
if (options.watch === false) {
|
|
10808
|
+
return { reload, stop: () => {} };
|
|
10809
|
+
}
|
|
10810
|
+
const stop = watchAftConfigFiles({
|
|
10811
|
+
paths: options.paths,
|
|
10812
|
+
debounceMs: options.debounceMs,
|
|
10813
|
+
onChange: safeReload,
|
|
10814
|
+
initialTexts: options.initialTexts,
|
|
10815
|
+
checkAtStart: true
|
|
10816
|
+
});
|
|
10817
|
+
return { reload, stop };
|
|
10818
|
+
}
|
|
10441
10819
|
// ../aft-bridge/dist/downloader.js
|
|
10442
10820
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
10443
|
-
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as
|
|
10821
|
+
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync4, unlinkSync as unlinkSync2, writeSync } from "node:fs";
|
|
10444
10822
|
import { hostname } from "node:os";
|
|
10445
10823
|
import { join as join7 } from "node:path";
|
|
10446
10824
|
import { Readable } from "node:stream";
|
|
@@ -10792,7 +11170,7 @@ function isReclaimableDownloadLock(owner, ageMs, staleMs) {
|
|
|
10792
11170
|
}
|
|
10793
11171
|
function reclaimDownloadLock(lockPath, expectedOwner) {
|
|
10794
11172
|
try {
|
|
10795
|
-
if (
|
|
11173
|
+
if (readFileSync4(lockPath, "utf-8") !== expectedOwner)
|
|
10796
11174
|
return false;
|
|
10797
11175
|
rmSync(lockPath, { force: true });
|
|
10798
11176
|
return true;
|
|
@@ -10810,7 +11188,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
|
|
|
10810
11188
|
continue;
|
|
10811
11189
|
}
|
|
10812
11190
|
const tempPath = join7(versionedCacheDir, entry.name);
|
|
10813
|
-
const ageMs = Date.now() -
|
|
11191
|
+
const ageMs = Date.now() - statSync4(tempPath).mtimeMs;
|
|
10814
11192
|
if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
|
|
10815
11193
|
unlinkSync2(tempPath);
|
|
10816
11194
|
}
|
|
@@ -10832,7 +11210,7 @@ async function acquireDownloadLock(lockPath, timing = {}) {
|
|
|
10832
11210
|
}
|
|
10833
11211
|
return () => {
|
|
10834
11212
|
try {
|
|
10835
|
-
if (
|
|
11213
|
+
if (readFileSync4(lockPath, "utf-8") === owner) {
|
|
10836
11214
|
rmSync(lockPath, { force: true });
|
|
10837
11215
|
}
|
|
10838
11216
|
} catch {}
|
|
@@ -10844,8 +11222,8 @@ async function acquireDownloadLock(lockPath, timing = {}) {
|
|
|
10844
11222
|
let existingOwner;
|
|
10845
11223
|
let ageMs;
|
|
10846
11224
|
try {
|
|
10847
|
-
existingOwner =
|
|
10848
|
-
ageMs = Date.now() -
|
|
11225
|
+
existingOwner = readFileSync4(lockPath, "utf-8");
|
|
11226
|
+
ageMs = Date.now() - statSync4(lockPath).mtimeMs;
|
|
10849
11227
|
} catch (readErr) {
|
|
10850
11228
|
if (readErr.code === "ENOENT")
|
|
10851
11229
|
continue;
|
|
@@ -10895,7 +11273,7 @@ async function fetchLatestTag() {
|
|
|
10895
11273
|
}
|
|
10896
11274
|
// ../aft-bridge/dist/durable-log.js
|
|
10897
11275
|
import { appendFile, chmod, mkdir, rename, rm, stat } from "node:fs/promises";
|
|
10898
|
-
import { dirname } from "node:path";
|
|
11276
|
+
import { dirname as dirname2 } from "node:path";
|
|
10899
11277
|
var DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
|
|
10900
11278
|
var DEFAULT_LOG_GENERATIONS = 1;
|
|
10901
11279
|
var LOG_DIR_MODE = 448;
|
|
@@ -10908,6 +11286,10 @@ class RotatingLogSink {
|
|
|
10908
11286
|
queue = Promise.resolve();
|
|
10909
11287
|
disabled = false;
|
|
10910
11288
|
failureReported = false;
|
|
11289
|
+
queuedBytes = 0;
|
|
11290
|
+
queuedRecords = 0;
|
|
11291
|
+
droppedBytes = 0;
|
|
11292
|
+
overflowQueued = false;
|
|
10911
11293
|
constructor(path, options = {}) {
|
|
10912
11294
|
this.path = path;
|
|
10913
11295
|
this.maxBytes = options.maxBytes ?? DEFAULT_LOG_BYTES;
|
|
@@ -10916,7 +11298,34 @@ class RotatingLogSink {
|
|
|
10916
11298
|
append(data) {
|
|
10917
11299
|
if (this.disabled || data.length === 0)
|
|
10918
11300
|
return;
|
|
10919
|
-
|
|
11301
|
+
const bytes = Buffer.byteLength(data);
|
|
11302
|
+
const overflow = this.queuedBytes + bytes > 1024 * 1024 || this.queuedRecords >= 4096;
|
|
11303
|
+
if (overflow) {
|
|
11304
|
+
this.droppedBytes += bytes;
|
|
11305
|
+
if (this.overflowQueued)
|
|
11306
|
+
return;
|
|
11307
|
+
this.overflowQueued = true;
|
|
11308
|
+
data = "";
|
|
11309
|
+
} else {
|
|
11310
|
+
this.queuedBytes += bytes;
|
|
11311
|
+
this.queuedRecords += 1;
|
|
11312
|
+
}
|
|
11313
|
+
this.queue = this.queue.then(async () => {
|
|
11314
|
+
if (overflow) {
|
|
11315
|
+
const dropped = this.droppedBytes;
|
|
11316
|
+
this.droppedBytes = 0;
|
|
11317
|
+
this.overflowQueued = false;
|
|
11318
|
+
await this.write(`[aft-plugin] durable log queue overflow: dropped ${dropped} bytes (1MiB/4096-record pending limit); reduce diagnostic volume.
|
|
11319
|
+
`);
|
|
11320
|
+
} else {
|
|
11321
|
+
try {
|
|
11322
|
+
await this.write(data);
|
|
11323
|
+
} finally {
|
|
11324
|
+
this.queuedBytes -= bytes;
|
|
11325
|
+
this.queuedRecords -= 1;
|
|
11326
|
+
}
|
|
11327
|
+
}
|
|
11328
|
+
}).catch((error) => {
|
|
10920
11329
|
this.disabled = true;
|
|
10921
11330
|
if (!this.failureReported) {
|
|
10922
11331
|
this.failureReported = true;
|
|
@@ -10931,8 +11340,8 @@ class RotatingLogSink {
|
|
|
10931
11340
|
await this.queue;
|
|
10932
11341
|
}
|
|
10933
11342
|
async write(data) {
|
|
10934
|
-
const dir =
|
|
10935
|
-
await mkdir(
|
|
11343
|
+
const dir = dirname2(this.path);
|
|
11344
|
+
await mkdir(dirname2(dir), { recursive: true });
|
|
10936
11345
|
try {
|
|
10937
11346
|
await mkdir(dir, { mode: LOG_DIR_MODE });
|
|
10938
11347
|
} catch (error) {
|
|
@@ -11038,6 +11447,15 @@ function formatEditSummary(data) {
|
|
|
11038
11447
|
let s = `Edited (${detail}).`;
|
|
11039
11448
|
if (data.formatted)
|
|
11040
11449
|
s += formatAutoFormattedSuffix(data);
|
|
11450
|
+
const fuzzy = data.fuzzy_matches ?? (data.fuzzy_match ? [data.fuzzy_match] : []);
|
|
11451
|
+
for (const match of fuzzy) {
|
|
11452
|
+
s += `
|
|
11453
|
+
Fuzzy match (pass ${match.pass}).`;
|
|
11454
|
+
for (const [index, text] of match.replaced_text.entries()) {
|
|
11455
|
+
s += `
|
|
11456
|
+
Replaced text ${index + 1}: ${text}`;
|
|
11457
|
+
}
|
|
11458
|
+
}
|
|
11041
11459
|
return s;
|
|
11042
11460
|
}
|
|
11043
11461
|
function formatAutoFormattedSuffix(data) {
|
|
@@ -12766,7 +13184,7 @@ function reverseRequestMethod(body) {
|
|
|
12766
13184
|
}
|
|
12767
13185
|
}
|
|
12768
13186
|
// ../aft-bridge/dist/subc-transport.js
|
|
12769
|
-
import { existsSync as existsSync4, statSync as
|
|
13187
|
+
import { existsSync as existsSync4, statSync as statSync5 } from "node:fs";
|
|
12770
13188
|
|
|
12771
13189
|
// ../aft-bridge/dist/lifecycle-registry.js
|
|
12772
13190
|
import { lstat } from "node:fs/promises";
|
|
@@ -13289,6 +13707,7 @@ var RECONNECT_RETRY_FLOOR_MS = 100;
|
|
|
13289
13707
|
var RECONNECT_RETRY_CAP_MS = 2000;
|
|
13290
13708
|
var SUBC_DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
13291
13709
|
var ROUTE_OPEN_RELOAD_WAIT_CEILING_MS = 45000;
|
|
13710
|
+
var CALL_DEADLINE_EXPIRED = Symbol("call deadline expired");
|
|
13292
13711
|
function reloadWaitExhaustedSuffix(callDeadlineMs) {
|
|
13293
13712
|
if (callDeadlineMs > ROUTE_OPEN_RELOAD_WAIT_CEILING_MS) {
|
|
13294
13713
|
const ceilingSeconds = ROUTE_OPEN_RELOAD_WAIT_CEILING_MS / 1000;
|
|
@@ -13641,7 +14060,16 @@ function absentRootError(root) {
|
|
|
13641
14060
|
return new SubcError(`invalid route project root: project root does not exist: ${root}`, "config_divergence");
|
|
13642
14061
|
}
|
|
13643
14062
|
function reloadWindowExhaustedError(error, callDeadlineMs) {
|
|
13644
|
-
|
|
14063
|
+
return withDeadlineSuffix(error, reloadWaitExhaustedSuffix(callDeadlineMs));
|
|
14064
|
+
}
|
|
14065
|
+
function callDeadlinePassedError(lastError, callDeadlineMs) {
|
|
14066
|
+
const seconds = Math.round(callDeadlineMs / 100) / 10;
|
|
14067
|
+
const suffix = ` The AFT daemon module did not return within this call's ${seconds}s deadline.`;
|
|
14068
|
+
if (lastError !== undefined)
|
|
14069
|
+
return withDeadlineSuffix(lastError, suffix);
|
|
14070
|
+
return new SubcError(`route to module '${AFT_MODULE_ID}' was not ready before the call ran out of time.${suffix}`, REQUEST_DEADLINE_CODE);
|
|
14071
|
+
}
|
|
14072
|
+
function withDeadlineSuffix(error, suffix) {
|
|
13645
14073
|
if (error instanceof Error) {
|
|
13646
14074
|
try {
|
|
13647
14075
|
error.message += suffix;
|
|
@@ -13880,7 +14308,7 @@ class SubcTransportPool {
|
|
|
13880
14308
|
rootCanAttach(root) {
|
|
13881
14309
|
let directoryExists = false;
|
|
13882
14310
|
try {
|
|
13883
|
-
directoryExists =
|
|
14311
|
+
directoryExists = statSync5(root).isDirectory();
|
|
13884
14312
|
} catch {}
|
|
13885
14313
|
if (directoryExists) {
|
|
13886
14314
|
this.dormantRoots.delete(root);
|
|
@@ -14220,6 +14648,7 @@ class SubcTransportPool {
|
|
|
14220
14648
|
return this.rootReapedError(record);
|
|
14221
14649
|
}
|
|
14222
14650
|
async routeRequest(identity, body, timeoutMs, onProgress, expectedGeneration, abortSignal) {
|
|
14651
|
+
const callStartedAt = performance.now();
|
|
14223
14652
|
const root = asCanonicalRootPath(identity.project_root);
|
|
14224
14653
|
let generation = expectedGeneration;
|
|
14225
14654
|
if (this.lifecycleEnabled()) {
|
|
@@ -14272,19 +14701,41 @@ class SubcTransportPool {
|
|
|
14272
14701
|
};
|
|
14273
14702
|
const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
14274
14703
|
const reloadWaitBudgetMs = Math.min(callDeadlineMs, ROUTE_OPEN_RELOAD_WAIT_CEILING_MS);
|
|
14275
|
-
let
|
|
14704
|
+
let scheduledDelayMs = 0;
|
|
14705
|
+
let lastRefusal;
|
|
14706
|
+
const spentMs = () => Math.max(performance.now() - callStartedAt, scheduledDelayMs);
|
|
14707
|
+
const remainingMs = () => callDeadlineMs - spentMs();
|
|
14708
|
+
const openRouteWithinDeadline = async () => {
|
|
14709
|
+
const remaining = remainingMs();
|
|
14710
|
+
if (remaining <= 0)
|
|
14711
|
+
throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
|
|
14712
|
+
let timer;
|
|
14713
|
+
const expired = new Promise((resolve) => {
|
|
14714
|
+
timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
|
|
14715
|
+
});
|
|
14716
|
+
try {
|
|
14717
|
+
const opened = await Promise.race([openRoute(), expired]);
|
|
14718
|
+
if (opened === CALL_DEADLINE_EXPIRED) {
|
|
14719
|
+
throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
|
|
14720
|
+
}
|
|
14721
|
+
return opened;
|
|
14722
|
+
} finally {
|
|
14723
|
+
clearTimeout(timer);
|
|
14724
|
+
}
|
|
14725
|
+
};
|
|
14276
14726
|
const openRouteAfterReloadWindow = async () => {
|
|
14277
14727
|
while (true) {
|
|
14278
14728
|
try {
|
|
14279
|
-
return await
|
|
14729
|
+
return await openRouteWithinDeadline();
|
|
14280
14730
|
} catch (error) {
|
|
14281
14731
|
if (!isRouteOpenReloadWindowError(error))
|
|
14282
14732
|
throw error;
|
|
14283
|
-
|
|
14733
|
+
lastRefusal = error;
|
|
14734
|
+
if (spentMs() + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
14284
14735
|
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
14285
14736
|
}
|
|
14286
14737
|
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
14287
|
-
|
|
14738
|
+
scheduledDelayMs = spentMs() + delayMs;
|
|
14288
14739
|
await wait;
|
|
14289
14740
|
}
|
|
14290
14741
|
}
|
|
@@ -14320,7 +14771,7 @@ class SubcTransportPool {
|
|
|
14320
14771
|
route: routeLabel(entry.handle)
|
|
14321
14772
|
});
|
|
14322
14773
|
};
|
|
14323
|
-
const requestOnRoute = async (route, entry) => {
|
|
14774
|
+
const requestOnRoute = async (route, entry, requestTimeoutMs) => {
|
|
14324
14775
|
this.assertRecordLive(record);
|
|
14325
14776
|
if (abortSignal?.aborted) {
|
|
14326
14777
|
clearRouteEntry(entry);
|
|
@@ -14336,8 +14787,10 @@ class SubcTransportPool {
|
|
|
14336
14787
|
};
|
|
14337
14788
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
14338
14789
|
try {
|
|
14339
|
-
const
|
|
14340
|
-
|
|
14790
|
+
const request = client.request(route, body, {
|
|
14791
|
+
timeoutMs: Math.ceil(requestTimeoutMs),
|
|
14792
|
+
onProgress
|
|
14793
|
+
});
|
|
14341
14794
|
const reply = abortSignal ? await Promise.race([request, aborted]) : await request;
|
|
14342
14795
|
if (!this.isCurrentSession(key, record)) {
|
|
14343
14796
|
if (this.isReapInduced(record))
|
|
@@ -14358,8 +14811,11 @@ class SubcTransportPool {
|
|
|
14358
14811
|
let reopened = false;
|
|
14359
14812
|
let retriedAbsentRoute = false;
|
|
14360
14813
|
while (true) {
|
|
14814
|
+
const requestTimeoutMs = remainingMs();
|
|
14815
|
+
if (requestTimeoutMs <= 0)
|
|
14816
|
+
throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
|
|
14361
14817
|
try {
|
|
14362
|
-
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
|
|
14818
|
+
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry, requestTimeoutMs);
|
|
14363
14819
|
if (reopened)
|
|
14364
14820
|
this.resetRouteReopenBackoff();
|
|
14365
14821
|
return reply;
|
|
@@ -14369,11 +14825,12 @@ class SubcTransportPool {
|
|
|
14369
14825
|
const ownsRoute = this.isCurrentSession(key, record) && this.client === client;
|
|
14370
14826
|
if (ownsRoute && isRouteRequestReloadRefusal(error)) {
|
|
14371
14827
|
clearRouteEntry(routeAndEntry.entry);
|
|
14372
|
-
|
|
14828
|
+
lastRefusal = error;
|
|
14829
|
+
if (spentMs() + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
14373
14830
|
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
14374
14831
|
}
|
|
14375
14832
|
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
14376
|
-
|
|
14833
|
+
scheduledDelayMs = spentMs() + delayMs;
|
|
14377
14834
|
await wait;
|
|
14378
14835
|
routeAndEntry = await openRouteAfterReloadWindow();
|
|
14379
14836
|
reopened = true;
|
|
@@ -14382,7 +14839,12 @@ class SubcTransportPool {
|
|
|
14382
14839
|
if (ownsRoute && !retriedAbsentRoute && isRouteProvenAbsentError(error)) {
|
|
14383
14840
|
retriedAbsentRoute = true;
|
|
14384
14841
|
clearRouteEntry(routeAndEntry.entry);
|
|
14385
|
-
|
|
14842
|
+
if (spentMs() + this.nextRouteReopenDelayMs() >= callDeadlineMs) {
|
|
14843
|
+
throw callDeadlinePassedError(error, callDeadlineMs);
|
|
14844
|
+
}
|
|
14845
|
+
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
14846
|
+
scheduledDelayMs = spentMs() + delayMs;
|
|
14847
|
+
await wait;
|
|
14386
14848
|
routeAndEntry = await openRouteAfterReloadWindow();
|
|
14387
14849
|
reopened = true;
|
|
14388
14850
|
continue;
|
|
@@ -16060,14 +16522,14 @@ function shouldInterruptWaitsForMessage(detachOnUserMessage, operatorText) {
|
|
|
16060
16522
|
return detachOnUserMessage || containsStandaloneDetachKeyword(operatorText);
|
|
16061
16523
|
}
|
|
16062
16524
|
// ../aft-bridge/dist/migration.js
|
|
16063
|
-
import { closeSync as closeSync3, existsSync as existsSync8, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as
|
|
16525
|
+
import { closeSync as closeSync3, existsSync as existsSync8, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync7, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16064
16526
|
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
16065
|
-
import { basename, dirname as
|
|
16527
|
+
import { basename as basename2, dirname as dirname5, join as join10, resolve as resolve6 } from "node:path";
|
|
16066
16528
|
|
|
16067
16529
|
// ../aft-bridge/dist/paths.js
|
|
16068
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as
|
|
16530
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
16069
16531
|
import { homedir as homedir8 } from "node:os";
|
|
16070
|
-
import { dirname as
|
|
16532
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join8, resolve as resolve5 } from "node:path";
|
|
16071
16533
|
function homeDir3() {
|
|
16072
16534
|
if (process.platform === "win32")
|
|
16073
16535
|
return process.env.USERPROFILE || process.env.HOME || homedir8();
|
|
@@ -16127,7 +16589,7 @@ function repairRootScopedStorageFile(storageRoot, harness, fileName) {
|
|
|
16127
16589
|
if (existsSync6(harnessPath) || !existsSync6(rootPath))
|
|
16128
16590
|
return harnessPath;
|
|
16129
16591
|
try {
|
|
16130
|
-
mkdirSync2(
|
|
16592
|
+
mkdirSync2(dirname3(harnessPath), { recursive: true });
|
|
16131
16593
|
renameSync3(rootPath, harnessPath);
|
|
16132
16594
|
} catch {}
|
|
16133
16595
|
return harnessPath;
|
|
@@ -16139,7 +16601,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
|
|
|
16139
16601
|
let lastVersion = "";
|
|
16140
16602
|
try {
|
|
16141
16603
|
if (existsSync6(versionFile)) {
|
|
16142
|
-
lastVersion =
|
|
16604
|
+
lastVersion = readFileSync5(versionFile, "utf-8").trim();
|
|
16143
16605
|
}
|
|
16144
16606
|
} catch {
|
|
16145
16607
|
return false;
|
|
@@ -16148,7 +16610,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
|
|
|
16148
16610
|
return false;
|
|
16149
16611
|
if (!lastVersion) {
|
|
16150
16612
|
try {
|
|
16151
|
-
mkdirSync2(
|
|
16613
|
+
mkdirSync2(dirname3(versionFile), { recursive: true });
|
|
16152
16614
|
writeFileSync2(versionFile, currentVersion);
|
|
16153
16615
|
} catch {}
|
|
16154
16616
|
return false;
|
|
@@ -16160,7 +16622,7 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
|
|
|
16160
16622
|
return;
|
|
16161
16623
|
const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
|
|
16162
16624
|
try {
|
|
16163
|
-
mkdirSync2(
|
|
16625
|
+
mkdirSync2(dirname3(versionFile), { recursive: true });
|
|
16164
16626
|
writeFileSync2(versionFile, currentVersion);
|
|
16165
16627
|
} catch {}
|
|
16166
16628
|
}
|
|
@@ -16209,10 +16671,10 @@ function decodeFileUrl(target) {
|
|
|
16209
16671
|
}
|
|
16210
16672
|
|
|
16211
16673
|
// ../aft-bridge/dist/resolver.js
|
|
16212
|
-
import { closeSync as closeSync2, existsSync as existsSync7, promises as fsPromises, openSync as openSync2, readFileSync as
|
|
16674
|
+
import { closeSync as closeSync2, existsSync as existsSync7, promises as fsPromises, openSync as openSync2, readFileSync as readFileSync6, readSync } from "node:fs";
|
|
16213
16675
|
import { createRequire } from "node:module";
|
|
16214
16676
|
import { homedir as homedir9 } from "node:os";
|
|
16215
|
-
import { delimiter, dirname as
|
|
16677
|
+
import { delimiter, dirname as dirname4, isAbsolute as isAbsolute4, join as join9 } from "node:path";
|
|
16216
16678
|
var ensureBinaryForResolver = ensureBinary;
|
|
16217
16679
|
var npmPlatformPackageReader = null;
|
|
16218
16680
|
var cacheCopiesInFlight = new Map;
|
|
@@ -16365,8 +16827,8 @@ function npmPlatformPackage(ext) {
|
|
|
16365
16827
|
try {
|
|
16366
16828
|
const req = createRequire(import.meta.url);
|
|
16367
16829
|
const manifestPath = req.resolve(`@cortexkit/aft-${platformKey()}/package.json`);
|
|
16368
|
-
const manifest = JSON.parse(
|
|
16369
|
-
const binaryPath = join9(
|
|
16830
|
+
const manifest = JSON.parse(readFileSync6(manifestPath, "utf8"));
|
|
16831
|
+
const binaryPath = join9(dirname4(manifestPath), "bin", `aft${ext}`);
|
|
16370
16832
|
if (typeof manifest.version !== "string" || !existsSync7(binaryPath))
|
|
16371
16833
|
return null;
|
|
16372
16834
|
return { binaryPath, version: normalizeBareVersion(manifest.version) };
|
|
@@ -16620,7 +17082,7 @@ function acquireConfigMigrationLock(lockDir) {
|
|
|
16620
17082
|
if (code !== "EEXIST")
|
|
16621
17083
|
throw err;
|
|
16622
17084
|
try {
|
|
16623
|
-
const ageMs = Date.now() -
|
|
17085
|
+
const ageMs = Date.now() - statSync6(lockDir).mtimeMs;
|
|
16624
17086
|
if (ageMs > 60000) {
|
|
16625
17087
|
rmSync2(lockDir, { recursive: true, force: true });
|
|
16626
17088
|
continue;
|
|
@@ -16634,12 +17096,12 @@ function acquireConfigMigrationLock(lockDir) {
|
|
|
16634
17096
|
}
|
|
16635
17097
|
}
|
|
16636
17098
|
function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
16637
|
-
mkdirSync3(
|
|
16638
|
-
const tmpPath = join10(
|
|
17099
|
+
mkdirSync3(dirname5(targetPath), { recursive: true });
|
|
17100
|
+
const tmpPath = join10(dirname5(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
16639
17101
|
let fd = null;
|
|
16640
17102
|
try {
|
|
16641
17103
|
fd = openSync3(tmpPath, "wx", 384);
|
|
16642
|
-
writeFileSync3(fd,
|
|
17104
|
+
writeFileSync3(fd, readFileSync7(sourcePath));
|
|
16643
17105
|
closeSync3(fd);
|
|
16644
17106
|
fd = null;
|
|
16645
17107
|
renameSync4(tmpPath, targetPath);
|
|
@@ -16656,8 +17118,8 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
|
16656
17118
|
}
|
|
16657
17119
|
}
|
|
16658
17120
|
function atomicWriteConfigFile(targetPath, content) {
|
|
16659
|
-
mkdirSync3(
|
|
16660
|
-
const tmpPath = join10(
|
|
17121
|
+
mkdirSync3(dirname5(targetPath), { recursive: true });
|
|
17122
|
+
const tmpPath = join10(dirname5(targetPath), `.${basename2(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
16661
17123
|
let fd = null;
|
|
16662
17124
|
try {
|
|
16663
17125
|
fd = openSync3(tmpPath, "wx", 384);
|
|
@@ -16718,11 +17180,11 @@ function markLegacySourcesMovedAside(sources, targetPath, logger) {
|
|
|
16718
17180
|
const desiredMarkerPath = `${source.path}${MOVED_MARKER_SUFFIX}`;
|
|
16719
17181
|
const markerPath = nonClobberingSidecarPath(desiredMarkerPath);
|
|
16720
17182
|
try {
|
|
16721
|
-
const original =
|
|
17183
|
+
const original = readFileSync7(source.path, "utf-8");
|
|
16722
17184
|
if (markerPath !== desiredMarkerPath) {
|
|
16723
17185
|
logger?.warn?.(`Preserving existing legacy AFT marker ${desiredMarkerPath}; writing new marker to ${markerPath}`);
|
|
16724
17186
|
}
|
|
16725
|
-
atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath,
|
|
17187
|
+
atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath, basename2(source.path), original));
|
|
16726
17188
|
unlinkSync3(source.path);
|
|
16727
17189
|
info?.(`Moved legacy AFT config ${source.path} aside to ${markerPath}; AFT now reads ${targetPath}`);
|
|
16728
17190
|
} catch (err) {
|
|
@@ -16782,15 +17244,15 @@ function migrateAftConfigFile(opts) {
|
|
|
16782
17244
|
if (existingSources.length === 0) {
|
|
16783
17245
|
return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
|
|
16784
17246
|
}
|
|
16785
|
-
mkdirSync3(
|
|
17247
|
+
mkdirSync3(dirname5(opts.targetPath), { recursive: true });
|
|
16786
17248
|
const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
|
|
16787
17249
|
try {
|
|
16788
17250
|
const sources = existingSources.map((source) => ({
|
|
16789
17251
|
...source,
|
|
16790
|
-
content:
|
|
17252
|
+
content: readFileSync7(source.path, "utf-8")
|
|
16791
17253
|
}));
|
|
16792
17254
|
if (existsSync8(opts.targetPath)) {
|
|
16793
|
-
const targetContent =
|
|
17255
|
+
const targetContent = readFileSync7(opts.targetPath, "utf-8");
|
|
16794
17256
|
for (const source of sources) {
|
|
16795
17257
|
if (fileSemanticsMatch(source.content, targetContent))
|
|
16796
17258
|
continue;
|
|
@@ -16841,11 +17303,11 @@ function spawnErrorLabel(error) {
|
|
|
16841
17303
|
function migrationLogPath(newRoot, harness, logger) {
|
|
16842
17304
|
const desired = join10(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
|
|
16843
17305
|
try {
|
|
16844
|
-
mkdirSync3(
|
|
17306
|
+
mkdirSync3(dirname5(desired), { recursive: true });
|
|
16845
17307
|
return desired;
|
|
16846
17308
|
} catch (err) {
|
|
16847
17309
|
const fallback = join10(tmpdir2(), `aft-migration-${harness}-${Date.now()}.jsonl`);
|
|
16848
|
-
logger?.warn?.(`Failed to create AFT migration log directory ${
|
|
17310
|
+
logger?.warn?.(`Failed to create AFT migration log directory ${dirname5(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
|
|
16849
17311
|
return fallback;
|
|
16850
17312
|
}
|
|
16851
17313
|
}
|
|
@@ -16906,9 +17368,9 @@ async function ensureStorageMigrated(opts) {
|
|
|
16906
17368
|
throw new Error(`AFT storage migration failed (${detail}). ` + `Harness: ${opts.harness}. Legacy: ${legacyRoot}. Target: ${newRoot}. ` + `See log: ${logPath}. ` + `Plugin load aborted to prevent legacy/new state divergence.` + (stderrTail ? ` Stderr tail: ${stderrTail}` : "") + (stdoutTail ? ` Stdout tail: ${stdoutTail}` : ""));
|
|
16907
17369
|
}
|
|
16908
17370
|
// ../aft-bridge/dist/migration-notices.js
|
|
16909
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
17371
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync as renameSync5, rmdirSync, statSync as statSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
16910
17372
|
import { homedir as homedir11 } from "node:os";
|
|
16911
|
-
import { dirname as
|
|
17373
|
+
import { dirname as dirname6, join as join11, resolve as resolve7 } from "node:path";
|
|
16912
17374
|
function migrationNoticeStorePath(env = process.env) {
|
|
16913
17375
|
const stateHome = env.XDG_STATE_HOME && env.XDG_STATE_HOME.length > 0 ? env.XDG_STATE_HOME : join11(homedir11(), ".local", "state");
|
|
16914
17376
|
return join11(stateHome, "cortexkit", "aft", "migration-notices.json");
|
|
@@ -16918,7 +17380,7 @@ function noticeKey(configPath, digest) {
|
|
|
16918
17380
|
}
|
|
16919
17381
|
function readRecords(storePath) {
|
|
16920
17382
|
try {
|
|
16921
|
-
const parsed = JSON.parse(
|
|
17383
|
+
const parsed = JSON.parse(readFileSync8(storePath, "utf8"));
|
|
16922
17384
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
16923
17385
|
} catch {
|
|
16924
17386
|
return {};
|
|
@@ -16927,7 +17389,7 @@ function readRecords(storePath) {
|
|
|
16927
17389
|
var LOCK_STALE_MS = 1e4;
|
|
16928
17390
|
function withStoreLock(storePath, action) {
|
|
16929
17391
|
const lockPath = `${storePath}.lock`;
|
|
16930
|
-
mkdirSync4(
|
|
17392
|
+
mkdirSync4(dirname6(storePath), { recursive: true });
|
|
16931
17393
|
const deadline = Date.now() + 2000;
|
|
16932
17394
|
for (;; ) {
|
|
16933
17395
|
try {
|
|
@@ -16937,7 +17399,7 @@ function withStoreLock(storePath, action) {
|
|
|
16937
17399
|
if (error.code !== "EEXIST")
|
|
16938
17400
|
throw error;
|
|
16939
17401
|
try {
|
|
16940
|
-
if (Date.now() -
|
|
17402
|
+
if (Date.now() - statSync7(lockPath).mtimeMs > LOCK_STALE_MS)
|
|
16941
17403
|
rmdirSync(lockPath);
|
|
16942
17404
|
} catch {}
|
|
16943
17405
|
if (Date.now() > deadline)
|
|
@@ -16978,9 +17440,9 @@ function deliverMigrationNoticeOnce(options) {
|
|
|
16978
17440
|
}
|
|
16979
17441
|
}
|
|
16980
17442
|
// ../aft-bridge/dist/npm-resolver.js
|
|
16981
|
-
import { readdirSync as readdirSync2, statSync as
|
|
17443
|
+
import { readdirSync as readdirSync2, statSync as statSync8 } from "node:fs";
|
|
16982
17444
|
import { homedir as homedir12 } from "node:os";
|
|
16983
|
-
import { dirname as
|
|
17445
|
+
import { dirname as dirname7, isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
16984
17446
|
function defaultDeps() {
|
|
16985
17447
|
return {
|
|
16986
17448
|
platform: process.platform,
|
|
@@ -16994,7 +17456,7 @@ function npmBinaryName(platform) {
|
|
|
16994
17456
|
}
|
|
16995
17457
|
function isFile(p) {
|
|
16996
17458
|
try {
|
|
16997
|
-
return
|
|
17459
|
+
return statSync8(p).isFile();
|
|
16998
17460
|
} catch {
|
|
16999
17461
|
return false;
|
|
17000
17462
|
}
|
|
@@ -17015,7 +17477,7 @@ function npmFromPath(deps) {
|
|
|
17015
17477
|
return null;
|
|
17016
17478
|
}
|
|
17017
17479
|
function npmAdjacentToNode(deps) {
|
|
17018
|
-
const dir =
|
|
17480
|
+
const dir = dirname7(deps.execPath);
|
|
17019
17481
|
return isFile(join12(dir, npmBinaryName(deps.platform))) ? dir : null;
|
|
17020
17482
|
}
|
|
17021
17483
|
function highestVersionedNodeBin(installsDir, name) {
|
|
@@ -17400,8 +17862,8 @@ function probeOnnxRuntimeLoadable(libPath, arch = process.arch) {
|
|
|
17400
17862
|
}
|
|
17401
17863
|
// ../aft-bridge/dist/onnx-runtime.js
|
|
17402
17864
|
import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
|
|
17403
|
-
import { chmodSync as chmodSync2, closeSync as closeSync5, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync5, openSync as openSync5, readdirSync as readdirSync3, readFileSync as
|
|
17404
|
-
import { basename as
|
|
17865
|
+
import { chmodSync as chmodSync2, closeSync as closeSync5, copyFileSync as copyFileSync2, createWriteStream as createWriteStream2, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync5, openSync as openSync5, readdirSync as readdirSync3, readFileSync as readFileSync9, readlinkSync, realpathSync as realpathSync3, renameSync as renameSync6, rmSync as rmSync3, statSync as statSync9, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
17866
|
+
import { basename as basename3, dirname as dirname8, isAbsolute as isAbsolute6, join as join14, relative as relative2, resolve as resolve8, win32 } from "node:path";
|
|
17405
17867
|
import { Readable as Readable2 } from "node:stream";
|
|
17406
17868
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
17407
17869
|
|
|
@@ -17605,7 +18067,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
17605
18067
|
abandoned = true;
|
|
17606
18068
|
} else {
|
|
17607
18069
|
try {
|
|
17608
|
-
const ageMs = Date.now() -
|
|
18070
|
+
const ageMs = Date.now() - statSync9(stagingDir).mtimeMs;
|
|
17609
18071
|
abandoned = ageMs > STALE_LOCK_MS;
|
|
17610
18072
|
} catch {
|
|
17611
18073
|
abandoned = true;
|
|
@@ -17642,7 +18104,7 @@ var REQUIRED_ORT_MAJOR = 1;
|
|
|
17642
18104
|
var REQUIRED_ORT_MIN_MINOR = 20;
|
|
17643
18105
|
var INVALID_ORT_VERSION = "<invalid>";
|
|
17644
18106
|
function parseOnnxVersionFromPath(value) {
|
|
17645
|
-
const name =
|
|
18107
|
+
const name = basename3(value);
|
|
17646
18108
|
const semverish = name.match(/(?:^|[._-])(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)(?:\.(?:dylib|dll))?$/);
|
|
17647
18109
|
if (semverish)
|
|
17648
18110
|
return semverish[1].split(/[-+]/, 1)[0];
|
|
@@ -17847,7 +18309,7 @@ async function downloadFileWithCap(url, destPath) {
|
|
|
17847
18309
|
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
|
|
17848
18310
|
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
|
|
17849
18311
|
}
|
|
17850
|
-
mkdirSync5(
|
|
18312
|
+
mkdirSync5(dirname8(destPath), { recursive: true });
|
|
17851
18313
|
let bytesWritten = 0;
|
|
17852
18314
|
const guard = new TransformStream({
|
|
17853
18315
|
transform(chunk, transformController) {
|
|
@@ -17881,7 +18343,7 @@ function validateExtractedTree(stagingRoot) {
|
|
|
17881
18343
|
const lst = lstatSync(fullPath);
|
|
17882
18344
|
if (lst.isSymbolicLink()) {
|
|
17883
18345
|
const linkTarget = readlinkSync(fullPath);
|
|
17884
|
-
const resolvedTarget = resolve8(
|
|
18346
|
+
const resolvedTarget = resolve8(dirname8(fullPath), linkTarget);
|
|
17885
18347
|
const rel = relative2(realRoot, resolvedTarget);
|
|
17886
18348
|
if (rel.startsWith("..") || isAbsolute6(rel) || win32.isAbsolute(rel)) {
|
|
17887
18349
|
throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
|
|
@@ -18017,7 +18479,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
18017
18479
|
unlinkSync4(dst);
|
|
18018
18480
|
} catch {}
|
|
18019
18481
|
const dstForContainment = join14(targetRoot, link.name);
|
|
18020
|
-
const resolvedTarget = resolve8(
|
|
18482
|
+
const resolvedTarget = resolve8(dirname8(dstForContainment), link.target);
|
|
18021
18483
|
if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
|
|
18022
18484
|
const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
|
|
18023
18485
|
if (requiredLibs.has(link.name)) {
|
|
@@ -18069,9 +18531,9 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
|
|
|
18069
18531
|
function readOnnxInstalledMeta(installDir) {
|
|
18070
18532
|
const path = join14(installDir, ONNX_INSTALLED_META_FILE);
|
|
18071
18533
|
try {
|
|
18072
|
-
if (!
|
|
18534
|
+
if (!statSync9(path).isFile())
|
|
18073
18535
|
return null;
|
|
18074
|
-
const raw =
|
|
18536
|
+
const raw = readFileSync9(path, "utf8");
|
|
18075
18537
|
const parsed = JSON.parse(raw);
|
|
18076
18538
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
18077
18539
|
return null;
|
|
@@ -18087,7 +18549,7 @@ function readOnnxInstalledMeta(installDir) {
|
|
|
18087
18549
|
}
|
|
18088
18550
|
function sha256File2(path) {
|
|
18089
18551
|
const hash = createHash4("sha256");
|
|
18090
|
-
hash.update(
|
|
18552
|
+
hash.update(readFileSync9(path));
|
|
18091
18553
|
return hash.digest("hex");
|
|
18092
18554
|
}
|
|
18093
18555
|
function acquireLock(lockPath) {
|
|
@@ -18115,12 +18577,12 @@ ${new Date().toISOString()}
|
|
|
18115
18577
|
let owningPid = null;
|
|
18116
18578
|
let lockMtimeMs = 0;
|
|
18117
18579
|
try {
|
|
18118
|
-
const raw =
|
|
18580
|
+
const raw = readFileSync9(lockPath, "utf8");
|
|
18119
18581
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
18120
18582
|
const parsed = Number.parseInt(firstLine, 10);
|
|
18121
18583
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
18122
18584
|
owningPid = parsed;
|
|
18123
|
-
lockMtimeMs =
|
|
18585
|
+
lockMtimeMs = statSync9(lockPath).mtimeMs;
|
|
18124
18586
|
} catch {
|
|
18125
18587
|
return tryClaim();
|
|
18126
18588
|
}
|
|
@@ -18140,7 +18602,7 @@ function releaseLock(lockPath) {
|
|
|
18140
18602
|
try {
|
|
18141
18603
|
let owningPid = null;
|
|
18142
18604
|
try {
|
|
18143
|
-
const raw =
|
|
18605
|
+
const raw = readFileSync9(lockPath, "utf8");
|
|
18144
18606
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
18145
18607
|
const parsed = Number.parseInt(firstLine, 10);
|
|
18146
18608
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -19880,7 +20342,7 @@ import {
|
|
|
19880
20342
|
// package.json
|
|
19881
20343
|
var package_default = {
|
|
19882
20344
|
name: "@cortexkit/aft-pi",
|
|
19883
|
-
version: "0.58.
|
|
20345
|
+
version: "0.58.1",
|
|
19884
20346
|
type: "module",
|
|
19885
20347
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
19886
20348
|
main: "dist/index.js",
|
|
@@ -19903,30 +20365,32 @@ var package_default = {
|
|
|
19903
20365
|
"test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
|
|
19904
20366
|
},
|
|
19905
20367
|
dependencies: {
|
|
19906
|
-
"@cortexkit/aft-bridge": "0.58.
|
|
20368
|
+
"@cortexkit/aft-bridge": "0.58.1",
|
|
19907
20369
|
"comment-json": "^5.0.0",
|
|
19908
20370
|
diff: "^8.0.4",
|
|
19909
|
-
typebox: "1.1.38",
|
|
19910
20371
|
zod: "^4.4.3"
|
|
19911
20372
|
},
|
|
19912
20373
|
optionalDependencies: {
|
|
19913
|
-
"@cortexkit/aft-darwin-arm64": "0.58.
|
|
19914
|
-
"@cortexkit/aft-darwin-x64": "0.58.
|
|
19915
|
-
"@cortexkit/aft-linux-arm64": "0.58.
|
|
19916
|
-
"@cortexkit/aft-linux-x64": "0.58.
|
|
19917
|
-
"@cortexkit/aft-win32-arm64": "0.58.
|
|
19918
|
-
"@cortexkit/aft-win32-x64": "0.58.
|
|
20374
|
+
"@cortexkit/aft-darwin-arm64": "0.58.1",
|
|
20375
|
+
"@cortexkit/aft-darwin-x64": "0.58.1",
|
|
20376
|
+
"@cortexkit/aft-linux-arm64": "0.58.1",
|
|
20377
|
+
"@cortexkit/aft-linux-x64": "0.58.1",
|
|
20378
|
+
"@cortexkit/aft-win32-arm64": "0.58.1",
|
|
20379
|
+
"@cortexkit/aft-win32-x64": "0.58.1"
|
|
19919
20380
|
},
|
|
19920
20381
|
devDependencies: {
|
|
19921
20382
|
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
19922
20383
|
"@earendil-works/pi-ai": "^0.80.2",
|
|
19923
20384
|
"@earendil-works/pi-tui": "^0.80.2",
|
|
19924
20385
|
"@types/node": "^22.0.0",
|
|
20386
|
+
typebox: "1.1.38",
|
|
19925
20387
|
typescript: "^5.8.0"
|
|
19926
20388
|
},
|
|
19927
20389
|
peerDependencies: {
|
|
20390
|
+
"@earendil-works/pi-ai": "*",
|
|
19928
20391
|
"@earendil-works/pi-coding-agent": "*",
|
|
19929
|
-
"@earendil-works/pi-tui": "*"
|
|
20392
|
+
"@earendil-works/pi-tui": "*",
|
|
20393
|
+
typebox: "*"
|
|
19930
20394
|
},
|
|
19931
20395
|
exports: {
|
|
19932
20396
|
".": {
|
|
@@ -20623,7 +21087,7 @@ function registerStatusCommand(pi, ctx) {
|
|
|
20623
21087
|
}
|
|
20624
21088
|
|
|
20625
21089
|
// src/config.ts
|
|
20626
|
-
import { existsSync as existsSync13, readFileSync as
|
|
21090
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
20627
21091
|
import { createRequire as createRequire2 } from "node:module";
|
|
20628
21092
|
import { homedir as homedir13 } from "node:os";
|
|
20629
21093
|
import { isAbsolute as isAbsolute7 } from "node:path";
|
|
@@ -25436,7 +25900,7 @@ var IndexConfigSchema = object({
|
|
|
25436
25900
|
roots: array(IndexRootSchema).optional()
|
|
25437
25901
|
});
|
|
25438
25902
|
var SemanticConfigSchema = object({
|
|
25439
|
-
backend: _enum(["fastembed", "openai_compatible", "ollama"]).optional(),
|
|
25903
|
+
backend: _enum(["fastembed", "openai_compatible", "ollama", "synapse"]).optional(),
|
|
25440
25904
|
model: string2().trim().min(1).optional(),
|
|
25441
25905
|
base_url: string2().trim().min(1).optional(),
|
|
25442
25906
|
api_key_env: string2().trim().min(1).optional(),
|
|
@@ -25447,6 +25911,17 @@ var SemanticConfigSchema = object({
|
|
|
25447
25911
|
max_input_tokens: number2().int().positive().optional(),
|
|
25448
25912
|
max_files: number2().int().positive().optional()
|
|
25449
25913
|
});
|
|
25914
|
+
var RerankConfigSchema = object({
|
|
25915
|
+
backend: _enum(["off", "onnx", "remote", "synapse"]).optional(),
|
|
25916
|
+
model: string2().trim().min(1).optional(),
|
|
25917
|
+
endpoint: string2().trim().min(1).optional(),
|
|
25918
|
+
api_key_env: string2().trim().min(1).optional(),
|
|
25919
|
+
top_n: number2().int().positive().optional(),
|
|
25920
|
+
timeout_ms: number2().int().positive().optional()
|
|
25921
|
+
});
|
|
25922
|
+
var SearchConfigSchema = object({
|
|
25923
|
+
rerank: RerankConfigSchema.optional()
|
|
25924
|
+
});
|
|
25450
25925
|
var LspExtensionSchema = string2().trim().min(1).refine((value) => value.replace(/^\.+/, "").length > 0, {
|
|
25451
25926
|
message: "Extension must include characters other than leading dots"
|
|
25452
25927
|
});
|
|
@@ -25582,6 +26057,7 @@ var AftConfigFieldsSchema = object({
|
|
|
25582
26057
|
lsp: LspConfigSchema.optional(),
|
|
25583
26058
|
url_fetch_allow_private: boolean2().optional(),
|
|
25584
26059
|
semantic: SemanticConfigSchema.optional(),
|
|
26060
|
+
search: SearchConfigSchema.optional(),
|
|
25585
26061
|
bridge: BridgeConfigSchema.optional(),
|
|
25586
26062
|
subc: SubcConfigSchema.optional(),
|
|
25587
26063
|
github: GithubConfigSchema.optional(),
|
|
@@ -25729,7 +26205,7 @@ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 })
|
|
|
25729
26205
|
let tmpPath = null;
|
|
25730
26206
|
let oldKeys = [];
|
|
25731
26207
|
try {
|
|
25732
|
-
const content =
|
|
26208
|
+
const content = readFileSync10(configPath, "utf-8");
|
|
25733
26209
|
const rawConfig = import_comment_json.parse(content);
|
|
25734
26210
|
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
25735
26211
|
return { migrated: false, oldKeys: [] };
|
|
@@ -25764,6 +26240,18 @@ ${serialized}` : serialized;
|
|
|
25764
26240
|
}
|
|
25765
26241
|
}
|
|
25766
26242
|
var configLoadErrors = [];
|
|
26243
|
+
var configValidationErrors = [];
|
|
26244
|
+
var configLoadSources = [];
|
|
26245
|
+
var configLoadTexts = new Map;
|
|
26246
|
+
function getConfigLoadSources() {
|
|
26247
|
+
return configLoadSources;
|
|
26248
|
+
}
|
|
26249
|
+
function getConfigLoadTexts() {
|
|
26250
|
+
return configLoadTexts;
|
|
26251
|
+
}
|
|
26252
|
+
function getConfigValidationErrors() {
|
|
26253
|
+
return configValidationErrors;
|
|
26254
|
+
}
|
|
25767
26255
|
function getConfigLoadErrors() {
|
|
25768
26256
|
return configLoadErrors;
|
|
25769
26257
|
}
|
|
@@ -25808,7 +26296,9 @@ function loadConfigFromPath(configPath, tier) {
|
|
|
25808
26296
|
try {
|
|
25809
26297
|
if (!existsSync13(configPath))
|
|
25810
26298
|
return null;
|
|
25811
|
-
const content =
|
|
26299
|
+
const content = readFileSync10(configPath, "utf-8");
|
|
26300
|
+
configLoadSources.push(configPath);
|
|
26301
|
+
configLoadTexts.set(configPath, content);
|
|
25812
26302
|
const rawConfig = import_comment_json.parse(content);
|
|
25813
26303
|
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
25814
26304
|
recordConfigParseFailure(configPath, "root must be an object");
|
|
@@ -25858,6 +26348,7 @@ function loadConfigFromPath(configPath, tier) {
|
|
|
25858
26348
|
} else {
|
|
25859
26349
|
const errorMsg = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
|
|
25860
26350
|
warn2(`Config validation error in ${configPath}: ${errorMsg}`);
|
|
26351
|
+
configValidationErrors.push({ path: configPath, message: errorMsg });
|
|
25861
26352
|
parsed = parseConfigPartially(cleanConfig);
|
|
25862
26353
|
}
|
|
25863
26354
|
if (tier === "user" && parsed.disabled_tools === undefined) {
|
|
@@ -26068,14 +26559,33 @@ function getStrippedTopLevelKeys(override) {
|
|
|
26068
26559
|
for (const tool of partitionProjectDisables(override.disabled_tools).ignored) {
|
|
26069
26560
|
stripped.push(`disabled_tools.${tool}`);
|
|
26070
26561
|
}
|
|
26562
|
+
stripped.push(...projectRerankStrippedKeys(override.search?.rerank));
|
|
26071
26563
|
return stripped;
|
|
26072
26564
|
}
|
|
26565
|
+
function projectRerankStrippedKeys(rerank) {
|
|
26566
|
+
if (rerank === undefined)
|
|
26567
|
+
return [];
|
|
26568
|
+
const stripped = [];
|
|
26569
|
+
if (rerank.backend !== undefined && rerank.backend !== "off")
|
|
26570
|
+
stripped.push("search.rerank.backend");
|
|
26571
|
+
for (const key of ["model", "endpoint", "api_key_env", "top_n", "timeout_ms"]) {
|
|
26572
|
+
if (rerank[key] !== undefined)
|
|
26573
|
+
stripped.push(`search.rerank.${key}`);
|
|
26574
|
+
}
|
|
26575
|
+
return stripped;
|
|
26576
|
+
}
|
|
26577
|
+
function mergeProjectSearchConfig(base, project) {
|
|
26578
|
+
if (project?.rerank?.backend !== "off")
|
|
26579
|
+
return base;
|
|
26580
|
+
return { ...base, rerank: { ...base?.rerank, backend: "off" } };
|
|
26581
|
+
}
|
|
26073
26582
|
function mergeConfigs(base, override) {
|
|
26074
26583
|
const disabledTools = unionDisabledTools(base.disabled_tools, partitionProjectDisables(override.disabled_tools).accepted);
|
|
26075
26584
|
const indexes = mergeIndexes(base.indexes, override.indexes, true);
|
|
26076
26585
|
const formatter = { ...base.formatter, ...override.formatter };
|
|
26077
26586
|
const checker = { ...base.checker, ...override.checker };
|
|
26078
26587
|
const semantic = mergeSemanticConfig(base.semantic, override.semantic);
|
|
26588
|
+
const search = mergeProjectSearchConfig(base.search, override.search);
|
|
26079
26589
|
const lsp = mergeLspConfig(base.lsp, override.lsp);
|
|
26080
26590
|
const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
|
|
26081
26591
|
const bash = mergeBashConfig(base.bash, override.bash);
|
|
@@ -26105,6 +26615,7 @@ function mergeConfigs(base, override) {
|
|
|
26105
26615
|
...pi !== undefined ? { pi } : {},
|
|
26106
26616
|
experimental,
|
|
26107
26617
|
semantic,
|
|
26618
|
+
search,
|
|
26108
26619
|
...bridge !== undefined ? { bridge } : {},
|
|
26109
26620
|
...indexes !== undefined ? { indexes } : {},
|
|
26110
26621
|
...disabledTools !== undefined ? { disabled_tools: disabledTools } : {}
|
|
@@ -26163,6 +26674,9 @@ function buildConfigTierConfigureParams(projectDirectory, processState = {}) {
|
|
|
26163
26674
|
}
|
|
26164
26675
|
function loadAftConfig(projectDirectory) {
|
|
26165
26676
|
configLoadErrors = [];
|
|
26677
|
+
configValidationErrors = [];
|
|
26678
|
+
configLoadSources = [];
|
|
26679
|
+
configLoadTexts = new Map;
|
|
26166
26680
|
configLoadNotices = [];
|
|
26167
26681
|
semanticInputSupplied = false;
|
|
26168
26682
|
const { userConfigPath, projectConfigPath } = resolveAftConfigPaths(projectDirectory);
|
|
@@ -26213,10 +26727,10 @@ import {
|
|
|
26213
26727
|
createReadStream as createReadStream2,
|
|
26214
26728
|
existsSync as existsSync15,
|
|
26215
26729
|
mkdirSync as mkdirSync7,
|
|
26216
|
-
readFileSync as
|
|
26730
|
+
readFileSync as readFileSync13,
|
|
26217
26731
|
renameSync as renameSync9,
|
|
26218
26732
|
rmSync as rmSync5,
|
|
26219
|
-
statSync as
|
|
26733
|
+
statSync as statSync11,
|
|
26220
26734
|
writeFileSync as writeFileSync8
|
|
26221
26735
|
} from "node:fs";
|
|
26222
26736
|
import { join as join17 } from "node:path";
|
|
@@ -26227,10 +26741,10 @@ import {
|
|
|
26227
26741
|
closeSync as closeSync6,
|
|
26228
26742
|
mkdirSync as mkdirSync6,
|
|
26229
26743
|
openSync as openSync6,
|
|
26230
|
-
readFileSync as
|
|
26744
|
+
readFileSync as readFileSync11,
|
|
26231
26745
|
renameSync as renameSync8,
|
|
26232
26746
|
rmSync as rmSync4,
|
|
26233
|
-
statSync as
|
|
26747
|
+
statSync as statSync10,
|
|
26234
26748
|
unlinkSync as unlinkSync6,
|
|
26235
26749
|
writeFileSync as writeFileSync7
|
|
26236
26750
|
} from "node:fs";
|
|
@@ -26253,7 +26767,7 @@ function lspBinDir(npmPackage) {
|
|
|
26253
26767
|
function isInstalled(npmPackage, binary) {
|
|
26254
26768
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
26255
26769
|
try {
|
|
26256
|
-
if (
|
|
26770
|
+
if (statSync10(join15(lspBinDir(npmPackage), candidate)).isFile())
|
|
26257
26771
|
return true;
|
|
26258
26772
|
} catch {}
|
|
26259
26773
|
}
|
|
@@ -26281,9 +26795,9 @@ function writeInstalledMetaIn(installDir, version, sha256) {
|
|
|
26281
26795
|
function readInstalledMetaIn(installDir) {
|
|
26282
26796
|
const path = join15(installDir, INSTALLED_META_FILE);
|
|
26283
26797
|
try {
|
|
26284
|
-
if (!
|
|
26798
|
+
if (!statSync10(path).isFile())
|
|
26285
26799
|
return null;
|
|
26286
|
-
const raw =
|
|
26800
|
+
const raw = readFileSync11(path, "utf8");
|
|
26287
26801
|
const parsed = JSON.parse(raw);
|
|
26288
26802
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
26289
26803
|
return null;
|
|
@@ -26352,12 +26866,12 @@ ${token}
|
|
|
26352
26866
|
let owningPid = null;
|
|
26353
26867
|
let lockMtimeMs = 0;
|
|
26354
26868
|
try {
|
|
26355
|
-
const raw =
|
|
26869
|
+
const raw = readFileSync11(lock, "utf8");
|
|
26356
26870
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
26357
26871
|
const parsed = Number.parseInt(firstLine, 10);
|
|
26358
26872
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
26359
26873
|
owningPid = parsed;
|
|
26360
|
-
lockMtimeMs =
|
|
26874
|
+
lockMtimeMs = statSync10(lock).mtimeMs;
|
|
26361
26875
|
} catch {
|
|
26362
26876
|
return tryClaim();
|
|
26363
26877
|
}
|
|
@@ -26391,7 +26905,7 @@ function releaseInstallLock(lockKey, acquisitionToken) {
|
|
|
26391
26905
|
let owningPid = null;
|
|
26392
26906
|
let owningToken = "";
|
|
26393
26907
|
try {
|
|
26394
|
-
const raw =
|
|
26908
|
+
const raw = readFileSync11(lock, "utf8");
|
|
26395
26909
|
const lines = raw.split(/\r?\n/);
|
|
26396
26910
|
const parsed = Number.parseInt(lines[0]?.trim() ?? "", 10);
|
|
26397
26911
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -26438,7 +26952,7 @@ function autoInstallStampPath() {
|
|
|
26438
26952
|
}
|
|
26439
26953
|
function hasRecentAutoInstallStamp(path) {
|
|
26440
26954
|
try {
|
|
26441
|
-
const parsed = JSON.parse(
|
|
26955
|
+
const parsed = JSON.parse(readFileSync11(path, "utf8"));
|
|
26442
26956
|
return typeof parsed.lastRunMs === "number" && Number.isFinite(parsed.lastRunMs) && Math.abs(Date.now() - parsed.lastRunMs) < AUTO_INSTALL_WINDOW_MS;
|
|
26443
26957
|
} catch {
|
|
26444
26958
|
return false;
|
|
@@ -26446,7 +26960,7 @@ function hasRecentAutoInstallStamp(path) {
|
|
|
26446
26960
|
}
|
|
26447
26961
|
function readAutoInstallLockOwner(path) {
|
|
26448
26962
|
try {
|
|
26449
|
-
const parsed = JSON.parse(
|
|
26963
|
+
const parsed = JSON.parse(readFileSync11(path, "utf8"));
|
|
26450
26964
|
if (typeof parsed.pid !== "number" || typeof parsed.startedMs !== "number" || typeof parsed.token !== "string") {
|
|
26451
26965
|
return null;
|
|
26452
26966
|
}
|
|
@@ -26459,7 +26973,7 @@ function autoInstallLockIsStale(path) {
|
|
|
26459
26973
|
const owner = readAutoInstallLockOwner(path);
|
|
26460
26974
|
let age = Number.POSITIVE_INFINITY;
|
|
26461
26975
|
try {
|
|
26462
|
-
age = Math.abs(Date.now() -
|
|
26976
|
+
age = Math.abs(Date.now() - statSync10(path).mtimeMs);
|
|
26463
26977
|
} catch {
|
|
26464
26978
|
return true;
|
|
26465
26979
|
}
|
|
@@ -26537,7 +27051,7 @@ var VERSION_CHECK_FILE = ".aft-version-check";
|
|
|
26537
27051
|
function readVersionCheck(npmPackage) {
|
|
26538
27052
|
const file = join15(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
26539
27053
|
try {
|
|
26540
|
-
const raw =
|
|
27054
|
+
const raw = readFileSync11(file, "utf8");
|
|
26541
27055
|
const parsed = JSON.parse(raw);
|
|
26542
27056
|
if (typeof parsed.last_checked === "string") {
|
|
26543
27057
|
return {
|
|
@@ -26640,6 +27154,13 @@ var NPM_LSP_TABLE = [
|
|
|
26640
27154
|
extensions: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"],
|
|
26641
27155
|
rootMarkers: ["tsconfig.json", "jsconfig.json", "package.json"]
|
|
26642
27156
|
},
|
|
27157
|
+
{
|
|
27158
|
+
id: "typescript-sdk",
|
|
27159
|
+
npm: "typescript",
|
|
27160
|
+
binary: "tsserver",
|
|
27161
|
+
extensions: ["ts", "tsx", "js", "jsx", "mjs", "cjs", "mts", "cts"],
|
|
27162
|
+
rootMarkers: ["tsconfig.json", "jsconfig.json", "package.json"]
|
|
27163
|
+
},
|
|
26643
27164
|
{
|
|
26644
27165
|
id: "python",
|
|
26645
27166
|
npm: "pyright",
|
|
@@ -26714,7 +27235,7 @@ var NPM_LSP_TABLE = [
|
|
|
26714
27235
|
];
|
|
26715
27236
|
|
|
26716
27237
|
// src/lsp-project-relevance.ts
|
|
26717
|
-
import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as
|
|
27238
|
+
import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
|
|
26718
27239
|
import { join as join16 } from "node:path";
|
|
26719
27240
|
var MAX_WALK_DIRS = 200;
|
|
26720
27241
|
var MAX_WALK_DEPTH = 4;
|
|
@@ -26756,7 +27277,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
|
|
|
26756
27277
|
}
|
|
26757
27278
|
function readPackageJson(projectRoot) {
|
|
26758
27279
|
try {
|
|
26759
|
-
const raw =
|
|
27280
|
+
const raw = readFileSync12(join16(projectRoot, "package.json"), "utf8");
|
|
26760
27281
|
const parsed = JSON.parse(raw);
|
|
26761
27282
|
if (typeof parsed !== "object" || parsed === null)
|
|
26762
27283
|
return null;
|
|
@@ -27104,7 +27625,7 @@ function hashInstalledBinary(spec) {
|
|
|
27104
27625
|
let pathToHash = null;
|
|
27105
27626
|
for (const p of candidates) {
|
|
27106
27627
|
try {
|
|
27107
|
-
if (
|
|
27628
|
+
if (statSync11(p).isFile()) {
|
|
27108
27629
|
pathToHash = p;
|
|
27109
27630
|
break;
|
|
27110
27631
|
}
|
|
@@ -27130,14 +27651,14 @@ function installedBinaryPath(spec) {
|
|
|
27130
27651
|
] : [lspBinaryPath(spec.npm, spec.binary)];
|
|
27131
27652
|
for (const candidate of candidates) {
|
|
27132
27653
|
try {
|
|
27133
|
-
if (
|
|
27654
|
+
if (statSync11(candidate).isFile())
|
|
27134
27655
|
return candidate;
|
|
27135
27656
|
} catch {}
|
|
27136
27657
|
}
|
|
27137
27658
|
return null;
|
|
27138
27659
|
}
|
|
27139
27660
|
function sha256OfFileSync(path) {
|
|
27140
|
-
return createHash5("sha256").update(
|
|
27661
|
+
return createHash5("sha256").update(readFileSync13(path)).digest("hex");
|
|
27141
27662
|
}
|
|
27142
27663
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
27143
27664
|
const packageDir = lspPackageDir(spec.npm);
|
|
@@ -27180,7 +27701,7 @@ function runAutoInstall(projectRoot, config, fetchImpl = fetch) {
|
|
|
27180
27701
|
if (isInstalled(spec.npm, spec.binary) && validateCachedNpmInstall(spec)) {
|
|
27181
27702
|
cachedBinDirs.push(lspBinDir(spec.npm));
|
|
27182
27703
|
}
|
|
27183
|
-
if (config.disabled.has(spec.id)) {
|
|
27704
|
+
if (config.disabled.has(spec.id) || spec.id === "typescript-sdk" && config.disabled.has("typescript")) {
|
|
27184
27705
|
skipped.push({ id: spec.id, reason: "disabled by config" });
|
|
27185
27706
|
continue;
|
|
27186
27707
|
}
|
|
@@ -27235,16 +27756,16 @@ import {
|
|
|
27235
27756
|
lstatSync as lstatSync2,
|
|
27236
27757
|
mkdirSync as mkdirSync8,
|
|
27237
27758
|
readdirSync as readdirSync5,
|
|
27238
|
-
readFileSync as
|
|
27759
|
+
readFileSync as readFileSync14,
|
|
27239
27760
|
readlinkSync as readlinkSync2,
|
|
27240
27761
|
realpathSync as realpathSync4,
|
|
27241
27762
|
renameSync as renameSync10,
|
|
27242
27763
|
rmSync as rmSync6,
|
|
27243
|
-
statSync as
|
|
27764
|
+
statSync as statSync12,
|
|
27244
27765
|
unlinkSync as unlinkSync7,
|
|
27245
27766
|
writeFileSync as writeFileSync9
|
|
27246
27767
|
} from "node:fs";
|
|
27247
|
-
import { dirname as
|
|
27768
|
+
import { dirname as dirname9, join as join18, relative as relative3, resolve as resolve9 } from "node:path";
|
|
27248
27769
|
import { Readable as Readable3 } from "node:stream";
|
|
27249
27770
|
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
27250
27771
|
|
|
@@ -27353,7 +27874,7 @@ function installFailureMarkerPath(spec) {
|
|
|
27353
27874
|
}
|
|
27354
27875
|
function readInstallFailureMarker(spec) {
|
|
27355
27876
|
try {
|
|
27356
|
-
const marker = JSON.parse(
|
|
27877
|
+
const marker = JSON.parse(readFileSync14(installFailureMarkerPath(spec), "utf8"));
|
|
27357
27878
|
if (typeof marker.release !== "string" || typeof marker.sha256 !== "string" || typeof marker.error !== "string" || typeof marker.at !== "string" || !Number.isFinite(Date.parse(marker.at))) {
|
|
27358
27879
|
return null;
|
|
27359
27880
|
}
|
|
@@ -27367,7 +27888,7 @@ function writeInstallFailureMarker(spec, release, sha256, installError) {
|
|
|
27367
27888
|
const markerError = installError.replace(/\s+/g, " ").trim();
|
|
27368
27889
|
const tempPath = `${path}.tmp-${process.pid}-${randomBytes3(6).toString("hex")}`;
|
|
27369
27890
|
try {
|
|
27370
|
-
mkdirSync8(
|
|
27891
|
+
mkdirSync8(dirname9(path), { recursive: true });
|
|
27371
27892
|
writeFileSync9(tempPath, `${JSON.stringify({ release, sha256, error: markerError, at: new Date().toISOString() })}
|
|
27372
27893
|
`, { encoding: "utf8", mode: 384 });
|
|
27373
27894
|
renameSync10(tempPath, path);
|
|
@@ -27396,7 +27917,7 @@ function ghBinaryPath(spec, platform) {
|
|
|
27396
27917
|
function isGithubInstalled(spec, platform) {
|
|
27397
27918
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
27398
27919
|
try {
|
|
27399
|
-
if (
|
|
27920
|
+
if (statSync12(join18(ghBinDir(spec), candidate)).isFile())
|
|
27400
27921
|
return true;
|
|
27401
27922
|
} catch {}
|
|
27402
27923
|
}
|
|
@@ -27410,9 +27931,9 @@ function ghBinaryCandidates(spec, platform) {
|
|
|
27410
27931
|
function readGithubInstalledMetaIn(installDir) {
|
|
27411
27932
|
try {
|
|
27412
27933
|
const path = join18(installDir, INSTALLED_META_FILE2);
|
|
27413
|
-
if (!
|
|
27934
|
+
if (!statSync12(path).isFile())
|
|
27414
27935
|
return null;
|
|
27415
|
-
const parsed = JSON.parse(
|
|
27936
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
27416
27937
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
27417
27938
|
return null;
|
|
27418
27939
|
return {
|
|
@@ -27453,7 +27974,7 @@ function sha256OfFile(path) {
|
|
|
27453
27974
|
});
|
|
27454
27975
|
}
|
|
27455
27976
|
function sha256OfFileSync2(path) {
|
|
27456
|
-
return createHash6("sha256").update(
|
|
27977
|
+
return createHash6("sha256").update(readFileSync14(path)).digest("hex");
|
|
27457
27978
|
}
|
|
27458
27979
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
|
|
27459
27980
|
const candidates = [];
|
|
@@ -27629,7 +28150,7 @@ async function downloadFile(url, destPath, fetchImpl, assetSize, signal) {
|
|
|
27629
28150
|
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES3) {
|
|
27630
28151
|
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES3}`);
|
|
27631
28152
|
}
|
|
27632
|
-
mkdirSync8(
|
|
28153
|
+
mkdirSync8(dirname9(destPath), { recursive: true });
|
|
27633
28154
|
let bytesWritten = 0;
|
|
27634
28155
|
const guard = new TransformStream({
|
|
27635
28156
|
transform(chunk, controller) {
|
|
@@ -27799,7 +28320,7 @@ function quarantineCachedGithubInstall(spec, reason) {
|
|
|
27799
28320
|
const dest = join18(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
|
|
27800
28321
|
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
27801
28322
|
try {
|
|
27802
|
-
mkdirSync8(
|
|
28323
|
+
mkdirSync8(dirname9(dest), { recursive: true });
|
|
27803
28324
|
rmSync6(dest, { recursive: true, force: true });
|
|
27804
28325
|
renameSync10(packageDir, dest);
|
|
27805
28326
|
} catch (err) {
|
|
@@ -27811,7 +28332,7 @@ function validateCachedGithubInstall(spec, platform) {
|
|
|
27811
28332
|
const meta = readGithubInstalledMetaIn(packageDir);
|
|
27812
28333
|
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join18(ghBinDir(spec), candidate)).find((candidate) => {
|
|
27813
28334
|
try {
|
|
27814
|
-
return
|
|
28335
|
+
return statSync12(candidate).isFile();
|
|
27815
28336
|
} catch {
|
|
27816
28337
|
return false;
|
|
27817
28338
|
}
|
|
@@ -27929,7 +28450,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
27929
28450
|
return { ok: false, sha256: archiveSha256, error: message };
|
|
27930
28451
|
}
|
|
27931
28452
|
const targetBinary = ghBinaryPath(spec, platform);
|
|
27932
|
-
mkdirSync8(
|
|
28453
|
+
mkdirSync8(dirname9(targetBinary), { recursive: true });
|
|
27933
28454
|
try {
|
|
27934
28455
|
copyFileSync3(innerBinaryPath, targetBinary);
|
|
27935
28456
|
if (platform !== "win32") {
|
|
@@ -28694,7 +29215,7 @@ var ISSUE_AND_PR_READ_DESCRIPTION = "GitHub issues and pull requests can be read
|
|
|
28694
29215
|
function whenGhReadEnabled(enabled, description) {
|
|
28695
29216
|
return enabled ? description : "";
|
|
28696
29217
|
}
|
|
28697
|
-
var READ_DESCRIPTION = "Read file contents with line numbers. Backed by AFT's indexed Rust reader — faster than the built-in `read` on large repos. Images are returned as attachments on vision-capable models; PDFs and non-vision models are not yet supported.";
|
|
29218
|
+
var READ_DESCRIPTION = "Read file contents with line numbers or sorted directory entries. Use startLine/endLine or 1-based offset/limit for either. Directory limit defaults to and is capped at 1000; enumeration stops at 10,000 entries and partial listings carry a shown/total trailer. Backed by AFT's indexed Rust reader — faster than the built-in `read` on large repos. Images are returned as attachments on vision-capable models; PDFs and non-vision models are not yet supported.";
|
|
28698
29219
|
function readDescription(ghReadEnabled) {
|
|
28699
29220
|
const githubDescription = whenGhReadEnabled(ghReadEnabled, ISSUE_AND_PR_READ_DESCRIPTION);
|
|
28700
29221
|
return githubDescription ? `${READ_DESCRIPTION} ${githubDescription}` : READ_DESCRIPTION;
|
|
@@ -28790,12 +29311,12 @@ async function assertExternalDirectoryPermission(extCtx, target, options = {}) {
|
|
|
28790
29311
|
}
|
|
28791
29312
|
var ReadParams = Type2.Object({
|
|
28792
29313
|
path: Type2.String({
|
|
28793
|
-
description: "Path to the file to read (absolute or relative to project root)"
|
|
29314
|
+
description: "Path to the file or directory to read (absolute or relative to project root)"
|
|
28794
29315
|
}),
|
|
28795
|
-
startLine: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line to start reading from"),
|
|
28796
|
-
endLine: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line to stop reading at (inclusive)"),
|
|
28797
|
-
limit: optionalInt(1, Number.MAX_SAFE_INTEGER, "
|
|
28798
|
-
offset: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line
|
|
29316
|
+
startLine: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line or directory entry to start reading from"),
|
|
29317
|
+
endLine: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line or directory entry to stop reading at (inclusive)"),
|
|
29318
|
+
limit: optionalInt(1, Number.MAX_SAFE_INTEGER, "Max lines (default: 2000) or directory entries (default and cap: 1000) to return"),
|
|
29319
|
+
offset: optionalInt(1, Number.MAX_SAFE_INTEGER, "1-based line or directory entry to start reading from (use with limit). Ignored if startLine is provided")
|
|
28799
29320
|
});
|
|
28800
29321
|
var WriteParams = Type2.Object({
|
|
28801
29322
|
path: Type2.String({
|
|
@@ -28930,7 +29451,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
28930
29451
|
name: readName,
|
|
28931
29452
|
label: readName,
|
|
28932
29453
|
description: readDescription(resolveGithubConfig(ctx.config).read),
|
|
28933
|
-
promptSnippet: "Read
|
|
29454
|
+
promptSnippet: "Read files or directories (supports offset/limit for either)",
|
|
28934
29455
|
promptGuidelines: [`Use ${readName} to examine files instead of cat or sed.`],
|
|
28935
29456
|
parameters: ReadParams,
|
|
28936
29457
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
@@ -30105,7 +30626,7 @@ A notification will fire when the pattern matches or the task exits.`, watchDeta
|
|
|
30105
30626
|
const effectiveWaitMs = workerForcedSync ? syncWaitCap : resolveWatchTimeoutMs(coerceConfiguredWatchTimeout(params.timeout_ms, syncWaitCap), role, syncWaitCap);
|
|
30106
30627
|
const data = await waitForBashStatus(ctx, bridge, extCtx, params.task_id, undefined, waitFor, true, effectiveWaitMs);
|
|
30107
30628
|
if (data.waited?.reason === "user_message") {
|
|
30108
|
-
const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, coerceBoolean(params.once, true));
|
|
30629
|
+
const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, coerceBoolean(params.once, true), data.waited.elapsed_ms);
|
|
30109
30630
|
return textResult(convertedText, { waited: data.waited });
|
|
30110
30631
|
}
|
|
30111
30632
|
const text = await formatBashStatus(extCtx, params.task_id, data, undefined, { role, capMs: syncWaitCap });
|
|
@@ -30113,9 +30634,10 @@ A notification will fire when the pattern matches or the task exits.`, watchDeta
|
|
|
30113
30634
|
}
|
|
30114
30635
|
};
|
|
30115
30636
|
}
|
|
30116
|
-
async function convertToAsyncWatchOnAbort(bridge, extCtx, taskId, waitFor, once) {
|
|
30637
|
+
async function convertToAsyncWatchOnAbort(bridge, extCtx, taskId, waitFor, once, elapsedMs) {
|
|
30638
|
+
const interrupted = `Sync watch for task ${taskId} was interrupted because you sent a message after ${elapsedMs}ms of waiting. `;
|
|
30117
30639
|
if (!waitFor) {
|
|
30118
|
-
return
|
|
30640
|
+
return interrupted + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits; don't poll bash_status.`;
|
|
30119
30641
|
}
|
|
30120
30642
|
const notifyParams = {
|
|
30121
30643
|
task_id: taskId,
|
|
@@ -30131,12 +30653,12 @@ async function convertToAsyncWatchOnAbort(bridge, extCtx, taskId, waitFor, once)
|
|
|
30131
30653
|
const registered = await callBashBridge(bridge, "bash_notify", notifyParams, extCtx);
|
|
30132
30654
|
if (registered.success === false) {
|
|
30133
30655
|
unmarkExplicitControl(sessionId, taskId);
|
|
30134
|
-
return
|
|
30656
|
+
return interrupted + `Auto-registering an async watch failed (${String(registered.message ?? "unknown error")}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
|
|
30135
30657
|
}
|
|
30136
|
-
return
|
|
30658
|
+
return interrupted + `The wait has been converted to an async watch (${registered.watch_id}). ` + `A notification will fire when the pattern matches or the task exits.`;
|
|
30137
30659
|
} catch (err) {
|
|
30138
30660
|
unmarkExplicitControl(sessionId, taskId);
|
|
30139
|
-
return
|
|
30661
|
+
return interrupted + `Auto-registering an async watch failed (${err instanceof Error ? err.message : String(err)}). ` + `The task is still running in the background. A completion reminder will be ` + `delivered automatically when the task exits.`;
|
|
30140
30662
|
}
|
|
30141
30663
|
}
|
|
30142
30664
|
function createBashWriteTool(ctx) {
|
|
@@ -30208,8 +30730,9 @@ async function bashStatusSnapshot(bridge, extCtx, taskId, outputMode, options, c
|
|
|
30208
30730
|
}, extCtx, options);
|
|
30209
30731
|
}
|
|
30210
30732
|
async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFor, waitForExit, effectiveWaitMs) {
|
|
30211
|
-
const startedAt =
|
|
30733
|
+
const startedAt = monotonicNowMs();
|
|
30212
30734
|
const deadline = startedAt + effectiveWaitMs;
|
|
30735
|
+
const elapsedMs = () => Math.round(monotonicNowMs() - startedAt);
|
|
30213
30736
|
let spillCursor = { output: 0, stderr: 0 };
|
|
30214
30737
|
const scanState = {
|
|
30215
30738
|
output: { text: "", baseOffset: 0 },
|
|
@@ -30239,16 +30762,18 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
|
|
|
30239
30762
|
if (isSyncWatchAborted(sessionId)) {
|
|
30240
30763
|
return withWaited(lastData ?? unavailableSnapshot(), {
|
|
30241
30764
|
reason: "user_message",
|
|
30242
|
-
elapsed_ms:
|
|
30765
|
+
elapsed_ms: elapsedMs(),
|
|
30766
|
+
limit_ms: effectiveWaitMs
|
|
30243
30767
|
});
|
|
30244
30768
|
}
|
|
30245
|
-
if (
|
|
30769
|
+
if (monotonicNowMs() >= deadline) {
|
|
30246
30770
|
return withWaited(lastData ?? unavailableSnapshot(), {
|
|
30247
30771
|
reason: "unavailable",
|
|
30248
|
-
elapsed_ms:
|
|
30772
|
+
elapsed_ms: elapsedMs(),
|
|
30773
|
+
limit_ms: effectiveWaitMs
|
|
30249
30774
|
});
|
|
30250
30775
|
}
|
|
30251
|
-
await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline -
|
|
30776
|
+
await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - monotonicNowMs())));
|
|
30252
30777
|
continue;
|
|
30253
30778
|
}
|
|
30254
30779
|
lastData = data;
|
|
@@ -30277,7 +30802,8 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
|
|
|
30277
30802
|
const matchStream = data.mode === "pty" ? undefined : chunk.stream === "output" ? "stdout" : "stderr";
|
|
30278
30803
|
return withWaited(data, {
|
|
30279
30804
|
reason: "matched",
|
|
30280
|
-
elapsed_ms:
|
|
30805
|
+
elapsed_ms: elapsedMs(),
|
|
30806
|
+
limit_ms: effectiveWaitMs,
|
|
30281
30807
|
match: match.text,
|
|
30282
30808
|
match_offset: state.baseOffset + match.byteOffset,
|
|
30283
30809
|
match_stream: matchStream
|
|
@@ -30297,15 +30823,27 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
|
|
|
30297
30823
|
consumeBgCompletion(sessionId, taskId);
|
|
30298
30824
|
await markBgCompletionDelivered({ ctx, directory: extCtx.cwd, sessionID: sessionId }, taskId);
|
|
30299
30825
|
}
|
|
30300
|
-
return withWaited(data, {
|
|
30826
|
+
return withWaited(data, {
|
|
30827
|
+
reason: "exited",
|
|
30828
|
+
elapsed_ms: elapsedMs(),
|
|
30829
|
+
limit_ms: effectiveWaitMs
|
|
30830
|
+
});
|
|
30301
30831
|
}
|
|
30302
30832
|
if (isSyncWatchAborted(sessionId)) {
|
|
30303
|
-
return withWaited(data, {
|
|
30833
|
+
return withWaited(data, {
|
|
30834
|
+
reason: "user_message",
|
|
30835
|
+
elapsed_ms: elapsedMs(),
|
|
30836
|
+
limit_ms: effectiveWaitMs
|
|
30837
|
+
});
|
|
30304
30838
|
}
|
|
30305
|
-
if (
|
|
30306
|
-
return withWaited(data, {
|
|
30839
|
+
if (monotonicNowMs() >= deadline) {
|
|
30840
|
+
return withWaited(data, {
|
|
30841
|
+
reason: "timeout",
|
|
30842
|
+
elapsed_ms: elapsedMs(),
|
|
30843
|
+
limit_ms: effectiveWaitMs
|
|
30844
|
+
});
|
|
30307
30845
|
}
|
|
30308
|
-
await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline -
|
|
30846
|
+
await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - monotonicNowMs())));
|
|
30309
30847
|
}
|
|
30310
30848
|
} finally {
|
|
30311
30849
|
if (waitForExit && !sawTerminal)
|
|
@@ -30412,18 +30950,19 @@ function withWaited(data, waited) {
|
|
|
30412
30950
|
return { ...data, waited };
|
|
30413
30951
|
}
|
|
30414
30952
|
function formatWaitSummary(waited, details, watchRole) {
|
|
30953
|
+
const waitedText = formatWatchWaited(waited.elapsed_ms, waited.limit_ms, watchRole.capMs);
|
|
30415
30954
|
if (waited.reason === "matched") {
|
|
30416
30955
|
const stream = waited.match_stream ? ` in ${waited.match_stream}` : "";
|
|
30417
|
-
return
|
|
30956
|
+
return `${waitedText}; matched ${JSON.stringify(waited.match ?? "")}${stream} at offset ${waited.match_offset ?? 0}.`;
|
|
30418
30957
|
}
|
|
30419
30958
|
if (waited.reason === "timeout") {
|
|
30420
|
-
return
|
|
30959
|
+
return `${waitedText}; timeout reached without match. ${watchTimeoutSteer(watchRole.role, watchRole.capMs, "timeout_ms")}`;
|
|
30421
30960
|
}
|
|
30422
30961
|
if (waited.reason === "unavailable") {
|
|
30423
|
-
return
|
|
30962
|
+
return `${waitedText}; the bridge was busy, so task state is unknown. Do not poll; let the task's completion notification wake the session, or use one bash_status snapshot on the next normal tool call.`;
|
|
30424
30963
|
}
|
|
30425
30964
|
const exit = typeof details.exit_code === "number" ? `, exit ${details.exit_code}` : "";
|
|
30426
|
-
return
|
|
30965
|
+
return `${waitedText}; task exited (${details.status}${exit}).`;
|
|
30427
30966
|
}
|
|
30428
30967
|
async function formatBashStatus(extCtx, taskId, details, requestedOutputMode, watchRole) {
|
|
30429
30968
|
const exit = typeof details.exit_code === "number" ? ` (exit ${details.exit_code})` : "";
|
|
@@ -30690,7 +31229,7 @@ function registerFsTools(pi, ctx, surface) {
|
|
|
30690
31229
|
pi.registerTool(withPathAliasPreparation({
|
|
30691
31230
|
name: "aft_delete",
|
|
30692
31231
|
label: "delete",
|
|
30693
|
-
description: "Delete one or more files (or directories). " + (backupsDisabled ? "Backup capture is disabled by user config, so this tool does not create undo snapshots. " : "Each file is backed up before deletion — use `aft_safety undo` to recover any of them.
|
|
31232
|
+
description: "Delete one or more files (or directories). " + (backupsDisabled ? "Backup capture is disabled by user config, so this tool does not create undo snapshots. A directory tree containing a mount point of another filesystem is still refused. " : "Each file is backed up before deletion — use `aft_safety undo` to recover any of them. A recursive delete backs up the whole tree: directories (empty ones too, with their permissions), file contents, hard links (relinked by undo) and symlinks (the link itself, never its target; restored exactly, even when dangling). Sockets are deleted but undo does not restore them, and a file hard-linked to paths outside the tree comes back as an independent copy; both are reported as warnings. Refused before anything is deleted: mount points of another filesystem, named pipes, device nodes, and symlinks undo cannot recreate exactly (non-UTF-8 target, or on Windows). Paths under the system temp directory are never backed up, so only mount points are refused there. The deleted file's contents stay in the undo store until its retention expires. A recursive delete whose backup would record more than 2,000 entries (files, directories and links) or copy 100 MiB in one call is refused before anything is deleted; delete such a tree in smaller pieces, or use bash `rm -rf` when no undo is needed. ") + "Directory deletion requires recursive: true. " + "Returns { success, complete, deleted, skipped_files }: partial success is allowed; files that fail are reported in skipped_files.",
|
|
30694
31233
|
parameters: DeleteParams,
|
|
30695
31234
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
30696
31235
|
const inputs = coerceStringArray(params.files);
|
|
@@ -30698,14 +31237,13 @@ function registerFsTools(pi, ctx, surface) {
|
|
|
30698
31237
|
throw new Error("delete: `files` must be a non-empty array of paths");
|
|
30699
31238
|
}
|
|
30700
31239
|
const files = await Promise.all(inputs.map((file) => resolvePathArg(extCtx.cwd, file)));
|
|
31240
|
+
const restrictToProjectRoot = ctx.config.restrict_to_project_root ?? false;
|
|
30701
31241
|
const checked = new Set;
|
|
30702
31242
|
for (const file of files) {
|
|
30703
31243
|
if (checked.has(file))
|
|
30704
31244
|
continue;
|
|
30705
31245
|
checked.add(file);
|
|
30706
|
-
await assertExternalDirectoryPermission(extCtx, file, {
|
|
30707
|
-
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
30708
|
-
});
|
|
31246
|
+
await assertExternalDirectoryPermission(extCtx, file, { restrictToProjectRoot });
|
|
30709
31247
|
}
|
|
30710
31248
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
30711
31249
|
const response = await callToolCall(bridge, "delete", {
|
|
@@ -30743,10 +31281,9 @@ function registerFsTools(pi, ctx, surface) {
|
|
|
30743
31281
|
const filePath = await resolvePathArg(extCtx.cwd, params.path);
|
|
30744
31282
|
const destination = await resolvePathArg(extCtx.cwd, params.destination);
|
|
30745
31283
|
const checked = new Set([filePath, destination]);
|
|
31284
|
+
const restrictToProjectRoot = ctx.config.restrict_to_project_root ?? false;
|
|
30746
31285
|
for (const file of checked) {
|
|
30747
|
-
await assertExternalDirectoryPermission(extCtx, file, {
|
|
30748
|
-
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
30749
|
-
});
|
|
31286
|
+
await assertExternalDirectoryPermission(extCtx, file, { restrictToProjectRoot });
|
|
30750
31287
|
}
|
|
30751
31288
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
30752
31289
|
const response = await callToolCall(bridge, "move", {
|
|
@@ -32176,6 +32713,12 @@ function piHashlineDowngrade(config, surface) {
|
|
|
32176
32713
|
message: 'edit_mode "hashline" is not in effect because "read" is in disabled_tools (hashline edits need tagged reads); registered tools keep their ordinary behavior.'
|
|
32177
32714
|
};
|
|
32178
32715
|
}
|
|
32716
|
+
function withLiveRestriction(surface, ctx) {
|
|
32717
|
+
return Object.defineProperty({ ...surface }, "restrictToProjectRoot", {
|
|
32718
|
+
enumerable: true,
|
|
32719
|
+
get: () => ctx.config.restrict_to_project_root ?? false
|
|
32720
|
+
});
|
|
32721
|
+
}
|
|
32179
32722
|
function resolvePiToolSurface(config, pi) {
|
|
32180
32723
|
const disabled = new Set(resolvedDisabledTools(config));
|
|
32181
32724
|
const ok = (name) => !disabled.has(name);
|
|
@@ -32228,7 +32771,8 @@ function bindToolRegistrationFunnel(pi, ctx, harness) {
|
|
|
32228
32771
|
}
|
|
32229
32772
|
});
|
|
32230
32773
|
}
|
|
32231
|
-
function registerPiToolSurface(pi, ctx,
|
|
32774
|
+
function registerPiToolSurface(pi, ctx, loadedSurface, harness) {
|
|
32775
|
+
const surface = withLiveRestriction(loadedSurface, ctx);
|
|
32232
32776
|
const boundPi = bindToolRegistrationFunnel(pi, ctx, harness);
|
|
32233
32777
|
if (surface.hoistBash)
|
|
32234
32778
|
registerBashTool(boundPi, ctx, surface.semantic, "bash", false);
|
|
@@ -32262,6 +32806,8 @@ var CONFIG_ERROR_STATUS_KEY = "aft";
|
|
|
32262
32806
|
var defaultDependencies = {
|
|
32263
32807
|
loadConfig: loadAftConfig,
|
|
32264
32808
|
configLoadErrors: getConfigLoadErrors,
|
|
32809
|
+
configLoadSources: getConfigLoadSources,
|
|
32810
|
+
configLoadTexts: getConfigLoadTexts,
|
|
32265
32811
|
migrateConfigLocations: (directory) => migrateAftConfigLocations(directory, bridgeLogger).flatMap((result) => result.warnings),
|
|
32266
32812
|
subcConnectionFileError
|
|
32267
32813
|
};
|
|
@@ -32280,6 +32826,8 @@ function parseFailure(dependencies) {
|
|
|
32280
32826
|
}
|
|
32281
32827
|
async function resolvePiBootstrapConfig(directory, notify, dependencies = defaultDependencies) {
|
|
32282
32828
|
let config;
|
|
32829
|
+
let sources = [];
|
|
32830
|
+
let sourceTexts = {};
|
|
32283
32831
|
try {
|
|
32284
32832
|
dependencies.loadConfig(directory);
|
|
32285
32833
|
const firstFailure = parseFailure(dependencies);
|
|
@@ -32291,11 +32839,13 @@ async function resolvePiBootstrapConfig(directory, notify, dependencies = defaul
|
|
|
32291
32839
|
const failure = parseFailure(dependencies);
|
|
32292
32840
|
if (failure)
|
|
32293
32841
|
return configErrorState(failure, notify);
|
|
32842
|
+
sources = [...dependencies.configLoadSources?.() ?? []];
|
|
32843
|
+
sourceTexts = Object.fromEntries(dependencies.configLoadTexts?.() ?? []);
|
|
32294
32844
|
} catch (err) {
|
|
32295
32845
|
return configErrorState(err instanceof Error ? err.message : String(err), notify);
|
|
32296
32846
|
}
|
|
32297
32847
|
const missing = await dependencies.subcConnectionFileError(config.subc?.connection_file);
|
|
32298
|
-
return missing === null ? { ok: true, config } : configErrorState(missing, notify, config);
|
|
32848
|
+
return missing === null ? { ok: true, config, sources, sourceTexts } : configErrorState(missing, notify, config);
|
|
32299
32849
|
}
|
|
32300
32850
|
function failingRegistrations(pi, message) {
|
|
32301
32851
|
const registerTool = (tool) => {
|
|
@@ -32331,6 +32881,58 @@ function registerPiConfigErrorState(pi, config, message) {
|
|
|
32331
32881
|
log2("AFT is in the config error state; every tool call will fail");
|
|
32332
32882
|
}
|
|
32333
32883
|
|
|
32884
|
+
// src/config-live-reload.ts
|
|
32885
|
+
var PI_LIVE_CONFIG_KEYS = aftLiveConfigKeys((config) => resolveBashConfig(config));
|
|
32886
|
+
function projectTextOf(directory) {
|
|
32887
|
+
const { projectConfigPath } = resolveCortexKitConfigPaths(directory);
|
|
32888
|
+
return getConfigLoadTexts().get(projectConfigPath) ?? null;
|
|
32889
|
+
}
|
|
32890
|
+
function loadPiConfigForLiveReload(directory) {
|
|
32891
|
+
try {
|
|
32892
|
+
const config = loadAftConfig(directory);
|
|
32893
|
+
const [failure] = getConfigLoadErrors();
|
|
32894
|
+
if (failure) {
|
|
32895
|
+
return { ok: false, message: formatConfigParseErrorMessage(failure.path, failure.message) };
|
|
32896
|
+
}
|
|
32897
|
+
const [invalid] = getConfigValidationErrors();
|
|
32898
|
+
if (invalid) {
|
|
32899
|
+
return {
|
|
32900
|
+
ok: false,
|
|
32901
|
+
message: `AFT config at ${invalid.path} has an invalid setting: ${invalid.message}`
|
|
32902
|
+
};
|
|
32903
|
+
}
|
|
32904
|
+
return {
|
|
32905
|
+
ok: true,
|
|
32906
|
+
config,
|
|
32907
|
+
sources: [...getConfigLoadSources()],
|
|
32908
|
+
projectText: projectTextOf(directory),
|
|
32909
|
+
texts: Object.fromEntries(getConfigLoadTexts())
|
|
32910
|
+
};
|
|
32911
|
+
} catch (err) {
|
|
32912
|
+
return { ok: false, message: err instanceof Error ? err.message : String(err) };
|
|
32913
|
+
}
|
|
32914
|
+
}
|
|
32915
|
+
function startPiLiveConfigReload(options) {
|
|
32916
|
+
const { userConfigPath, projectConfigPath } = resolveCortexKitConfigPaths(options.directory);
|
|
32917
|
+
return startLiveConfigReload({
|
|
32918
|
+
paths: [userConfigPath, projectConfigPath],
|
|
32919
|
+
load: () => loadPiConfigForLiveReload(options.directory),
|
|
32920
|
+
initialSources: options.initialSources,
|
|
32921
|
+
initialProjectText: options.initialSourceTexts?.[projectConfigPath] ?? null,
|
|
32922
|
+
initialTexts: options.initialSourceTexts,
|
|
32923
|
+
securityKeys: aftLiveSecurityKeys(PI_LIVE_CONFIG_KEYS),
|
|
32924
|
+
keys: PI_LIVE_CONFIG_KEYS,
|
|
32925
|
+
getConfig: options.getConfig,
|
|
32926
|
+
setConfig: options.setConfig,
|
|
32927
|
+
log: (message) => log2(`${message} (${options.directory})`),
|
|
32928
|
+
reportError: (message) => {
|
|
32929
|
+
error2(message);
|
|
32930
|
+
options.notify(message);
|
|
32931
|
+
},
|
|
32932
|
+
watch: options.watch
|
|
32933
|
+
});
|
|
32934
|
+
}
|
|
32935
|
+
|
|
32334
32936
|
// src/shutdown-hooks.ts
|
|
32335
32937
|
var GLOBAL_KEY = "__aftPiShutdownHooks__";
|
|
32336
32938
|
function getState() {
|
|
@@ -32503,6 +33105,8 @@ function buildHintsFromConfig(config, absentTools, hashlineEffective = false) {
|
|
|
32503
33105
|
});
|
|
32504
33106
|
}
|
|
32505
33107
|
function registerWorkflowHints(pi, config, surface) {
|
|
33108
|
+
if (skipsEagerStartup())
|
|
33109
|
+
return;
|
|
32506
33110
|
const absent = new Set;
|
|
32507
33111
|
if (!surface.outline)
|
|
32508
33112
|
absent.add("aft_outline");
|
|
@@ -32956,6 +33560,16 @@ ${lines}
|
|
|
32956
33560
|
hashlineEffective: hashlineEditRegistered,
|
|
32957
33561
|
storageDir
|
|
32958
33562
|
};
|
|
33563
|
+
const liveConfigReload = startPiLiveConfigReload({
|
|
33564
|
+
directory: projectRoot,
|
|
33565
|
+
initialSources: bootstrap.sources ?? [],
|
|
33566
|
+
initialSourceTexts: bootstrap.sourceTexts,
|
|
33567
|
+
getConfig: () => ctx.config,
|
|
33568
|
+
setConfig: (next) => {
|
|
33569
|
+
ctx.config = next;
|
|
33570
|
+
},
|
|
33571
|
+
notify: (message) => deliverConfigMigrationWarnings([message])
|
|
33572
|
+
});
|
|
32959
33573
|
if (onnxRuntimePromise) {
|
|
32960
33574
|
onnxRuntimePromise.then((ortDylibDir) => {
|
|
32961
33575
|
if (ortDylibDir) {
|
|
@@ -33062,6 +33676,7 @@ Retry with: npx @cortexkit/aft doctor --fix`
|
|
|
33062
33676
|
});
|
|
33063
33677
|
const unregisterShutdownCleanup = registerShutdownCleanup(async () => {
|
|
33064
33678
|
hostShutdownStarted = true;
|
|
33679
|
+
liveConfigReload.stop();
|
|
33065
33680
|
try {
|
|
33066
33681
|
await Promise.allSettled([abortInFlightAutoInstalls(), abortInFlightGithubInstalls()]);
|
|
33067
33682
|
await pool.shutdown();
|
|
@@ -33072,6 +33687,7 @@ Retry with: npx @cortexkit/aft doctor --fix`
|
|
|
33072
33687
|
});
|
|
33073
33688
|
pi.on("session_shutdown", async () => {
|
|
33074
33689
|
hostShutdownStarted = true;
|
|
33690
|
+
liveConfigReload.stop();
|
|
33075
33691
|
try {
|
|
33076
33692
|
await Promise.allSettled([abortInFlightAutoInstalls(), abortInFlightGithubInstalls()]);
|
|
33077
33693
|
await pool.shutdown();
|