@cortexkit/aft-pi 0.53.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bash-wait-detach.d.ts +6 -0
- package/dist/bash-wait-detach.d.ts.map +1 -1
- package/dist/bg-notifications.d.ts +1 -0
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/config.d.ts +190 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +984 -386
- package/dist/lsp-auto-install.d.ts.map +1 -1
- package/dist/lsp-cache.d.ts +9 -6
- package/dist/lsp-cache.d.ts.map +1 -1
- package/dist/tool-registration.d.ts +4 -1
- package/dist/tool-registration.d.ts.map +1 -1
- package/dist/tools/_shared.d.ts +7 -0
- package/dist/tools/_shared.d.ts.map +1 -1
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/inspect.d.ts +1 -1
- package/dist/tools/inspect.d.ts.map +1 -1
- package/dist/tools/safety.d.ts.map +1 -1
- package/dist/tools/semantic.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -7711,9 +7711,9 @@ var require_stringify = __commonJS(function(exports, module) {
|
|
|
7711
7711
|
value
|
|
7712
7712
|
} = comment;
|
|
7713
7713
|
const line_breaks_before = blank_lines > 0 ? blank_lines + (inline ? 0 : 1) : null;
|
|
7714
|
-
const
|
|
7714
|
+
const delimiter3 = line_breaks_before > 0 ? repeat_line_breaks(line_breaks_before, deeper_gap) : inline ? SPACE : i === 0 && symbol_tag === PREFIX_BEFORE_ALL && deeper_gap === EMPTY ? EMPTY : LF + deeper_gap;
|
|
7715
7715
|
const is_line_comment = type === "LineComment";
|
|
7716
|
-
str +=
|
|
7716
|
+
str += delimiter3 + comment_stringify(value, is_line_comment);
|
|
7717
7717
|
blank_lines = 0;
|
|
7718
7718
|
last_comment = comment;
|
|
7719
7719
|
});
|
|
@@ -7730,10 +7730,10 @@ var require_stringify = __commonJS(function(exports, module) {
|
|
|
7730
7730
|
replacer = null;
|
|
7731
7731
|
indent = EMPTY;
|
|
7732
7732
|
};
|
|
7733
|
-
var
|
|
7733
|
+
var join13 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two)), gap) : EMPTY;
|
|
7734
7734
|
var join_content = (inside, value, gap) => {
|
|
7735
7735
|
const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
|
|
7736
|
-
return
|
|
7736
|
+
return join13(comment, inside, gap);
|
|
7737
7737
|
};
|
|
7738
7738
|
var stringify_string = (holder, key, value) => {
|
|
7739
7739
|
const raw = get_raw_string_literal(holder, key);
|
|
@@ -7755,13 +7755,13 @@ var require_stringify = __commonJS(function(exports, module) {
|
|
|
7755
7755
|
if (i !== 0) {
|
|
7756
7756
|
inside += COMMA;
|
|
7757
7757
|
}
|
|
7758
|
-
const before =
|
|
7758
|
+
const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
|
|
7759
7759
|
inside += before || LF + deeper_gap;
|
|
7760
7760
|
inside += stringify(i, value, deeper_gap) || STR_NULL;
|
|
7761
7761
|
inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
|
|
7762
7762
|
after_comma = process_comments(value, AFTER(i), deeper_gap);
|
|
7763
7763
|
}
|
|
7764
|
-
inside +=
|
|
7764
|
+
inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
7765
7765
|
return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
|
|
7766
7766
|
};
|
|
7767
7767
|
var object_stringify = (value, gap) => {
|
|
@@ -7782,13 +7782,13 @@ var require_stringify = __commonJS(function(exports, module) {
|
|
|
7782
7782
|
inside += COMMA;
|
|
7783
7783
|
}
|
|
7784
7784
|
first = false;
|
|
7785
|
-
const before =
|
|
7785
|
+
const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
|
|
7786
7786
|
inside += before || LF + deeper_gap;
|
|
7787
7787
|
inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
|
|
7788
7788
|
after_comma = process_comments(value, AFTER(key), deeper_gap);
|
|
7789
7789
|
};
|
|
7790
7790
|
keys.forEach(iteratee);
|
|
7791
|
-
inside +=
|
|
7791
|
+
inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
7792
7792
|
return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
|
|
7793
7793
|
};
|
|
7794
7794
|
function stringify(key, holder, gap) {
|
|
@@ -8329,10 +8329,68 @@ function skipSpaces(input, start) {
|
|
|
8329
8329
|
}
|
|
8330
8330
|
// ../aft-bridge/dist/bash-host-fallback.js
|
|
8331
8331
|
import { spawn } from "node:child_process";
|
|
8332
|
+
import { existsSync } from "node:fs";
|
|
8333
|
+
import { delimiter, join as join3 } from "node:path";
|
|
8334
|
+
|
|
8335
|
+
// ../aft-bridge/dist/storage-paths.js
|
|
8336
|
+
import { homedir as homedir2 } from "node:os";
|
|
8337
|
+
import { join as join2, resolve as resolve2 } from "node:path";
|
|
8338
|
+
function homeDir() {
|
|
8339
|
+
if (process.platform === "win32")
|
|
8340
|
+
return process.env.USERPROFILE || process.env.HOME || homedir2();
|
|
8341
|
+
return process.env.HOME || homedir2();
|
|
8342
|
+
}
|
|
8343
|
+
function dataHome() {
|
|
8344
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
8345
|
+
if (xdg)
|
|
8346
|
+
return xdg;
|
|
8347
|
+
if (process.platform === "win32") {
|
|
8348
|
+
return process.env.LOCALAPPDATA || process.env.APPDATA || join2(homeDir(), "AppData", "Local");
|
|
8349
|
+
}
|
|
8350
|
+
return join2(homeDir(), ".local", "share");
|
|
8351
|
+
}
|
|
8352
|
+
function resolveStoragePath(raw) {
|
|
8353
|
+
let expanded = raw;
|
|
8354
|
+
if (raw === "~") {
|
|
8355
|
+
expanded = homeDir();
|
|
8356
|
+
} else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
|
|
8357
|
+
expanded = join2(homeDir(), raw.slice(2));
|
|
8358
|
+
}
|
|
8359
|
+
return resolve2(expanded);
|
|
8360
|
+
}
|
|
8361
|
+
function resolveCortexKitStorageRoot() {
|
|
8362
|
+
const override = process.env.AFT_STORAGE_DIR;
|
|
8363
|
+
if (override)
|
|
8364
|
+
return resolveStoragePath(override);
|
|
8365
|
+
return resolveStoragePath(join2(dataHome(), "cortexkit", "aft"));
|
|
8366
|
+
}
|
|
8367
|
+
function resolveAftStorageRoot(configuredRoot) {
|
|
8368
|
+
if (process.env.AFT_STORAGE_DIR)
|
|
8369
|
+
return resolveCortexKitStorageRoot();
|
|
8370
|
+
if (configuredRoot)
|
|
8371
|
+
return configuredRoot;
|
|
8372
|
+
return resolveCortexKitStorageRoot();
|
|
8373
|
+
}
|
|
8374
|
+
function resolveAftLogPath(filename, configuredRoot) {
|
|
8375
|
+
return join2(resolveAftStorageRoot(configuredRoot), "logs", filename);
|
|
8376
|
+
}
|
|
8377
|
+
|
|
8378
|
+
// ../aft-bridge/dist/bash-host-fallback.js
|
|
8332
8379
|
var BASH_HOST_FALLBACK_BANNER = "[AFT host fallback - module transport down; no rewrites/compression/background]";
|
|
8333
8380
|
var BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES = 100 * 1024;
|
|
8334
8381
|
var BASH_HOST_FALLBACK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
|
|
8335
8382
|
var BASH_HOST_FALLBACK_REFUSAL = "AFT transport is down; only foreground execution is available in host fallback";
|
|
8383
|
+
function hostFallbackPathWithShims(env) {
|
|
8384
|
+
const storageRoot = env.AFT_STORAGE_DIR ? resolveStoragePath(env.AFT_STORAGE_DIR) : resolveCortexKitStorageRoot();
|
|
8385
|
+
const shimsDir = join3(storageRoot, "shims");
|
|
8386
|
+
if (!existsSync(join3(shimsDir, "gh")))
|
|
8387
|
+
return env.PATH;
|
|
8388
|
+
const inherited = env.PATH ?? "";
|
|
8389
|
+
const entries = inherited.split(delimiter).filter((entry) => entry.length > 0);
|
|
8390
|
+
if (entries[0] === shimsDir)
|
|
8391
|
+
return inherited;
|
|
8392
|
+
return [shimsDir, ...entries.filter((entry) => entry !== shimsDir)].join(delimiter);
|
|
8393
|
+
}
|
|
8336
8394
|
function bashHostFallbackAskPattern(command, cwd) {
|
|
8337
8395
|
return `AFT UNAVAILABLE - host fallback execution:
|
|
8338
8396
|
|
|
@@ -8365,11 +8423,17 @@ async function runBashHostFallback(options) {
|
|
|
8365
8423
|
if (options.signal?.aborted) {
|
|
8366
8424
|
throw new DOMException("The host fallback command was aborted", "AbortError");
|
|
8367
8425
|
}
|
|
8368
|
-
return await new Promise((
|
|
8426
|
+
return await new Promise((resolve3, reject) => {
|
|
8369
8427
|
const child = spawn(options.command, {
|
|
8370
8428
|
cwd: options.projectRoot,
|
|
8371
8429
|
shell: true,
|
|
8372
|
-
env:
|
|
8430
|
+
env: (() => {
|
|
8431
|
+
const merged = { ...process.env, ...options.env };
|
|
8432
|
+
const path2 = hostFallbackPathWithShims(merged);
|
|
8433
|
+
if (path2 !== undefined)
|
|
8434
|
+
merged.PATH = path2;
|
|
8435
|
+
return merged;
|
|
8436
|
+
})(),
|
|
8373
8437
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8374
8438
|
detached: process.platform !== "win32",
|
|
8375
8439
|
windowsHide: true
|
|
@@ -8432,7 +8496,7 @@ async function runBashHostFallback(options) {
|
|
|
8432
8496
|
return;
|
|
8433
8497
|
}
|
|
8434
8498
|
const exitCode = timedOut ? 124 : code ?? 1;
|
|
8435
|
-
|
|
8499
|
+
resolve3({
|
|
8436
8500
|
success: true,
|
|
8437
8501
|
output: renderOutput(Buffer.concat(chunks), exitCode),
|
|
8438
8502
|
exit_code: exitCode,
|
|
@@ -8452,8 +8516,8 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
|
|
|
8452
8516
|
import { spawn as spawn2 } from "node:child_process";
|
|
8453
8517
|
import { createHash } from "node:crypto";
|
|
8454
8518
|
import { readFileSync } from "node:fs";
|
|
8455
|
-
import { homedir as
|
|
8456
|
-
import { join as
|
|
8519
|
+
import { homedir as homedir3 } from "node:os";
|
|
8520
|
+
import { join as join4 } from "node:path";
|
|
8457
8521
|
import { StringDecoder } from "node:string_decoder";
|
|
8458
8522
|
|
|
8459
8523
|
// ../aft-bridge/dist/command-timeouts.js
|
|
@@ -8859,6 +8923,21 @@ class BinaryBridge {
|
|
|
8859
8923
|
}
|
|
8860
8924
|
return this.sendWithVersionMismatchRetry(command, dispatchParams, options, true);
|
|
8861
8925
|
}
|
|
8926
|
+
listenForRequestAbort(requestId, signal) {
|
|
8927
|
+
if (!signal)
|
|
8928
|
+
return () => {};
|
|
8929
|
+
let fired = false;
|
|
8930
|
+
const onAbort = () => {
|
|
8931
|
+
if (fired)
|
|
8932
|
+
return;
|
|
8933
|
+
fired = true;
|
|
8934
|
+
this.send("cancel_request", { id: requestId }, { keepBridgeOnTimeout: true }).catch(() => {});
|
|
8935
|
+
};
|
|
8936
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8937
|
+
if (signal.aborted)
|
|
8938
|
+
onAbort();
|
|
8939
|
+
return () => signal.removeEventListener("abort", onAbort);
|
|
8940
|
+
}
|
|
8862
8941
|
async toolCall(sessionId, name, rawArgs = {}, options) {
|
|
8863
8942
|
const params = { name, arguments: rawArgs };
|
|
8864
8943
|
if (sessionId)
|
|
@@ -8881,7 +8960,7 @@ class BinaryBridge {
|
|
|
8881
8960
|
if (this._shuttingDown) {
|
|
8882
8961
|
throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
|
|
8883
8962
|
}
|
|
8884
|
-
if (Object.hasOwn(params, "id")) {
|
|
8963
|
+
if (Object.hasOwn(params, "id") && command !== "cancel_request") {
|
|
8885
8964
|
throw new Error("params cannot contain reserved key 'id'");
|
|
8886
8965
|
}
|
|
8887
8966
|
const requestSessionId = typeof params.session_id === "string" && params.session_id.length > 0 ? params.session_id : undefined;
|
|
@@ -8935,7 +9014,7 @@ class BinaryBridge {
|
|
|
8935
9014
|
}
|
|
8936
9015
|
const id = String(this.nextId++);
|
|
8937
9016
|
let request;
|
|
8938
|
-
if (Object.hasOwn(params, "command") || Object.hasOwn(params, "method")) {
|
|
9017
|
+
if (command === "cancel_request" || Object.hasOwn(params, "command") || Object.hasOwn(params, "method")) {
|
|
8939
9018
|
const nested = { ...params };
|
|
8940
9019
|
const reserved = {};
|
|
8941
9020
|
for (const key of ["session_id", "lsp_hints"]) {
|
|
@@ -8953,13 +9032,14 @@ class BinaryBridge {
|
|
|
8953
9032
|
const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
|
|
8954
9033
|
let requestSentAt = Date.now();
|
|
8955
9034
|
const child = this.process;
|
|
8956
|
-
const response = await new Promise((
|
|
9035
|
+
const response = await new Promise((resolve3, reject) => {
|
|
8957
9036
|
const timer = setTimeout(() => {
|
|
8958
|
-
const
|
|
8959
|
-
if (!
|
|
9037
|
+
const entry2 = this.pending.get(id);
|
|
9038
|
+
if (!entry2)
|
|
8960
9039
|
return;
|
|
8961
9040
|
this.pending.delete(id);
|
|
8962
|
-
clearTimeout(
|
|
9041
|
+
clearTimeout(entry2.timer);
|
|
9042
|
+
entry2.onSettled?.();
|
|
8963
9043
|
if (keepBridgeOnTimeout) {
|
|
8964
9044
|
const timeoutMsg2 = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`;
|
|
8965
9045
|
if (requestSessionId) {
|
|
@@ -8967,7 +9047,7 @@ class BinaryBridge {
|
|
|
8967
9047
|
} else {
|
|
8968
9048
|
this.warnVia(timeoutMsg2);
|
|
8969
9049
|
}
|
|
8970
|
-
|
|
9050
|
+
entry2.reject(new BridgeTransportTimeoutError(command, effectiveTimeoutMs, `${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
|
|
8971
9051
|
return;
|
|
8972
9052
|
}
|
|
8973
9053
|
const childActiveSinceRequest = this.lastChildActivityAt > requestSentAt;
|
|
@@ -8982,13 +9062,20 @@ class BinaryBridge {
|
|
|
8982
9062
|
this.warnVia(timeoutMsg);
|
|
8983
9063
|
}
|
|
8984
9064
|
if (keepWarm) {
|
|
8985
|
-
|
|
9065
|
+
entry2.reject(new Error(`${this.errorPrefix} request "${command}" timed out after ${effectiveTimeoutMs}ms (bridge busy/under load); bridge kept warm — retry`));
|
|
8986
9066
|
return;
|
|
8987
9067
|
}
|
|
8988
|
-
|
|
9068
|
+
entry2.reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
|
|
8989
9069
|
this.handleTimeout(requestSessionId);
|
|
8990
9070
|
}, effectiveTimeoutMs);
|
|
8991
|
-
|
|
9071
|
+
const entry = {
|
|
9072
|
+
resolve: resolve3,
|
|
9073
|
+
reject,
|
|
9074
|
+
timer,
|
|
9075
|
+
onProgress: options?.onProgress,
|
|
9076
|
+
command
|
|
9077
|
+
};
|
|
9078
|
+
this.pending.set(id, entry);
|
|
8992
9079
|
if (!child?.stdin?.writable) {
|
|
8993
9080
|
this.pending.delete(id);
|
|
8994
9081
|
clearTimeout(timer);
|
|
@@ -9002,11 +9089,12 @@ class BinaryBridge {
|
|
|
9002
9089
|
const handleWriteFailure = (cause) => {
|
|
9003
9090
|
const writeError = cause instanceof Error ? cause : new Error(String(cause));
|
|
9004
9091
|
const error2 = new BridgeTransportUnknownOutcomeError(`${this.errorPrefix} Failed to write to stdin: ${writeError.message}`, { cause: writeError });
|
|
9005
|
-
const
|
|
9006
|
-
if (
|
|
9092
|
+
const entry2 = this.pending.get(id);
|
|
9093
|
+
if (entry2) {
|
|
9007
9094
|
this.pending.delete(id);
|
|
9008
|
-
clearTimeout(
|
|
9009
|
-
|
|
9095
|
+
clearTimeout(entry2.timer);
|
|
9096
|
+
entry2.onSettled?.();
|
|
9097
|
+
entry2.reject(error2);
|
|
9010
9098
|
}
|
|
9011
9099
|
if (this.process === child)
|
|
9012
9100
|
this.invalidateTransportProcess(error2);
|
|
@@ -9019,6 +9107,9 @@ class BinaryBridge {
|
|
|
9019
9107
|
} catch (err) {
|
|
9020
9108
|
handleWriteFailure(err);
|
|
9021
9109
|
}
|
|
9110
|
+
if (this.pending.has(id)) {
|
|
9111
|
+
entry.onSettled = this.listenForRequestAbort(id, options?.abortSignal);
|
|
9112
|
+
}
|
|
9022
9113
|
});
|
|
9023
9114
|
if (command === "configure" && response.success === true && options?.markConfiguredOnSuccess !== false) {
|
|
9024
9115
|
this.configured = true;
|
|
@@ -9106,15 +9197,15 @@ class BinaryBridge {
|
|
|
9106
9197
|
if (this.process) {
|
|
9107
9198
|
const proc = this.process;
|
|
9108
9199
|
this.process = null;
|
|
9109
|
-
return new Promise((
|
|
9200
|
+
return new Promise((resolve3) => {
|
|
9110
9201
|
const forceKillTimer = setTimeout(() => {
|
|
9111
9202
|
proc.kill("SIGKILL");
|
|
9112
|
-
|
|
9203
|
+
resolve3();
|
|
9113
9204
|
}, 5000);
|
|
9114
9205
|
proc.once("exit", () => {
|
|
9115
9206
|
clearTimeout(forceKillTimer);
|
|
9116
9207
|
this.logVia("Process exited during shutdown");
|
|
9117
|
-
|
|
9208
|
+
resolve3();
|
|
9118
9209
|
});
|
|
9119
9210
|
proc.kill("SIGTERM");
|
|
9120
9211
|
});
|
|
@@ -9162,15 +9253,15 @@ class BinaryBridge {
|
|
|
9162
9253
|
return;
|
|
9163
9254
|
const proc = this.process;
|
|
9164
9255
|
this.process = null;
|
|
9165
|
-
await new Promise((
|
|
9256
|
+
await new Promise((resolve3) => {
|
|
9166
9257
|
const forceKillTimer = setTimeout(() => {
|
|
9167
9258
|
proc.kill("SIGKILL");
|
|
9168
|
-
|
|
9259
|
+
resolve3();
|
|
9169
9260
|
}, 5000);
|
|
9170
9261
|
proc.once("exit", () => {
|
|
9171
9262
|
clearTimeout(forceKillTimer);
|
|
9172
9263
|
this.logVia("Process exited during coordinated binary replacement");
|
|
9173
|
-
|
|
9264
|
+
resolve3();
|
|
9174
9265
|
});
|
|
9175
9266
|
proc.kill("SIGTERM");
|
|
9176
9267
|
});
|
|
@@ -9200,7 +9291,7 @@ class BinaryBridge {
|
|
|
9200
9291
|
})();
|
|
9201
9292
|
const useFastembedBackend = semanticBackend === undefined || semanticBackend === "fastembed" || semanticBackend === "";
|
|
9202
9293
|
const ortDir = typeof this.configOverrides._ort_dylib_dir === "string" && useFastembedBackend ? this.configOverrides._ort_dylib_dir : null;
|
|
9203
|
-
const ortLibraryPath = ortDir == null ? null :
|
|
9294
|
+
const ortLibraryPath = ortDir == null ? null : join4(ortDir, process.platform === "win32" ? "onnxruntime.dll" : process.platform === "darwin" ? "libonnxruntime.dylib" : "libonnxruntime.so");
|
|
9204
9295
|
const envPath = process.platform === "win32" && ortDir ? `${ortDir};${process.env.PATH ?? ""}` : process.env.PATH;
|
|
9205
9296
|
const env = {
|
|
9206
9297
|
...process.env,
|
|
@@ -9208,7 +9299,7 @@ class BinaryBridge {
|
|
|
9208
9299
|
};
|
|
9209
9300
|
this.logVia(`bridge.spawnProcess: useFastembedBackend=${useFastembedBackend}, ` + `parentORT=${process.env.ORT_DYLIB_PATH ?? "(unset)"}, ` + `ortLibraryPath=${ortLibraryPath ?? "(none)"}`);
|
|
9210
9301
|
if (useFastembedBackend) {
|
|
9211
|
-
env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ?
|
|
9302
|
+
env.FASTEMBED_CACHE_DIR = process.env.FASTEMBED_CACHE_DIR || (typeof this.configOverrides.storage_dir === "string" ? join4(this.configOverrides.storage_dir, "semantic", "models") : join4(homedir3() || "", ".cache", "fastembed"));
|
|
9212
9303
|
if (process.env.ORT_DYLIB_PATH) {
|
|
9213
9304
|
this.logVia(`ORT_DYLIB_PATH inherited from parent env: ${process.env.ORT_DYLIB_PATH}`);
|
|
9214
9305
|
} else if (ortLibraryPath) {
|
|
@@ -9387,6 +9478,7 @@ class BinaryBridge {
|
|
|
9387
9478
|
if (requestId && entry) {
|
|
9388
9479
|
this.pending.delete(requestId);
|
|
9389
9480
|
clearTimeout(entry.timer);
|
|
9481
|
+
entry.onSettled?.();
|
|
9390
9482
|
entry.resolve({
|
|
9391
9483
|
success: false,
|
|
9392
9484
|
code: "permission_required",
|
|
@@ -9428,6 +9520,7 @@ class BinaryBridge {
|
|
|
9428
9520
|
return;
|
|
9429
9521
|
this.pending.delete(id);
|
|
9430
9522
|
clearTimeout(entry.timer);
|
|
9523
|
+
entry.onSettled?.();
|
|
9431
9524
|
this.consecutiveRequestTimeouts = 0;
|
|
9432
9525
|
this.scheduleRestartCountReset();
|
|
9433
9526
|
this.accountForBashTaskResponse(entry.command, response);
|
|
@@ -9518,6 +9611,7 @@ class BinaryBridge {
|
|
|
9518
9611
|
rejectAllPending(error2) {
|
|
9519
9612
|
for (const [_id, entry] of this.pending) {
|
|
9520
9613
|
clearTimeout(entry.timer);
|
|
9614
|
+
entry.onSettled?.();
|
|
9521
9615
|
entry.reject(error2);
|
|
9522
9616
|
}
|
|
9523
9617
|
this.pending.clear();
|
|
@@ -9537,32 +9631,32 @@ class BinaryBridge {
|
|
|
9537
9631
|
}
|
|
9538
9632
|
}
|
|
9539
9633
|
// ../aft-bridge/dist/cache-paths.js
|
|
9540
|
-
import { homedir as
|
|
9541
|
-
import { join as
|
|
9542
|
-
function
|
|
9543
|
-
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) ||
|
|
9634
|
+
import { homedir as homedir4 } from "node:os";
|
|
9635
|
+
import { join as join5 } from "node:path";
|
|
9636
|
+
function homeDir2(env) {
|
|
9637
|
+
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir4();
|
|
9544
9638
|
}
|
|
9545
9639
|
function getAftCacheRoot(env = process.env) {
|
|
9546
9640
|
if (env.AFT_CACHE_DIR)
|
|
9547
9641
|
return env.AFT_CACHE_DIR;
|
|
9548
9642
|
if (process.platform === "win32") {
|
|
9549
|
-
const base2 = env.LOCALAPPDATA || env.APPDATA ||
|
|
9550
|
-
return
|
|
9643
|
+
const base2 = env.LOCALAPPDATA || env.APPDATA || join5(homeDir2(env), "AppData", "Local");
|
|
9644
|
+
return join5(base2, "aft");
|
|
9551
9645
|
}
|
|
9552
|
-
const base = env.XDG_CACHE_HOME ||
|
|
9553
|
-
return
|
|
9646
|
+
const base = env.XDG_CACHE_HOME || join5(homeDir2(env), ".cache");
|
|
9647
|
+
return join5(base, "aft");
|
|
9554
9648
|
}
|
|
9555
9649
|
function getAftBinaryCacheDir(env = process.env) {
|
|
9556
|
-
return
|
|
9650
|
+
return join5(getAftCacheRoot(env), "bin");
|
|
9557
9651
|
}
|
|
9558
9652
|
function getAftLspPackagesDir(env = process.env) {
|
|
9559
|
-
return
|
|
9653
|
+
return join5(getAftCacheRoot(env), "lsp-packages");
|
|
9560
9654
|
}
|
|
9561
9655
|
function getAftLspBinariesDir(env = process.env) {
|
|
9562
|
-
return
|
|
9656
|
+
return join5(getAftCacheRoot(env), "lsp-binaries");
|
|
9563
9657
|
}
|
|
9564
9658
|
// ../aft-bridge/dist/callgraph-format.js
|
|
9565
|
-
import { homedir as
|
|
9659
|
+
import { homedir as homedir5 } from "node:os";
|
|
9566
9660
|
var UNRESOLVED_SUMMARY_NAME_LIMIT = 10;
|
|
9567
9661
|
var PLAIN_CALLGRAPH_THEME = {
|
|
9568
9662
|
fg: (_role, text) => text
|
|
@@ -9585,7 +9679,7 @@ function asBoolean(value) {
|
|
|
9585
9679
|
return typeof value === "boolean" ? value : undefined;
|
|
9586
9680
|
}
|
|
9587
9681
|
function shortenPath(path2) {
|
|
9588
|
-
const home =
|
|
9682
|
+
const home = homedir5();
|
|
9589
9683
|
if (path2.startsWith(home))
|
|
9590
9684
|
return `~${path2.slice(home.length)}`;
|
|
9591
9685
|
return path2;
|
|
@@ -9932,26 +10026,26 @@ function stripHarnessSpecificConfigKeys(value, keys) {
|
|
|
9932
10026
|
return stripped;
|
|
9933
10027
|
}
|
|
9934
10028
|
// ../aft-bridge/dist/config-tiers.js
|
|
9935
|
-
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
9936
|
-
import { resolve as
|
|
10029
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
10030
|
+
import { resolve as resolve3 } from "node:path";
|
|
9937
10031
|
function readConfigTiers(opts) {
|
|
9938
10032
|
const tiers = [];
|
|
9939
10033
|
try {
|
|
9940
|
-
if (
|
|
10034
|
+
if (existsSync2(opts.userConfigPath)) {
|
|
9941
10035
|
const doc = readFileSync2(opts.userConfigPath, "utf-8");
|
|
9942
10036
|
tiers.push({
|
|
9943
10037
|
tier: "user",
|
|
9944
|
-
source:
|
|
10038
|
+
source: resolve3(opts.userConfigPath),
|
|
9945
10039
|
doc
|
|
9946
10040
|
});
|
|
9947
10041
|
}
|
|
9948
10042
|
} catch {}
|
|
9949
10043
|
try {
|
|
9950
|
-
if (
|
|
10044
|
+
if (existsSync2(opts.projectConfigPath)) {
|
|
9951
10045
|
const doc = readFileSync2(opts.projectConfigPath, "utf-8");
|
|
9952
10046
|
tiers.push({
|
|
9953
10047
|
tier: "project",
|
|
9954
|
-
source:
|
|
10048
|
+
source: resolve3(opts.projectConfigPath),
|
|
9955
10049
|
doc
|
|
9956
10050
|
});
|
|
9957
10051
|
}
|
|
@@ -9967,9 +10061,9 @@ function formatDroppedKeyWarnings(dropped) {
|
|
|
9967
10061
|
// ../aft-bridge/dist/downloader.js
|
|
9968
10062
|
import { spawnSync } from "node:child_process";
|
|
9969
10063
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
9970
|
-
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as
|
|
10064
|
+
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync3, mkdirSync, openSync, readdirSync, readFileSync as readFileSync3, renameSync, rmSync, statSync as statSync2, unlinkSync, writeSync } from "node:fs";
|
|
9971
10065
|
import { hostname } from "node:os";
|
|
9972
|
-
import { join as
|
|
10066
|
+
import { join as join6 } from "node:path";
|
|
9973
10067
|
import { Readable } from "node:stream";
|
|
9974
10068
|
import { pipeline } from "node:stream/promises";
|
|
9975
10069
|
|
|
@@ -10029,8 +10123,8 @@ function getBinaryName() {
|
|
|
10029
10123
|
function getCachedBinaryPath(version) {
|
|
10030
10124
|
if (!version)
|
|
10031
10125
|
return null;
|
|
10032
|
-
const binaryPath =
|
|
10033
|
-
return
|
|
10126
|
+
const binaryPath = join6(getAftBinaryCacheDir(), version, getBinaryName());
|
|
10127
|
+
return existsSync3(binaryPath) ? binaryPath : null;
|
|
10034
10128
|
}
|
|
10035
10129
|
async function downloadBinary(version) {
|
|
10036
10130
|
const archMap = PLATFORM_ARCH_MAP[process.platform] ?? {};
|
|
@@ -10046,16 +10140,16 @@ async function downloadBinary(version) {
|
|
|
10046
10140
|
return null;
|
|
10047
10141
|
}
|
|
10048
10142
|
const tag = rawTag.startsWith("v") ? rawTag : `v${rawTag}`;
|
|
10049
|
-
const versionedCacheDir =
|
|
10143
|
+
const versionedCacheDir = join6(getAftBinaryCacheDir(), tag);
|
|
10050
10144
|
const binaryName = getBinaryName();
|
|
10051
|
-
const binaryPath =
|
|
10052
|
-
if (
|
|
10145
|
+
const binaryPath = join6(versionedCacheDir, binaryName);
|
|
10146
|
+
if (existsSync3(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
|
|
10053
10147
|
return binaryPath;
|
|
10054
10148
|
}
|
|
10055
10149
|
const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
|
|
10056
10150
|
const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
|
|
10057
10151
|
log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
|
|
10058
|
-
const lockPath =
|
|
10152
|
+
const lockPath = join6(versionedCacheDir, ".download.lock");
|
|
10059
10153
|
let releaseLock = null;
|
|
10060
10154
|
let binaryController = null;
|
|
10061
10155
|
let checksumController = null;
|
|
@@ -10064,7 +10158,7 @@ async function downloadBinary(version) {
|
|
|
10064
10158
|
const tmpPath = `${binaryPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
10065
10159
|
const cleanUpPartialDownload = () => {
|
|
10066
10160
|
try {
|
|
10067
|
-
if (
|
|
10161
|
+
if (existsSync3(tmpPath))
|
|
10068
10162
|
unlinkSync(tmpPath);
|
|
10069
10163
|
} catch {}
|
|
10070
10164
|
};
|
|
@@ -10088,12 +10182,12 @@ async function downloadBinary(version) {
|
|
|
10088
10182
|
process.once("SIGINT", handleSigint);
|
|
10089
10183
|
process.once("exit", handleExit);
|
|
10090
10184
|
try {
|
|
10091
|
-
if (!
|
|
10185
|
+
if (!existsSync3(versionedCacheDir)) {
|
|
10092
10186
|
mkdirSync(versionedCacheDir, { recursive: true });
|
|
10093
10187
|
}
|
|
10094
10188
|
releaseLock = await acquireDownloadLock(lockPath);
|
|
10095
10189
|
sweepStaleDownloadTemps(versionedCacheDir, binaryName);
|
|
10096
|
-
if (
|
|
10190
|
+
if (existsSync3(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
|
|
10097
10191
|
return binaryPath;
|
|
10098
10192
|
}
|
|
10099
10193
|
binaryController = new AbortController;
|
|
@@ -10158,7 +10252,7 @@ async function downloadBinary(version) {
|
|
|
10158
10252
|
renameSync(tmpPath, binaryPath);
|
|
10159
10253
|
}
|
|
10160
10254
|
try {
|
|
10161
|
-
if (
|
|
10255
|
+
if (existsSync3(tmpPath))
|
|
10162
10256
|
unlinkSync(tmpPath);
|
|
10163
10257
|
} catch {
|
|
10164
10258
|
warn(`Could not clean up temporary download file ${tmpPath} — it can be removed manually.`);
|
|
@@ -10274,7 +10368,7 @@ function sweepStaleDownloadTemps(versionedCacheDir, binaryName) {
|
|
|
10274
10368
|
if (!entry.isFile() || !entry.name.startsWith(tempPrefix) || !entry.name.endsWith(".tmp")) {
|
|
10275
10369
|
continue;
|
|
10276
10370
|
}
|
|
10277
|
-
const tempPath =
|
|
10371
|
+
const tempPath = join6(versionedCacheDir, entry.name);
|
|
10278
10372
|
const ageMs = Date.now() - statSync2(tempPath).mtimeMs;
|
|
10279
10373
|
if (Math.abs(ageMs) > DOWNLOAD_LOCK_STALE_MS)
|
|
10280
10374
|
unlinkSync(tempPath);
|
|
@@ -10323,7 +10417,7 @@ async function acquireDownloadLock(lockPath, timing = {}) {
|
|
|
10323
10417
|
if (Date.now() - startedAt > timeoutMs) {
|
|
10324
10418
|
throw new Error(`Timed out waiting for download lock: ${lockPath}`);
|
|
10325
10419
|
}
|
|
10326
|
-
await new Promise((
|
|
10420
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollIntervalMs));
|
|
10327
10421
|
}
|
|
10328
10422
|
}
|
|
10329
10423
|
}
|
|
@@ -10361,51 +10455,6 @@ async function fetchLatestTag() {
|
|
|
10361
10455
|
// ../aft-bridge/dist/durable-log.js
|
|
10362
10456
|
import { appendFile, mkdir, rename, rm, stat } from "node:fs/promises";
|
|
10363
10457
|
import { dirname } from "node:path";
|
|
10364
|
-
|
|
10365
|
-
// ../aft-bridge/dist/storage-paths.js
|
|
10366
|
-
import { homedir as homedir5 } from "node:os";
|
|
10367
|
-
import { join as join5, resolve as resolve3 } from "node:path";
|
|
10368
|
-
function homeDir2() {
|
|
10369
|
-
if (process.platform === "win32")
|
|
10370
|
-
return process.env.USERPROFILE || process.env.HOME || homedir5();
|
|
10371
|
-
return process.env.HOME || homedir5();
|
|
10372
|
-
}
|
|
10373
|
-
function dataHome() {
|
|
10374
|
-
const xdg = process.env.XDG_DATA_HOME;
|
|
10375
|
-
if (xdg)
|
|
10376
|
-
return xdg;
|
|
10377
|
-
if (process.platform === "win32") {
|
|
10378
|
-
return process.env.LOCALAPPDATA || process.env.APPDATA || join5(homeDir2(), "AppData", "Local");
|
|
10379
|
-
}
|
|
10380
|
-
return join5(homeDir2(), ".local", "share");
|
|
10381
|
-
}
|
|
10382
|
-
function resolveStoragePath(raw) {
|
|
10383
|
-
let expanded = raw;
|
|
10384
|
-
if (raw === "~") {
|
|
10385
|
-
expanded = homeDir2();
|
|
10386
|
-
} else if (raw.startsWith("~/") || raw.startsWith("~\\")) {
|
|
10387
|
-
expanded = join5(homeDir2(), raw.slice(2));
|
|
10388
|
-
}
|
|
10389
|
-
return resolve3(expanded);
|
|
10390
|
-
}
|
|
10391
|
-
function resolveCortexKitStorageRoot() {
|
|
10392
|
-
const override = process.env.AFT_STORAGE_DIR;
|
|
10393
|
-
if (override)
|
|
10394
|
-
return resolveStoragePath(override);
|
|
10395
|
-
return resolveStoragePath(join5(dataHome(), "cortexkit", "aft"));
|
|
10396
|
-
}
|
|
10397
|
-
function resolveAftStorageRoot(configuredRoot) {
|
|
10398
|
-
if (process.env.AFT_STORAGE_DIR)
|
|
10399
|
-
return resolveCortexKitStorageRoot();
|
|
10400
|
-
if (configuredRoot)
|
|
10401
|
-
return configuredRoot;
|
|
10402
|
-
return resolveCortexKitStorageRoot();
|
|
10403
|
-
}
|
|
10404
|
-
function resolveAftLogPath(filename, configuredRoot) {
|
|
10405
|
-
return join5(resolveAftStorageRoot(configuredRoot), "logs", filename);
|
|
10406
|
-
}
|
|
10407
|
-
|
|
10408
|
-
// ../aft-bridge/dist/durable-log.js
|
|
10409
10458
|
var DEFAULT_LOG_BYTES = 32 * 1024 * 1024;
|
|
10410
10459
|
var DEFAULT_LOG_GENERATIONS = 1;
|
|
10411
10460
|
class RotatingLogSink {
|
|
@@ -12040,7 +12089,7 @@ function pendingKey(handle, corr) {
|
|
|
12040
12089
|
return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
|
|
12041
12090
|
}
|
|
12042
12091
|
// ../aft-bridge/dist/subc-transport.js
|
|
12043
|
-
import { existsSync as
|
|
12092
|
+
import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
|
|
12044
12093
|
|
|
12045
12094
|
// ../aft-bridge/dist/lifecycle-registry.js
|
|
12046
12095
|
import { lstat } from "node:fs/promises";
|
|
@@ -13049,7 +13098,7 @@ class SubcTransportPool {
|
|
|
13049
13098
|
this.dormantRoots.delete(root);
|
|
13050
13099
|
return true;
|
|
13051
13100
|
}
|
|
13052
|
-
const reclaimedMarkerPresent =
|
|
13101
|
+
const reclaimedMarkerPresent = existsSync4(`${root}.reclaimed`);
|
|
13053
13102
|
if (reclaimedMarkerPresent) {
|
|
13054
13103
|
this.markRootDormant(root);
|
|
13055
13104
|
return false;
|
|
@@ -13881,14 +13930,14 @@ function stripJsoncSymbols(value) {
|
|
|
13881
13930
|
}
|
|
13882
13931
|
// ../aft-bridge/dist/migration.js
|
|
13883
13932
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
13884
|
-
import { closeSync as closeSync3, existsSync as
|
|
13933
|
+
import { closeSync as closeSync3, existsSync as existsSync7, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
13885
13934
|
import { homedir as homedir8, tmpdir } from "node:os";
|
|
13886
|
-
import { basename, dirname as dirname3, join as
|
|
13935
|
+
import { basename, dirname as dirname3, join as join9, resolve as resolve6 } from "node:path";
|
|
13887
13936
|
|
|
13888
13937
|
// ../aft-bridge/dist/paths.js
|
|
13889
|
-
import { existsSync as
|
|
13938
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
|
|
13890
13939
|
import { homedir as homedir6 } from "node:os";
|
|
13891
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, join as
|
|
13940
|
+
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join7, resolve as resolve5 } from "node:path";
|
|
13892
13941
|
function homeDir3() {
|
|
13893
13942
|
if (process.platform === "win32")
|
|
13894
13943
|
return process.env.USERPROFILE || process.env.HOME || homedir6();
|
|
@@ -13898,16 +13947,16 @@ function configHome() {
|
|
|
13898
13947
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
13899
13948
|
if (xdg && isAbsolute2(xdg))
|
|
13900
13949
|
return xdg;
|
|
13901
|
-
return
|
|
13950
|
+
return join7(homeDir3(), ".config");
|
|
13902
13951
|
}
|
|
13903
13952
|
function legacyOpenCodeConfigDir() {
|
|
13904
13953
|
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
13905
13954
|
if (envDir)
|
|
13906
13955
|
return resolve5(envDir);
|
|
13907
|
-
return
|
|
13956
|
+
return join7(configHome(), "opencode");
|
|
13908
13957
|
}
|
|
13909
13958
|
function legacyPiAgentDir() {
|
|
13910
|
-
return
|
|
13959
|
+
return join7(homeDir3(), ".pi", "agent");
|
|
13911
13960
|
}
|
|
13912
13961
|
function legacySources(basePath, label, harness) {
|
|
13913
13962
|
return [
|
|
@@ -13916,10 +13965,10 @@ function legacySources(basePath, label, harness) {
|
|
|
13916
13965
|
];
|
|
13917
13966
|
}
|
|
13918
13967
|
function resolveCortexKitUserConfigPath() {
|
|
13919
|
-
return
|
|
13968
|
+
return join7(configHome(), "cortexkit", "aft.jsonc");
|
|
13920
13969
|
}
|
|
13921
13970
|
function resolveCortexKitProjectConfigPath(projectDirectory) {
|
|
13922
|
-
return
|
|
13971
|
+
return join7(projectDirectory, ".cortexkit", "aft.jsonc");
|
|
13923
13972
|
}
|
|
13924
13973
|
function resolveCortexKitConfigPaths(projectDirectory) {
|
|
13925
13974
|
return {
|
|
@@ -13930,22 +13979,22 @@ function resolveCortexKitConfigPaths(projectDirectory) {
|
|
|
13930
13979
|
function resolveLegacyAftConfigSources(projectDirectory) {
|
|
13931
13980
|
return {
|
|
13932
13981
|
user: [
|
|
13933
|
-
...legacySources(
|
|
13934
|
-
...legacySources(
|
|
13982
|
+
...legacySources(join7(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
|
|
13983
|
+
...legacySources(join7(legacyPiAgentDir(), "aft"), "Pi user", "pi")
|
|
13935
13984
|
],
|
|
13936
13985
|
project: [
|
|
13937
|
-
...legacySources(
|
|
13938
|
-
...legacySources(
|
|
13986
|
+
...legacySources(join7(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
|
|
13987
|
+
...legacySources(join7(projectDirectory, ".pi", "aft"), "Pi project", "pi")
|
|
13939
13988
|
]
|
|
13940
13989
|
};
|
|
13941
13990
|
}
|
|
13942
13991
|
function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
|
|
13943
|
-
return
|
|
13992
|
+
return join7(storageRoot, harness, ...segments);
|
|
13944
13993
|
}
|
|
13945
13994
|
function repairRootScopedStorageFile(storageRoot, harness, fileName) {
|
|
13946
13995
|
const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
|
|
13947
|
-
const rootPath =
|
|
13948
|
-
if (
|
|
13996
|
+
const rootPath = join7(storageRoot, fileName);
|
|
13997
|
+
if (existsSync5(harnessPath) || !existsSync5(rootPath))
|
|
13949
13998
|
return harnessPath;
|
|
13950
13999
|
try {
|
|
13951
14000
|
mkdirSync2(dirname2(harnessPath), { recursive: true });
|
|
@@ -13959,7 +14008,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
|
|
|
13959
14008
|
const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
|
|
13960
14009
|
let lastVersion = "";
|
|
13961
14010
|
try {
|
|
13962
|
-
if (
|
|
14011
|
+
if (existsSync5(versionFile)) {
|
|
13963
14012
|
lastVersion = readFileSync4(versionFile, "utf-8").trim();
|
|
13964
14013
|
}
|
|
13965
14014
|
} catch {
|
|
@@ -14031,10 +14080,10 @@ function decodeFileUrl(target) {
|
|
|
14031
14080
|
|
|
14032
14081
|
// ../aft-bridge/dist/resolver.js
|
|
14033
14082
|
import { execSync } from "node:child_process";
|
|
14034
|
-
import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as
|
|
14083
|
+
import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
|
|
14035
14084
|
import { createRequire as createRequire2 } from "node:module";
|
|
14036
14085
|
import { homedir as homedir7 } from "node:os";
|
|
14037
|
-
import { join as
|
|
14086
|
+
import { join as join8 } from "node:path";
|
|
14038
14087
|
var ensureBinaryForResolver = ensureBinary;
|
|
14039
14088
|
function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
14040
14089
|
try {
|
|
@@ -14043,10 +14092,10 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
14043
14092
|
return null;
|
|
14044
14093
|
const tag = version.startsWith("v") ? version : `v${version}`;
|
|
14045
14094
|
const cacheDir = getAftBinaryCacheDir();
|
|
14046
|
-
const versionedDir =
|
|
14095
|
+
const versionedDir = join8(cacheDir, tag);
|
|
14047
14096
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
14048
|
-
const cachedPath =
|
|
14049
|
-
if (
|
|
14097
|
+
const cachedPath = join8(versionedDir, `aft${ext}`);
|
|
14098
|
+
if (existsSync6(cachedPath)) {
|
|
14050
14099
|
const cachedVersion = readBinaryVersion(cachedPath);
|
|
14051
14100
|
if (cachedVersion === version)
|
|
14052
14101
|
return cachedPath;
|
|
@@ -14058,7 +14107,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
14058
14107
|
if (process.platform !== "win32") {
|
|
14059
14108
|
chmodSync2(tmpPath, 493);
|
|
14060
14109
|
}
|
|
14061
|
-
if (process.platform === "win32" &&
|
|
14110
|
+
if (process.platform === "win32" && existsSync6(cachedPath)) {
|
|
14062
14111
|
try {
|
|
14063
14112
|
unlinkSync2(cachedPath);
|
|
14064
14113
|
} catch {}
|
|
@@ -14078,8 +14127,8 @@ function homeDirFromEnv(env) {
|
|
|
14078
14127
|
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir7();
|
|
14079
14128
|
}
|
|
14080
14129
|
function cachedBinaryPathFromEnv(version, env, ext) {
|
|
14081
|
-
const binaryPath =
|
|
14082
|
-
return
|
|
14130
|
+
const binaryPath = join8(getAftBinaryCacheDir(env), version, `aft${ext}`);
|
|
14131
|
+
return existsSync6(binaryPath) ? binaryPath : null;
|
|
14083
14132
|
}
|
|
14084
14133
|
function isExpectedCachedBinary2(binaryPath, expectedVersion) {
|
|
14085
14134
|
const expected = normalizeBareVersion(expectedVersion);
|
|
@@ -14178,7 +14227,7 @@ function findBinarySyncInner(expectedVersion) {
|
|
|
14178
14227
|
const packageBin = `@cortexkit/aft-${key}/bin/aft${ext}`;
|
|
14179
14228
|
const req = createRequire2(import.meta.url);
|
|
14180
14229
|
const resolved = req.resolve(packageBin);
|
|
14181
|
-
if (
|
|
14230
|
+
if (existsSync6(resolved)) {
|
|
14182
14231
|
const npmVersion = readBinaryVersion(resolved);
|
|
14183
14232
|
if (npmVersion === null) {
|
|
14184
14233
|
warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
|
|
@@ -14207,8 +14256,8 @@ function findBinarySyncInner(expectedVersion) {
|
|
|
14207
14256
|
return { path: usable, source: "PATH" };
|
|
14208
14257
|
}
|
|
14209
14258
|
} catch {}
|
|
14210
|
-
const cargoPath =
|
|
14211
|
-
if (
|
|
14259
|
+
const cargoPath = join8(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
|
|
14260
|
+
if (existsSync6(cargoPath)) {
|
|
14212
14261
|
const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
|
|
14213
14262
|
if (usable)
|
|
14214
14263
|
return { path: usable, source: "cargo" };
|
|
@@ -14254,9 +14303,9 @@ function dataHome2() {
|
|
|
14254
14303
|
if (process.env.XDG_DATA_HOME)
|
|
14255
14304
|
return process.env.XDG_DATA_HOME;
|
|
14256
14305
|
if (process.platform === "win32") {
|
|
14257
|
-
return process.env.LOCALAPPDATA || process.env.APPDATA ||
|
|
14306
|
+
return process.env.LOCALAPPDATA || process.env.APPDATA || join9(homeDir4(), "AppData", "Local");
|
|
14258
14307
|
}
|
|
14259
|
-
return
|
|
14308
|
+
return join9(homeDir4(), ".local", "share");
|
|
14260
14309
|
}
|
|
14261
14310
|
function homeDir4() {
|
|
14262
14311
|
if (process.platform === "win32")
|
|
@@ -14265,8 +14314,8 @@ function homeDir4() {
|
|
|
14265
14314
|
}
|
|
14266
14315
|
function resolveLegacyStorageRoot(harness) {
|
|
14267
14316
|
if (harness === "pi")
|
|
14268
|
-
return
|
|
14269
|
-
return
|
|
14317
|
+
return join9(homeDir4(), ".pi", "agent", "aft");
|
|
14318
|
+
return join9(dataHome2(), "opencode", "storage", "plugin", "aft");
|
|
14270
14319
|
}
|
|
14271
14320
|
function stripJsoncForParse(input) {
|
|
14272
14321
|
let out = "";
|
|
@@ -14396,7 +14445,7 @@ function acquireConfigMigrationLock(lockDir) {
|
|
|
14396
14445
|
}
|
|
14397
14446
|
function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
14398
14447
|
mkdirSync4(dirname3(targetPath), { recursive: true });
|
|
14399
|
-
const tmpPath =
|
|
14448
|
+
const tmpPath = join9(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
14400
14449
|
let fd = null;
|
|
14401
14450
|
try {
|
|
14402
14451
|
fd = openSync3(tmpPath, "wx", 384);
|
|
@@ -14418,7 +14467,7 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
|
14418
14467
|
}
|
|
14419
14468
|
function atomicWriteConfigFile(targetPath, content) {
|
|
14420
14469
|
mkdirSync4(dirname3(targetPath), { recursive: true });
|
|
14421
|
-
const tmpPath =
|
|
14470
|
+
const tmpPath = join9(dirname3(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
14422
14471
|
let fd = null;
|
|
14423
14472
|
try {
|
|
14424
14473
|
fd = openSync3(tmpPath, "wx", 384);
|
|
@@ -14440,11 +14489,11 @@ function atomicWriteConfigFile(targetPath, content) {
|
|
|
14440
14489
|
}
|
|
14441
14490
|
var MOVED_MARKER_SUFFIX = ".MOVED_READPLEASE";
|
|
14442
14491
|
function nonClobberingSidecarPath(desiredPath) {
|
|
14443
|
-
if (!
|
|
14492
|
+
if (!existsSync7(desiredPath))
|
|
14444
14493
|
return desiredPath;
|
|
14445
14494
|
for (let index = 1;index < Number.MAX_SAFE_INTEGER; index++) {
|
|
14446
14495
|
const candidate = `${desiredPath}.${index}`;
|
|
14447
|
-
if (!
|
|
14496
|
+
if (!existsSync7(candidate))
|
|
14448
14497
|
return candidate;
|
|
14449
14498
|
}
|
|
14450
14499
|
throw new Error(`could not find available preservation sidecar path for ${desiredPath}`);
|
|
@@ -14538,7 +14587,7 @@ function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
|
|
|
14538
14587
|
function migrateAftConfigFile(opts) {
|
|
14539
14588
|
const warnings = [];
|
|
14540
14589
|
const resolvedTarget = resolve6(opts.targetPath);
|
|
14541
|
-
const existingSources = opts.legacySources.filter((source) =>
|
|
14590
|
+
const existingSources = opts.legacySources.filter((source) => existsSync7(source.path) && resolve6(source.path) !== resolvedTarget);
|
|
14542
14591
|
const info = opts.logger?.info ?? opts.logger?.log;
|
|
14543
14592
|
if (existingSources.length === 0) {
|
|
14544
14593
|
return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
|
|
@@ -14550,7 +14599,7 @@ function migrateAftConfigFile(opts) {
|
|
|
14550
14599
|
...source,
|
|
14551
14600
|
content: readFileSync5(source.path, "utf-8")
|
|
14552
14601
|
}));
|
|
14553
|
-
if (
|
|
14602
|
+
if (existsSync7(opts.targetPath)) {
|
|
14554
14603
|
const targetContent = readFileSync5(opts.targetPath, "utf-8");
|
|
14555
14604
|
for (const source of sources) {
|
|
14556
14605
|
if (fileSemanticsMatch(source.content, targetContent))
|
|
@@ -14600,12 +14649,12 @@ function spawnErrorLabel(error2) {
|
|
|
14600
14649
|
return [code, error2.message].filter(Boolean).join(": ");
|
|
14601
14650
|
}
|
|
14602
14651
|
function migrationLogPath(newRoot, harness, logger) {
|
|
14603
|
-
const desired =
|
|
14652
|
+
const desired = join9(newRoot, "logs", "migration", `${harness}-${Date.now()}.jsonl`);
|
|
14604
14653
|
try {
|
|
14605
14654
|
mkdirSync4(dirname3(desired), { recursive: true });
|
|
14606
14655
|
return desired;
|
|
14607
14656
|
} catch (err) {
|
|
14608
|
-
const fallback =
|
|
14657
|
+
const fallback = join9(tmpdir(), `aft-migration-${harness}-${Date.now()}.jsonl`);
|
|
14609
14658
|
logger?.warn?.(`Failed to create AFT migration log directory ${dirname3(desired)}: ${err instanceof Error ? err.message : String(err)}. ` + `Using fallback log path ${fallback}.`);
|
|
14610
14659
|
return fallback;
|
|
14611
14660
|
}
|
|
@@ -14615,11 +14664,11 @@ async function ensureStorageMigrated(opts) {
|
|
|
14615
14664
|
const newRoot = resolveCortexKitStorageRoot();
|
|
14616
14665
|
const targetMarker = resolveHarnessStoragePath(newRoot, opts.harness, TARGET_MARKER);
|
|
14617
14666
|
const info = opts.logger?.info ?? opts.logger?.log;
|
|
14618
|
-
if (
|
|
14667
|
+
if (existsSync7(targetMarker)) {
|
|
14619
14668
|
info?.(`AFT storage already migrated for ${opts.harness}; using ${newRoot}`);
|
|
14620
14669
|
return;
|
|
14621
14670
|
}
|
|
14622
|
-
if (!
|
|
14671
|
+
if (!existsSync7(legacyRoot)) {
|
|
14623
14672
|
info?.(`AFT storage migration skipped for ${opts.harness}: no legacy data at ${legacyRoot}; ` + `using ${newRoot} for fresh install`);
|
|
14624
14673
|
return;
|
|
14625
14674
|
}
|
|
@@ -14667,9 +14716,10 @@ async function ensureStorageMigrated(opts) {
|
|
|
14667
14716
|
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}` : ""));
|
|
14668
14717
|
}
|
|
14669
14718
|
// ../aft-bridge/dist/npm-resolver.js
|
|
14719
|
+
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
14670
14720
|
import { readdirSync as readdirSync2, statSync as statSync5 } from "node:fs";
|
|
14671
14721
|
import { homedir as homedir9 } from "node:os";
|
|
14672
|
-
import { delimiter, dirname as dirname4, isAbsolute as isAbsolute3, join as
|
|
14722
|
+
import { delimiter as delimiter2, dirname as dirname4, isAbsolute as isAbsolute3, join as join10 } from "node:path";
|
|
14673
14723
|
function defaultDeps() {
|
|
14674
14724
|
return {
|
|
14675
14725
|
platform: process.platform,
|
|
@@ -14691,18 +14741,18 @@ function isFile(p) {
|
|
|
14691
14741
|
function npmFromPath(deps) {
|
|
14692
14742
|
const name = npmBinaryName(deps.platform);
|
|
14693
14743
|
const raw = deps.env.PATH ?? deps.env.Path ?? "";
|
|
14694
|
-
for (const entry of raw.split(
|
|
14744
|
+
for (const entry of raw.split(delimiter2)) {
|
|
14695
14745
|
const dir = entry.trim().replace(/^"|"$/g, "");
|
|
14696
14746
|
if (!dir || !isAbsolute3(dir))
|
|
14697
14747
|
continue;
|
|
14698
|
-
if (isFile(
|
|
14748
|
+
if (isFile(join10(dir, name)))
|
|
14699
14749
|
return dir;
|
|
14700
14750
|
}
|
|
14701
14751
|
return null;
|
|
14702
14752
|
}
|
|
14703
14753
|
function npmAdjacentToNode(deps) {
|
|
14704
14754
|
const dir = dirname4(deps.execPath);
|
|
14705
|
-
return isFile(
|
|
14755
|
+
return isFile(join10(dir, npmBinaryName(deps.platform))) ? dir : null;
|
|
14706
14756
|
}
|
|
14707
14757
|
function highestVersionedNodeBin(installsDir, name) {
|
|
14708
14758
|
let entries;
|
|
@@ -14711,8 +14761,8 @@ function highestVersionedNodeBin(installsDir, name) {
|
|
|
14711
14761
|
} catch {
|
|
14712
14762
|
return null;
|
|
14713
14763
|
}
|
|
14714
|
-
const candidates = entries.filter((v) => isFile(
|
|
14715
|
-
return candidates.length > 0 ?
|
|
14764
|
+
const candidates = entries.filter((v) => isFile(join10(installsDir, v, "bin", name))).sort((a, b) => compareVersionsDesc(a, b));
|
|
14765
|
+
return candidates.length > 0 ? join10(installsDir, candidates[0], "bin") : null;
|
|
14716
14766
|
}
|
|
14717
14767
|
function compareVersionsDesc(a, b) {
|
|
14718
14768
|
const pa = a.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10));
|
|
@@ -14737,22 +14787,22 @@ function wellKnownNpmDirs(deps) {
|
|
|
14737
14787
|
const programFiles = env.ProgramFiles || "C:\\Program Files";
|
|
14738
14788
|
const appData = env.APPDATA;
|
|
14739
14789
|
const localAppData = env.LOCALAPPDATA;
|
|
14740
|
-
push(
|
|
14790
|
+
push(join10(programFiles, "nodejs"));
|
|
14741
14791
|
if (appData)
|
|
14742
|
-
push(
|
|
14792
|
+
push(join10(appData, "npm"));
|
|
14743
14793
|
if (localAppData)
|
|
14744
|
-
push(
|
|
14794
|
+
push(join10(localAppData, "Volta", "bin"));
|
|
14745
14795
|
if (env.NVM_SYMLINK)
|
|
14746
14796
|
push(env.NVM_SYMLINK);
|
|
14747
14797
|
} else {
|
|
14748
14798
|
if (env.NVM_BIN)
|
|
14749
14799
|
push(env.NVM_BIN);
|
|
14750
|
-
push(highestVersionedNodeBin(
|
|
14751
|
-
push(highestVersionedNodeBin(
|
|
14752
|
-
push(highestVersionedNodeBin(
|
|
14753
|
-
push(
|
|
14754
|
-
push(
|
|
14755
|
-
const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin",
|
|
14800
|
+
push(highestVersionedNodeBin(join10(home, ".nvm", "versions", "node"), name));
|
|
14801
|
+
push(highestVersionedNodeBin(join10(home, ".local", "share", "mise", "installs", "node"), name));
|
|
14802
|
+
push(highestVersionedNodeBin(join10(home, ".asdf", "installs", "nodejs"), name));
|
|
14803
|
+
push(join10(home, ".volta", "bin"));
|
|
14804
|
+
push(join10(home, ".asdf", "shims"));
|
|
14805
|
+
const systemDirs = deps.systemNpmDirs ?? (platform === "darwin" ? ["/opt/homebrew/bin", "/usr/local/bin"] : ["/usr/local/bin", "/usr/bin", join10(home, ".local", "bin")]);
|
|
14756
14806
|
for (const dir of systemDirs)
|
|
14757
14807
|
push(dir);
|
|
14758
14808
|
}
|
|
@@ -14762,29 +14812,212 @@ function resolveNpm(deps = defaultDeps()) {
|
|
|
14762
14812
|
const name = npmBinaryName(deps.platform);
|
|
14763
14813
|
const onPath = npmFromPath(deps);
|
|
14764
14814
|
if (onPath)
|
|
14765
|
-
return { command:
|
|
14815
|
+
return { command: join10(onPath, name), binDir: onPath };
|
|
14766
14816
|
const adjacent = npmAdjacentToNode(deps);
|
|
14767
14817
|
if (adjacent)
|
|
14768
|
-
return { command:
|
|
14818
|
+
return { command: join10(adjacent, name), binDir: adjacent };
|
|
14769
14819
|
for (const dir of wellKnownNpmDirs(deps)) {
|
|
14770
|
-
const candidate =
|
|
14820
|
+
const candidate = join10(dir, name);
|
|
14771
14821
|
if (isFile(candidate))
|
|
14772
14822
|
return { command: candidate, binDir: dir };
|
|
14773
14823
|
}
|
|
14774
14824
|
return null;
|
|
14775
14825
|
}
|
|
14826
|
+
function quoteCmdArgument(value) {
|
|
14827
|
+
if (/[\0\r\n"%]/.test(value)) {
|
|
14828
|
+
throw new Error(`npm argument cannot be represented safely for cmd.exe: ${JSON.stringify(value)}`);
|
|
14829
|
+
}
|
|
14830
|
+
return `"${value}"`;
|
|
14831
|
+
}
|
|
14832
|
+
function npmInvocation(resolved, npmArgs, platform = process.platform, env = process.env) {
|
|
14833
|
+
if (platform !== "win32" || !/\.(?:cmd|bat)$/i.test(resolved.command)) {
|
|
14834
|
+
return { command: resolved.command, args: [...npmArgs] };
|
|
14835
|
+
}
|
|
14836
|
+
if (/[\0\r\n"]/.test(resolved.command)) {
|
|
14837
|
+
throw new Error(`npm command cannot be represented safely for cmd.exe: ${JSON.stringify(resolved.command)}`);
|
|
14838
|
+
}
|
|
14839
|
+
const commandEnvName = "AFT_NPM_COMMAND";
|
|
14840
|
+
const quotedArgs = npmArgs.map(quoteCmdArgument);
|
|
14841
|
+
const commandLine = `""%${commandEnvName}%"${quotedArgs.length > 0 ? ` ${quotedArgs.join(" ")}` : ""}"`;
|
|
14842
|
+
return {
|
|
14843
|
+
command: env.ComSpec ?? env.COMSPEC ?? "cmd.exe",
|
|
14844
|
+
args: ["/d", "/s", "/v:off", "/c", commandLine],
|
|
14845
|
+
env: { [commandEnvName]: resolved.command },
|
|
14846
|
+
windowsVerbatimArguments: true,
|
|
14847
|
+
windowsCmdShim: true
|
|
14848
|
+
};
|
|
14849
|
+
}
|
|
14850
|
+
|
|
14851
|
+
class NpmTerminationUnknownError extends Error {
|
|
14852
|
+
code = "npm_termination_unknown";
|
|
14853
|
+
constructor(detail) {
|
|
14854
|
+
super(`npm process-tree termination could not be confirmed: ${detail}`);
|
|
14855
|
+
this.name = "NpmTerminationUnknownError";
|
|
14856
|
+
}
|
|
14857
|
+
}
|
|
14858
|
+
function terminateDirectNpmChild(child, gracePeriodMs) {
|
|
14859
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
14860
|
+
return Promise.resolve();
|
|
14861
|
+
return new Promise((resolve7, reject) => {
|
|
14862
|
+
let settled = false;
|
|
14863
|
+
let forceTimer = null;
|
|
14864
|
+
let confirmationTimer = null;
|
|
14865
|
+
let signalFailure = null;
|
|
14866
|
+
const cleanup = () => {
|
|
14867
|
+
if (forceTimer)
|
|
14868
|
+
clearTimeout(forceTimer);
|
|
14869
|
+
if (confirmationTimer)
|
|
14870
|
+
clearTimeout(confirmationTimer);
|
|
14871
|
+
child.removeListener("exit", finish);
|
|
14872
|
+
child.removeListener("error", onChildError);
|
|
14873
|
+
};
|
|
14874
|
+
const finish = () => {
|
|
14875
|
+
if (settled)
|
|
14876
|
+
return;
|
|
14877
|
+
settled = true;
|
|
14878
|
+
cleanup();
|
|
14879
|
+
resolve7();
|
|
14880
|
+
};
|
|
14881
|
+
const fail = () => {
|
|
14882
|
+
if (settled)
|
|
14883
|
+
return;
|
|
14884
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
14885
|
+
finish();
|
|
14886
|
+
return;
|
|
14887
|
+
}
|
|
14888
|
+
settled = true;
|
|
14889
|
+
cleanup();
|
|
14890
|
+
reject(new NpmTerminationUnknownError(signalFailure ?? `direct npm child did not exit after SIGKILL within ${gracePeriodMs}ms`));
|
|
14891
|
+
};
|
|
14892
|
+
const onChildError = (error2) => {
|
|
14893
|
+
signalFailure = `direct npm child error during termination: ${String(error2)}`;
|
|
14894
|
+
};
|
|
14895
|
+
const signal = (value) => {
|
|
14896
|
+
try {
|
|
14897
|
+
if (!child.kill(value)) {
|
|
14898
|
+
signalFailure = `direct npm child rejected ${value ?? "SIGTERM"}`;
|
|
14899
|
+
}
|
|
14900
|
+
} catch (error2) {
|
|
14901
|
+
signalFailure = `direct npm child ${value ?? "SIGTERM"} failed: ${String(error2)}`;
|
|
14902
|
+
}
|
|
14903
|
+
};
|
|
14904
|
+
child.once("exit", finish);
|
|
14905
|
+
child.on("error", onChildError);
|
|
14906
|
+
forceTimer = setTimeout(() => {
|
|
14907
|
+
signal("SIGKILL");
|
|
14908
|
+
confirmationTimer = setTimeout(fail, gracePeriodMs);
|
|
14909
|
+
}, gracePeriodMs);
|
|
14910
|
+
signal();
|
|
14911
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
14912
|
+
finish();
|
|
14913
|
+
});
|
|
14914
|
+
}
|
|
14915
|
+
function terminateNpmProcessTree(child, invocation, env = process.env, gracePeriodMs = 5000) {
|
|
14916
|
+
if (!invocation.windowsCmdShim)
|
|
14917
|
+
return terminateDirectNpmChild(child, gracePeriodMs);
|
|
14918
|
+
const exitedSuccessfully = () => child.exitCode === 0 && child.signalCode === null;
|
|
14919
|
+
if (exitedSuccessfully())
|
|
14920
|
+
return Promise.resolve();
|
|
14921
|
+
if (child.pid === undefined) {
|
|
14922
|
+
return Promise.reject(new NpmTerminationUnknownError("cmd.exe child has no process ID"));
|
|
14923
|
+
}
|
|
14924
|
+
return new Promise((resolve7, reject) => {
|
|
14925
|
+
let settled = false;
|
|
14926
|
+
let childExited = child.exitCode !== null || child.signalCode !== null;
|
|
14927
|
+
let treeKillConfirmed = false;
|
|
14928
|
+
let treeKillFailure = null;
|
|
14929
|
+
let killer = null;
|
|
14930
|
+
const timeout = setTimeout(() => {
|
|
14931
|
+
try {
|
|
14932
|
+
killer?.kill();
|
|
14933
|
+
} catch {}
|
|
14934
|
+
if (treeKillConfirmed || exitedSuccessfully()) {
|
|
14935
|
+
settled = true;
|
|
14936
|
+
cleanup();
|
|
14937
|
+
resolve7();
|
|
14938
|
+
return;
|
|
14939
|
+
}
|
|
14940
|
+
fail(treeKillFailure ?? `taskkill.exe did not finish within ${gracePeriodMs}ms`);
|
|
14941
|
+
}, gracePeriodMs);
|
|
14942
|
+
const cleanup = () => {
|
|
14943
|
+
clearTimeout(timeout);
|
|
14944
|
+
child.removeListener("exit", onChildExit);
|
|
14945
|
+
};
|
|
14946
|
+
const succeedIfConfirmed = () => {
|
|
14947
|
+
if (settled || !childExited || !treeKillConfirmed)
|
|
14948
|
+
return;
|
|
14949
|
+
settled = true;
|
|
14950
|
+
cleanup();
|
|
14951
|
+
resolve7();
|
|
14952
|
+
};
|
|
14953
|
+
const fail = (detail) => {
|
|
14954
|
+
if (settled)
|
|
14955
|
+
return;
|
|
14956
|
+
settled = true;
|
|
14957
|
+
cleanup();
|
|
14958
|
+
reject(new NpmTerminationUnknownError(detail));
|
|
14959
|
+
};
|
|
14960
|
+
function onChildExit() {
|
|
14961
|
+
childExited = true;
|
|
14962
|
+
if (treeKillFailure !== null) {
|
|
14963
|
+
if (exitedSuccessfully()) {
|
|
14964
|
+
settled = true;
|
|
14965
|
+
cleanup();
|
|
14966
|
+
resolve7();
|
|
14967
|
+
} else {
|
|
14968
|
+
fail(treeKillFailure);
|
|
14969
|
+
}
|
|
14970
|
+
return;
|
|
14971
|
+
}
|
|
14972
|
+
succeedIfConfirmed();
|
|
14973
|
+
}
|
|
14974
|
+
const recordTreeKillFailure = (detail) => {
|
|
14975
|
+
if (settled)
|
|
14976
|
+
return;
|
|
14977
|
+
if (exitedSuccessfully()) {
|
|
14978
|
+
settled = true;
|
|
14979
|
+
cleanup();
|
|
14980
|
+
resolve7();
|
|
14981
|
+
return;
|
|
14982
|
+
}
|
|
14983
|
+
treeKillFailure = detail;
|
|
14984
|
+
if (childExited)
|
|
14985
|
+
fail(detail);
|
|
14986
|
+
};
|
|
14987
|
+
child.once("exit", onChildExit);
|
|
14988
|
+
const systemRoot = env.SystemRoot ?? env.SYSTEMROOT;
|
|
14989
|
+
const taskkill = systemRoot ? join10(systemRoot, "System32", "taskkill.exe") : "taskkill.exe";
|
|
14990
|
+
try {
|
|
14991
|
+
killer = spawn3(taskkill, ["/pid", String(child.pid), "/t", "/f"], {
|
|
14992
|
+
stdio: "ignore",
|
|
14993
|
+
windowsHide: true
|
|
14994
|
+
});
|
|
14995
|
+
killer.once("error", (error2) => recordTreeKillFailure(`taskkill.exe failed to start: ${String(error2)}`));
|
|
14996
|
+
killer.once("exit", (code) => {
|
|
14997
|
+
if (code !== 0) {
|
|
14998
|
+
recordTreeKillFailure(`taskkill.exe exited with code ${code ?? "unknown"}`);
|
|
14999
|
+
return;
|
|
15000
|
+
}
|
|
15001
|
+
treeKillConfirmed = true;
|
|
15002
|
+
succeedIfConfirmed();
|
|
15003
|
+
});
|
|
15004
|
+
} catch (error2) {
|
|
15005
|
+
recordTreeKillFailure(`taskkill.exe failed to start: ${String(error2)}`);
|
|
15006
|
+
}
|
|
15007
|
+
});
|
|
15008
|
+
}
|
|
14776
15009
|
function npmSpawnEnv(resolved, baseEnv = process.env) {
|
|
14777
15010
|
if (!resolved.binDir)
|
|
14778
15011
|
return { ...baseEnv };
|
|
14779
15012
|
const existing = baseEnv.PATH ?? baseEnv.Path ?? "";
|
|
14780
|
-
const next = existing ? `${resolved.binDir}${
|
|
15013
|
+
const next = existing ? `${resolved.binDir}${delimiter2}${existing}` : resolved.binDir;
|
|
14781
15014
|
return { ...baseEnv, PATH: next };
|
|
14782
15015
|
}
|
|
14783
15016
|
// ../aft-bridge/dist/onnx-runtime.js
|
|
14784
15017
|
import { execFileSync } from "node:child_process";
|
|
14785
15018
|
import { createHash as createHash3 } from "node:crypto";
|
|
14786
|
-
import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as
|
|
14787
|
-
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as
|
|
15019
|
+
import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync8, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync3, readFileSync as readFileSync6, readlinkSync, realpathSync as realpathSync2, rmSync as rmSync3, statSync as statSync6, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
15020
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute4, join as join11, relative as relative2, resolve as resolve7, win32 } from "node:path";
|
|
14788
15021
|
import { Readable as Readable2 } from "node:stream";
|
|
14789
15022
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
14790
15023
|
var ORT_VERSION = "1.24.4";
|
|
@@ -14847,11 +15080,11 @@ function getManualInstallHint() {
|
|
|
14847
15080
|
}
|
|
14848
15081
|
async function ensureOnnxRuntime(storageDir) {
|
|
14849
15082
|
const info = getPlatformInfo();
|
|
14850
|
-
const ortVersionDir =
|
|
15083
|
+
const ortVersionDir = join11(storageDir, "onnxruntime", ORT_VERSION);
|
|
14851
15084
|
const libName = info?.libName ?? "libonnxruntime.dylib";
|
|
14852
15085
|
const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
|
|
14853
|
-
const libPath =
|
|
14854
|
-
if (
|
|
15086
|
+
const libPath = join11(resolvedOrtDir, libName);
|
|
15087
|
+
if (existsSync8(libPath)) {
|
|
14855
15088
|
const meta = readOnnxInstalledMeta(ortVersionDir);
|
|
14856
15089
|
if (meta?.sha256) {
|
|
14857
15090
|
try {
|
|
@@ -14880,9 +15113,9 @@ async function ensureOnnxRuntime(storageDir) {
|
|
|
14880
15113
|
warn(`ONNX Runtime auto-download not available for ${process.platform}/${process.arch}. Install manually: ${getManualInstallHint()}`);
|
|
14881
15114
|
return null;
|
|
14882
15115
|
}
|
|
14883
|
-
const onnxBaseDir =
|
|
15116
|
+
const onnxBaseDir = join11(storageDir, "onnxruntime");
|
|
14884
15117
|
mkdirSync5(onnxBaseDir, { recursive: true });
|
|
14885
|
-
const lockPath =
|
|
15118
|
+
const lockPath = join11(onnxBaseDir, ONNX_LOCK_FILE);
|
|
14886
15119
|
cleanupAbandonedStagingDirs(onnxBaseDir);
|
|
14887
15120
|
if (!acquireLock(lockPath)) {
|
|
14888
15121
|
warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
|
|
@@ -14901,7 +15134,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
14901
15134
|
for (const entry of entries) {
|
|
14902
15135
|
if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
|
|
14903
15136
|
continue;
|
|
14904
|
-
const stagingDir =
|
|
15137
|
+
const stagingDir = join11(onnxBaseDir, entry);
|
|
14905
15138
|
const parts = entry.split(".");
|
|
14906
15139
|
const pidStr = parts[parts.length - 2];
|
|
14907
15140
|
const pid = pidStr ? Number.parseInt(pidStr, 10) : NaN;
|
|
@@ -14938,7 +15171,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
14938
15171
|
}
|
|
14939
15172
|
function cleanupIncompleteTargetIfUnowned(ortDir) {
|
|
14940
15173
|
try {
|
|
14941
|
-
if (
|
|
15174
|
+
if (existsSync8(ortDir) && !existsSync8(join11(ortDir, ONNX_INSTALLED_META_FILE))) {
|
|
14942
15175
|
log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
|
|
14943
15176
|
rmSync3(ortDir, { recursive: true, force: true });
|
|
14944
15177
|
}
|
|
@@ -14982,8 +15215,8 @@ function detectOnnxVersion(libDir, libName) {
|
|
|
14982
15215
|
if (version)
|
|
14983
15216
|
return version;
|
|
14984
15217
|
}
|
|
14985
|
-
const base =
|
|
14986
|
-
if (
|
|
15218
|
+
const base = join11(libDir, libName);
|
|
15219
|
+
if (existsSync8(base)) {
|
|
14987
15220
|
try {
|
|
14988
15221
|
const real = realpathSync2(base);
|
|
14989
15222
|
const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
|
|
@@ -15014,8 +15247,8 @@ function pathEnvValue() {
|
|
|
15014
15247
|
return process.env.PATH ?? process.env.Path ?? process.env.path ?? "";
|
|
15015
15248
|
}
|
|
15016
15249
|
function pathEntriesForPlatform() {
|
|
15017
|
-
const
|
|
15018
|
-
return pathEnvValue().split(
|
|
15250
|
+
const delimiter3 = process.platform === "win32" ? ";" : ":";
|
|
15251
|
+
return pathEnvValue().split(delimiter3).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
|
|
15019
15252
|
if (!entry || entry === "." || entry.includes("\x00"))
|
|
15020
15253
|
return false;
|
|
15021
15254
|
return isAbsolute4(entry) || win32.isAbsolute(entry);
|
|
@@ -15045,10 +15278,10 @@ function directoryContainsLibrary(dir, libName) {
|
|
|
15045
15278
|
}
|
|
15046
15279
|
}
|
|
15047
15280
|
function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
|
|
15048
|
-
if (
|
|
15281
|
+
if (existsSync8(join11(ortVersionDir, libName)))
|
|
15049
15282
|
return ortVersionDir;
|
|
15050
|
-
const libSubdir =
|
|
15051
|
-
if (
|
|
15283
|
+
const libSubdir = join11(ortVersionDir, "lib");
|
|
15284
|
+
if (existsSync8(join11(libSubdir, libName)))
|
|
15052
15285
|
return libSubdir;
|
|
15053
15286
|
return ortVersionDir;
|
|
15054
15287
|
}
|
|
@@ -15063,13 +15296,13 @@ function findSystemOnnxRuntime(libName) {
|
|
|
15063
15296
|
} else if (process.platform === "win32") {
|
|
15064
15297
|
const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
|
|
15065
15298
|
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
|
|
15066
|
-
searchPaths.push(
|
|
15299
|
+
searchPaths.push(join11(programFiles, "onnxruntime", "lib"), join11(programFiles, "Microsoft ONNX Runtime", "lib"), join11(programFiles, "Microsoft Machine Learning", "lib"), join11(programFilesX86, "onnxruntime", "lib"), ...(() => {
|
|
15067
15300
|
const nugetPaths = [];
|
|
15068
15301
|
const userProfile = process.env.USERPROFILE ?? "";
|
|
15069
15302
|
if (!userProfile)
|
|
15070
15303
|
return nugetPaths;
|
|
15071
|
-
const nugetPackageDir =
|
|
15072
|
-
if (!
|
|
15304
|
+
const nugetPackageDir = join11(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
|
|
15305
|
+
if (!existsSync8(nugetPackageDir))
|
|
15073
15306
|
return nugetPaths;
|
|
15074
15307
|
try {
|
|
15075
15308
|
for (const entry of readdirSync3(nugetPackageDir, { withFileTypes: true })) {
|
|
@@ -15077,7 +15310,7 @@ function findSystemOnnxRuntime(libName) {
|
|
|
15077
15310
|
continue;
|
|
15078
15311
|
if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
|
|
15079
15312
|
continue;
|
|
15080
|
-
nugetPaths.push(
|
|
15313
|
+
nugetPaths.push(join11(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join11(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
|
|
15081
15314
|
}
|
|
15082
15315
|
} catch (err) {
|
|
15083
15316
|
warn(`Failed to scan NuGet ONNX Runtime cache ${nugetPackageDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -15099,11 +15332,11 @@ function findSystemOnnxRuntime(libName) {
|
|
|
15099
15332
|
});
|
|
15100
15333
|
const unknownVersionPaths = [];
|
|
15101
15334
|
for (const dir of uniquePaths) {
|
|
15102
|
-
const libPath =
|
|
15335
|
+
const libPath = join11(dir, libName);
|
|
15103
15336
|
if (process.platform === "win32") {
|
|
15104
15337
|
if (!directoryContainsLibrary(dir, libName))
|
|
15105
15338
|
continue;
|
|
15106
|
-
} else if (!
|
|
15339
|
+
} else if (!existsSync8(libPath)) {
|
|
15107
15340
|
continue;
|
|
15108
15341
|
}
|
|
15109
15342
|
const version = detectOnnxVersion(dir, libName);
|
|
@@ -15169,7 +15402,7 @@ function validateExtractedTree(stagingRoot) {
|
|
|
15169
15402
|
const walk = (dir) => {
|
|
15170
15403
|
const entries = readdirSync3(dir);
|
|
15171
15404
|
for (const entry of entries) {
|
|
15172
|
-
const fullPath =
|
|
15405
|
+
const fullPath = join11(dir, entry);
|
|
15173
15406
|
const lst = lstatSync(fullPath);
|
|
15174
15407
|
if (lst.isSymbolicLink()) {
|
|
15175
15408
|
const linkTarget = readlinkSync(fullPath);
|
|
@@ -15204,7 +15437,7 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
15204
15437
|
const tmpDir = `${targetDir}.tmp.${process.pid}.${Date.now().toString(36)}`;
|
|
15205
15438
|
try {
|
|
15206
15439
|
mkdirSync5(tmpDir, { recursive: true });
|
|
15207
|
-
const archivePath =
|
|
15440
|
+
const archivePath = join11(tmpDir, `onnxruntime.${info.archiveType}`);
|
|
15208
15441
|
await downloadFileWithCap(url, archivePath);
|
|
15209
15442
|
const archiveSha256 = sha256File(archivePath);
|
|
15210
15443
|
log(`ONNX Runtime archive sha256=${archiveSha256}`);
|
|
@@ -15220,8 +15453,8 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
15220
15453
|
unlinkSync4(archivePath);
|
|
15221
15454
|
} catch {}
|
|
15222
15455
|
validateExtractedTree(tmpDir);
|
|
15223
|
-
const extractedDir =
|
|
15224
|
-
if (!
|
|
15456
|
+
const extractedDir = join11(tmpDir, info.assetName, "lib");
|
|
15457
|
+
if (!existsSync8(extractedDir)) {
|
|
15225
15458
|
throw new Error(`Expected directory not found: ${extractedDir}`);
|
|
15226
15459
|
}
|
|
15227
15460
|
mkdirSync5(targetDir, { recursive: true });
|
|
@@ -15229,7 +15462,7 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
15229
15462
|
const realFiles = [];
|
|
15230
15463
|
const symlinks = [];
|
|
15231
15464
|
for (const libFile of libFiles) {
|
|
15232
|
-
const src =
|
|
15465
|
+
const src = join11(extractedDir, libFile);
|
|
15233
15466
|
try {
|
|
15234
15467
|
const stat2 = lstatSync(src);
|
|
15235
15468
|
log(`ORT extract: ${libFile} — isSymlink=${stat2.isSymbolicLink()}, isFile=${stat2.isFile()}, size=${stat2.size}`);
|
|
@@ -15244,7 +15477,7 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
15244
15477
|
}
|
|
15245
15478
|
}
|
|
15246
15479
|
copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
|
|
15247
|
-
const libPath =
|
|
15480
|
+
const libPath = join11(targetDir, info.libName);
|
|
15248
15481
|
let libHash = null;
|
|
15249
15482
|
try {
|
|
15250
15483
|
libHash = sha256File(libPath);
|
|
@@ -15269,8 +15502,8 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
15269
15502
|
function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync3) {
|
|
15270
15503
|
const requiredLibs = new Set([info.libName]);
|
|
15271
15504
|
for (const libFile of realFiles) {
|
|
15272
|
-
const src =
|
|
15273
|
-
const dst =
|
|
15505
|
+
const src = join11(extractedDir, libFile);
|
|
15506
|
+
const dst = join11(targetDir, libFile);
|
|
15274
15507
|
try {
|
|
15275
15508
|
copyFile(src, dst);
|
|
15276
15509
|
if (process.platform !== "win32") {
|
|
@@ -15286,11 +15519,11 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
15286
15519
|
}
|
|
15287
15520
|
const targetRoot = realpathSync2(targetDir);
|
|
15288
15521
|
for (const link of symlinks) {
|
|
15289
|
-
const dst =
|
|
15522
|
+
const dst = join11(targetDir, link.name);
|
|
15290
15523
|
try {
|
|
15291
15524
|
unlinkSync4(dst);
|
|
15292
15525
|
} catch {}
|
|
15293
|
-
const dstForContainment =
|
|
15526
|
+
const dstForContainment = join11(targetRoot, link.name);
|
|
15294
15527
|
const resolvedTarget = resolve7(dirname5(dstForContainment), link.target);
|
|
15295
15528
|
if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
|
|
15296
15529
|
const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
|
|
@@ -15311,8 +15544,8 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
15311
15544
|
log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
|
|
15312
15545
|
}
|
|
15313
15546
|
}
|
|
15314
|
-
const requiredPath =
|
|
15315
|
-
if (!
|
|
15547
|
+
const requiredPath = join11(targetDir, info.libName);
|
|
15548
|
+
if (!existsSync8(requiredPath)) {
|
|
15316
15549
|
rmSync3(targetDir, { recursive: true, force: true });
|
|
15317
15550
|
throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
|
|
15318
15551
|
}
|
|
@@ -15338,13 +15571,13 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
|
|
|
15338
15571
|
...sha256 ? { sha256 } : {},
|
|
15339
15572
|
archiveSha256
|
|
15340
15573
|
};
|
|
15341
|
-
writeFileSync3(
|
|
15574
|
+
writeFileSync3(join11(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
|
|
15342
15575
|
} catch (err) {
|
|
15343
15576
|
log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
|
|
15344
15577
|
}
|
|
15345
15578
|
}
|
|
15346
15579
|
function readOnnxInstalledMeta(installDir) {
|
|
15347
|
-
const path2 =
|
|
15580
|
+
const path2 = join11(installDir, ONNX_INSTALLED_META_FILE);
|
|
15348
15581
|
try {
|
|
15349
15582
|
if (!statSync6(path2).isFile())
|
|
15350
15583
|
return null;
|
|
@@ -15750,7 +15983,7 @@ function editModesPresent(record) {
|
|
|
15750
15983
|
const hasSymbol = isNonEmptyString(record.symbol);
|
|
15751
15984
|
if (!hasSymbol) {
|
|
15752
15985
|
delete record.symbol;
|
|
15753
|
-
if (record.content
|
|
15986
|
+
if (isNullOrEmptyString(record.content))
|
|
15754
15987
|
delete record.content;
|
|
15755
15988
|
} else if (record.content === null) {
|
|
15756
15989
|
delete record.content;
|
|
@@ -15779,17 +16012,27 @@ function editModesPresent(record) {
|
|
|
15779
16012
|
function isNonEmptyString(value) {
|
|
15780
16013
|
return typeof value === "string" && value.length > 0;
|
|
15781
16014
|
}
|
|
16015
|
+
function isNullOrEmptyString(value) {
|
|
16016
|
+
return value === null || value === "";
|
|
16017
|
+
}
|
|
15782
16018
|
var OMIT_OPTIONAL_FIELDS_STEERING = "Omit unused optional fields entirely; do not send empty strings or empty arrays for them.";
|
|
15783
16019
|
function isEditSentinelItem(item) {
|
|
15784
16020
|
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
15785
16021
|
return false;
|
|
15786
16022
|
const record = item;
|
|
15787
|
-
|
|
16023
|
+
const oldStringEmpty = hasOwn(record, "oldString") && isNullOrEmptyString(record.oldString);
|
|
16024
|
+
if (!oldStringEmpty)
|
|
15788
16025
|
return false;
|
|
15789
|
-
|
|
15790
|
-
if (!newStringEmpty)
|
|
16026
|
+
if (record.oldString === null && ["startLine", "endLine"].some((key) => hasOwn(record, key) && record[key] !== null)) {
|
|
15791
16027
|
return false;
|
|
15792
|
-
|
|
16028
|
+
}
|
|
16029
|
+
return (!hasOwn(record, "newString") || isNullOrEmptyString(record.newString)) && (!hasOwn(record, "content") || isNullOrEmptyString(record.content)) && (!hasOwn(record, "replaceAll") || record.replaceAll === null || record.replaceAll === false) && isDefaultOccurrence(record.occurrence);
|
|
16030
|
+
}
|
|
16031
|
+
function hasMeaningfulFindPayload(item) {
|
|
16032
|
+
return isNonEmptyString(item.oldString);
|
|
16033
|
+
}
|
|
16034
|
+
function isDefaultOccurrence(value) {
|
|
16035
|
+
return value === undefined || value === null || value === 1;
|
|
15793
16036
|
}
|
|
15794
16037
|
function normalizeEditArraySentinels(record) {
|
|
15795
16038
|
const value = record.edits;
|
|
@@ -15842,9 +16085,33 @@ function parseEditArray(value) {
|
|
|
15842
16085
|
}
|
|
15843
16086
|
return value;
|
|
15844
16087
|
}
|
|
15845
|
-
function
|
|
15846
|
-
const
|
|
15847
|
-
|
|
16088
|
+
function normalizeEditItemSentinels(item) {
|
|
16089
|
+
const hadRangeFields = ["startLine", "endLine", "content"].some((key) => hasOwn(item, key));
|
|
16090
|
+
for (const key of [
|
|
16091
|
+
"oldString",
|
|
16092
|
+
"newString",
|
|
16093
|
+
"replaceAll",
|
|
16094
|
+
"occurrence",
|
|
16095
|
+
"startLine",
|
|
16096
|
+
"endLine",
|
|
16097
|
+
"content"
|
|
16098
|
+
]) {
|
|
16099
|
+
if (item[key] === null)
|
|
16100
|
+
delete item[key];
|
|
16101
|
+
}
|
|
16102
|
+
const contentIsEmpty = item.content === "";
|
|
16103
|
+
if (hasMeaningfulFindPayload(item) && (!hasOwn(item, "content") || contentIsEmpty)) {
|
|
16104
|
+
for (const key of ["startLine", "endLine", "content"])
|
|
16105
|
+
delete item[key];
|
|
16106
|
+
if (hadRangeFields) {
|
|
16107
|
+
if (item.replaceAll === false)
|
|
16108
|
+
delete item.replaceAll;
|
|
16109
|
+
if (hasOwn(item, "occurrence") && isDefaultOccurrence(item.occurrence))
|
|
16110
|
+
delete item.occurrence;
|
|
16111
|
+
}
|
|
16112
|
+
return;
|
|
16113
|
+
}
|
|
16114
|
+
if (!isNonEmptyString(item.content))
|
|
15848
16115
|
return;
|
|
15849
16116
|
if (item.oldString === "")
|
|
15850
16117
|
delete item.oldString;
|
|
@@ -15852,7 +16119,7 @@ function stripLineRangeSentinels(item) {
|
|
|
15852
16119
|
delete item.newString;
|
|
15853
16120
|
if (item.replaceAll === false)
|
|
15854
16121
|
delete item.replaceAll;
|
|
15855
|
-
if (item
|
|
16122
|
+
if (hasOwn(item, "occurrence") && isDefaultOccurrence(item.occurrence))
|
|
15856
16123
|
delete item.occurrence;
|
|
15857
16124
|
}
|
|
15858
16125
|
function normalizeEditItem(value, index) {
|
|
@@ -15863,7 +16130,7 @@ function normalizeEditItem(value, index) {
|
|
|
15863
16130
|
const item = copyOwnProperties(source);
|
|
15864
16131
|
normalizeItemAlias(item, "oldString", "oldText");
|
|
15865
16132
|
normalizeItemAlias(item, "newString", "newText");
|
|
15866
|
-
|
|
16133
|
+
normalizeEditItemSentinels(item);
|
|
15867
16134
|
const hasFindField = ["oldString", "newString", "replaceAll", "occurrence"].some((key) => hasOwn(item, key));
|
|
15868
16135
|
const hasRangeField = ["startLine", "endLine", "content"].some((key) => hasOwn(item, key));
|
|
15869
16136
|
if (hasFindField && hasRangeField) {
|
|
@@ -16556,17 +16823,17 @@ function collectStructuredExtras(response) {
|
|
|
16556
16823
|
return stringifyData(extras);
|
|
16557
16824
|
}
|
|
16558
16825
|
// ../aft-bridge/dist/transport-factory.js
|
|
16559
|
-
import { existsSync as
|
|
16826
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
16560
16827
|
import { homedir as homedir11 } from "node:os";
|
|
16561
|
-
import { isAbsolute as isAbsolute5, join as
|
|
16828
|
+
import { isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
16562
16829
|
function resolveConnectionFilePath(raw) {
|
|
16563
16830
|
const trimmed = raw.trim();
|
|
16564
16831
|
if (trimmed.startsWith("~")) {
|
|
16565
|
-
return
|
|
16832
|
+
return join12(homedir11(), trimmed.slice(1).replace(/^[/\\]/, ""));
|
|
16566
16833
|
}
|
|
16567
16834
|
if (isAbsolute5(trimmed))
|
|
16568
16835
|
return trimmed;
|
|
16569
|
-
return
|
|
16836
|
+
return join12(homedir11(), trimmed);
|
|
16570
16837
|
}
|
|
16571
16838
|
var SUBC_CLIENT_REAPER_PROCESS_KEY = "subc_client_reaper";
|
|
16572
16839
|
function booleanOption(value) {
|
|
@@ -16640,7 +16907,7 @@ async function createConcreteAftTransportPool(opts) {
|
|
|
16640
16907
|
consumerIdentity: opts.subcConsumerIdentity,
|
|
16641
16908
|
onBgEventsNudge: opts.onBgEventsNudge,
|
|
16642
16909
|
onBgEventsNudgeRef: opts.onBgEventsNudgeRef,
|
|
16643
|
-
lifecycleDemandCheck: opts.subcLifecycleDemandCheck ?? ((root) =>
|
|
16910
|
+
lifecycleDemandCheck: opts.subcLifecycleDemandCheck ?? ((root) => existsSync9(root))
|
|
16644
16911
|
});
|
|
16645
16912
|
}
|
|
16646
16913
|
return new BridgePool(opts.binaryPath, opts.poolOptions, opts.configOverrides);
|
|
@@ -16751,6 +17018,8 @@ var UNKNOWN_COMPLETION_CAP = 32;
|
|
|
16751
17018
|
var DEFAULT_SESSION_ID2 = "__default__";
|
|
16752
17019
|
var LOG_PREFIX = "[aft-pi] bg-notifications:";
|
|
16753
17020
|
var SUBC_NUDGE_LOG_INTERVAL_MS = 60000;
|
|
17021
|
+
var DEFAULT_BG_HOP_TIMEOUT_MS = 15000;
|
|
17022
|
+
var bgHopTimeoutMs = DEFAULT_BG_HOP_TIMEOUT_MS;
|
|
16754
17023
|
var subcNudgesInFlight = new Map;
|
|
16755
17024
|
var subcNudgeLogState = new Map;
|
|
16756
17025
|
function normalizeSessionID(sessionID) {
|
|
@@ -16974,11 +17243,21 @@ function handleSubcBgEventsNudge(drainContext) {
|
|
|
16974
17243
|
}
|
|
16975
17244
|
async function handleSubcBgEventsNudgeOnce(drainContext) {
|
|
16976
17245
|
bridgeForDrain(drainContext);
|
|
16977
|
-
stateFor(drainContext.sessionID)
|
|
17246
|
+
const state = stateFor(drainContext.sessionID);
|
|
17247
|
+
state.wakeDeferredTaskIds.clear();
|
|
17248
|
+
rearmHardStoppedWake(state, drainContext);
|
|
16978
17249
|
await triggerWakeIfPending(drainContext, false, true, true);
|
|
16979
17250
|
}
|
|
16980
17251
|
function logSubcNudgeLifecycle(drainContext, kind, message) {
|
|
16981
|
-
|
|
17252
|
+
logDeliveryHop(drainContext, kind, message, {
|
|
17253
|
+
event: "subc_bg_nudge_delivery",
|
|
17254
|
+
cause: kind
|
|
17255
|
+
});
|
|
17256
|
+
}
|
|
17257
|
+
function logDeliveryHop(drainContext, kind, message, data, level = "info") {
|
|
17258
|
+
const sessionID = normalizeSessionID(drainContext.sessionID);
|
|
17259
|
+
const taskKey = typeof data.task_id === "string" ? data.task_id : Array.isArray(data.task_ids) ? data.task_ids.join(",") : "";
|
|
17260
|
+
const key = `${kind}\x00${taskKey}\x00${drainContext.directory}\x00${sessionID}`;
|
|
16982
17261
|
const now = Date.now();
|
|
16983
17262
|
const state = subcNudgeLogState.get(key);
|
|
16984
17263
|
if (state && now - state.lastEmittedAt < SUBC_NUDGE_LOG_INTERVAL_MS) {
|
|
@@ -16987,13 +17266,48 @@ function logSubcNudgeLifecycle(drainContext, kind, message) {
|
|
|
16987
17266
|
}
|
|
16988
17267
|
const suppressed = state?.suppressed ?? 0;
|
|
16989
17268
|
subcNudgeLogState.set(key, { lastEmittedAt: now, suppressed: 0 });
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
cause: kind,
|
|
17269
|
+
const payload = {
|
|
17270
|
+
...data,
|
|
16993
17271
|
canonical_root: drainContext.directory,
|
|
16994
17272
|
suppressed
|
|
17273
|
+
};
|
|
17274
|
+
if (level === "warn") {
|
|
17275
|
+
sessionWarn(sessionID, `${LOG_PREFIX} ${message}`, payload);
|
|
17276
|
+
} else {
|
|
17277
|
+
sessionLog(sessionID, `${LOG_PREFIX} ${message}`, payload);
|
|
17278
|
+
}
|
|
17279
|
+
}
|
|
17280
|
+
function logPerTaskDeliveryHop(drainContext, kind, message, taskIDs, data, level = "info") {
|
|
17281
|
+
for (const taskID of taskIDs) {
|
|
17282
|
+
logDeliveryHop(drainContext, kind, message, { ...data, task_id: taskID, task_ids: taskIDs }, level);
|
|
17283
|
+
}
|
|
17284
|
+
}
|
|
17285
|
+
function rearmHardStoppedWake(state, drainContext) {
|
|
17286
|
+
if (!state.wakeHardStopped)
|
|
17287
|
+
return;
|
|
17288
|
+
state.wakeHardStopped = false;
|
|
17289
|
+
state.wakeRetryAttempts = 0;
|
|
17290
|
+
state.retryDelayMs = null;
|
|
17291
|
+
logDeliveryHop(drainContext, "inject-rearmed", "delivery retry re-armed", {
|
|
17292
|
+
event: "bash_completion_inject_rearmed",
|
|
17293
|
+
task_ids: state.pendingCompletions.map((completion) => completion.task_id)
|
|
16995
17294
|
});
|
|
16996
17295
|
}
|
|
17296
|
+
async function withBgHopTimeout(operation, label) {
|
|
17297
|
+
let timer;
|
|
17298
|
+
try {
|
|
17299
|
+
return await Promise.race([
|
|
17300
|
+
operation,
|
|
17301
|
+
new Promise((_, reject) => {
|
|
17302
|
+
timer = setTimeout(() => reject(new Error(`${label} timed out after ${bgHopTimeoutMs}ms`)), bgHopTimeoutMs);
|
|
17303
|
+
timer.unref?.();
|
|
17304
|
+
})
|
|
17305
|
+
]);
|
|
17306
|
+
} finally {
|
|
17307
|
+
if (timer)
|
|
17308
|
+
clearTimeout(timer);
|
|
17309
|
+
}
|
|
17310
|
+
}
|
|
16997
17311
|
async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredCompletions = true, forceDrain = false) {
|
|
16998
17312
|
const state = stateFor(drainContext.sessionID);
|
|
16999
17313
|
if (!skipDrain && (forceDrain || state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted)) {
|
|
@@ -17003,8 +17317,25 @@ async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredComp
|
|
|
17003
17317
|
if (!hasWakeEligiblePending(state, includeDeferredCompletions))
|
|
17004
17318
|
return;
|
|
17005
17319
|
scheduleWake(state, async (reminder, deliveredCompletions) => {
|
|
17006
|
-
drainContext.runtime.sendUserMessage(reminder, { deliverAs: "steer" });
|
|
17007
17320
|
const ackTargetIds = deliveredCompletions.map((completion) => completion.task_id);
|
|
17321
|
+
logPerTaskDeliveryHop(drainContext, "inject-start", "session inject start", ackTargetIds, {
|
|
17322
|
+
event: "bash_completion_wake_send_user_message_start",
|
|
17323
|
+
attempt: state.wakeRetryAttempts + 1
|
|
17324
|
+
});
|
|
17325
|
+
try {
|
|
17326
|
+
drainContext.runtime.sendUserMessage(reminder, { deliverAs: "steer" });
|
|
17327
|
+
} catch (err) {
|
|
17328
|
+
logPerTaskDeliveryHop(drainContext, "inject-error", "session inject failed", ackTargetIds, {
|
|
17329
|
+
event: "bash_completion_wake_send_user_message_error",
|
|
17330
|
+
attempt: state.wakeRetryAttempts + 1,
|
|
17331
|
+
cause: err instanceof Error ? err.message : String(err)
|
|
17332
|
+
}, "warn");
|
|
17333
|
+
throw err;
|
|
17334
|
+
}
|
|
17335
|
+
logPerTaskDeliveryHop(drainContext, "inject-ok", "session inject ok", ackTargetIds, {
|
|
17336
|
+
event: "bash_completion_wake_send_user_message_ok",
|
|
17337
|
+
attempt: state.wakeRetryAttempts + 1
|
|
17338
|
+
});
|
|
17008
17339
|
markDeliveredAwaitingAck(state, ackTargetIds);
|
|
17009
17340
|
const acked = await ackCompletions(drainContext, deliveredCompletions);
|
|
17010
17341
|
if (acked)
|
|
@@ -17020,7 +17351,12 @@ async function triggerWakeIfPending(drainContext, skipDrain, includeDeferredComp
|
|
|
17020
17351
|
});
|
|
17021
17352
|
return;
|
|
17022
17353
|
}
|
|
17023
|
-
|
|
17354
|
+
if (hardStopped) {
|
|
17355
|
+
logDeliveryHop(drainContext, "inject-hard-stopped", "delivery retries paused", {
|
|
17356
|
+
event: "bash_completion_inject_hard_stopped",
|
|
17357
|
+
cause: err instanceof Error ? err.message : String(err)
|
|
17358
|
+
});
|
|
17359
|
+
}
|
|
17024
17360
|
}, includeDeferredCompletions);
|
|
17025
17361
|
}
|
|
17026
17362
|
function formatSystemReminder(completions) {
|
|
@@ -17090,12 +17426,21 @@ async function drainCompletions(drainContext) {
|
|
|
17090
17426
|
const bridge = bridgeForDrain(drainContext);
|
|
17091
17427
|
const state = stateFor(drainContext.sessionID);
|
|
17092
17428
|
const params = drainContext.sessionID ? { session_id: drainContext.sessionID } : {};
|
|
17093
|
-
const response = await bridge.send("bash_drain_completions", params);
|
|
17429
|
+
const response = await withBgHopTimeout(bridge.send("bash_drain_completions", params, { timeoutMs: bgHopTimeoutMs }), "bash_drain_completions");
|
|
17094
17430
|
if (response.success === false) {
|
|
17095
|
-
|
|
17431
|
+
logDeliveryHop(drainContext, "drain-error", "drain failed", {
|
|
17432
|
+
event: "bash_completion_drain_error",
|
|
17433
|
+
cause: String(response.message ?? "unknown error")
|
|
17434
|
+
}, "warn");
|
|
17096
17435
|
return;
|
|
17097
17436
|
}
|
|
17098
17437
|
state.forcedDrainCompleted = true;
|
|
17438
|
+
const drainedTaskIds = Array.isArray(response.bg_completions) ? response.bg_completions.filter(isBgCompletion).map((completion) => completion.task_id) : [];
|
|
17439
|
+
logDeliveryHop(drainContext, "drain-ok", "drain ok", {
|
|
17440
|
+
event: "bash_completion_drain_ok",
|
|
17441
|
+
count: drainedTaskIds.length,
|
|
17442
|
+
task_ids: drainedTaskIds
|
|
17443
|
+
});
|
|
17099
17444
|
const reackTaskIds = reconcileAwaitingAck(state, response.bg_completions);
|
|
17100
17445
|
ingestDrainedBgCompletions(drainContext.sessionID, response.bg_completions);
|
|
17101
17446
|
if (reackTaskIds.length > 0) {
|
|
@@ -17111,7 +17456,10 @@ async function drainCompletions(drainContext) {
|
|
|
17111
17456
|
} catch (err) {
|
|
17112
17457
|
if (drainContext.nudgeRef && isTerminalNudgeError(err))
|
|
17113
17458
|
throw err;
|
|
17114
|
-
|
|
17459
|
+
logDeliveryHop(drainContext, "drain-error", "drain failed", {
|
|
17460
|
+
event: "bash_completion_drain_error",
|
|
17461
|
+
cause: err instanceof Error ? err.message : String(err)
|
|
17462
|
+
}, "warn");
|
|
17115
17463
|
}
|
|
17116
17464
|
}
|
|
17117
17465
|
async function ackCompletions(drainContext, completions) {
|
|
@@ -17121,16 +17469,25 @@ async function ackCompletions(drainContext, completions) {
|
|
|
17121
17469
|
try {
|
|
17122
17470
|
const bridge = bridgeForDrain(drainContext);
|
|
17123
17471
|
const params = drainContext.sessionID ? { session_id: drainContext.sessionID, task_ids: taskIds } : { task_ids: taskIds };
|
|
17124
|
-
const response = await bridge.send("bash_ack_completions", params);
|
|
17472
|
+
const response = await withBgHopTimeout(bridge.send("bash_ack_completions", params, { timeoutMs: bgHopTimeoutMs }), "bash_ack_completions");
|
|
17125
17473
|
if (response.success === false) {
|
|
17126
|
-
|
|
17474
|
+
logPerTaskDeliveryHop(drainContext, "ack-error", "ack failed", taskIds, {
|
|
17475
|
+
event: "bash_completion_ack_error",
|
|
17476
|
+
cause: String(response.message ?? "unknown error")
|
|
17477
|
+
}, "warn");
|
|
17127
17478
|
return false;
|
|
17128
17479
|
}
|
|
17480
|
+
logPerTaskDeliveryHop(drainContext, "ack-ok", "ack ok", taskIds, {
|
|
17481
|
+
event: "bash_completion_ack_ok"
|
|
17482
|
+
});
|
|
17129
17483
|
return true;
|
|
17130
17484
|
} catch (err) {
|
|
17131
17485
|
if (drainContext.nudgeRef && isTerminalNudgeError(err))
|
|
17132
17486
|
throw err;
|
|
17133
|
-
|
|
17487
|
+
logPerTaskDeliveryHop(drainContext, "ack-error", "ack failed", taskIds, {
|
|
17488
|
+
event: "bash_completion_ack_error",
|
|
17489
|
+
cause: err instanceof Error ? err.message : String(err)
|
|
17490
|
+
}, "warn");
|
|
17134
17491
|
return false;
|
|
17135
17492
|
}
|
|
17136
17493
|
}
|
|
@@ -17461,7 +17818,7 @@ import {
|
|
|
17461
17818
|
// package.json
|
|
17462
17819
|
var package_default = {
|
|
17463
17820
|
name: "@cortexkit/aft-pi",
|
|
17464
|
-
version: "0.
|
|
17821
|
+
version: "0.55.0",
|
|
17465
17822
|
type: "module",
|
|
17466
17823
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
17467
17824
|
main: "dist/index.js",
|
|
@@ -17484,19 +17841,19 @@ var package_default = {
|
|
|
17484
17841
|
"test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
|
|
17485
17842
|
},
|
|
17486
17843
|
dependencies: {
|
|
17487
|
-
"@cortexkit/aft-bridge": "0.
|
|
17844
|
+
"@cortexkit/aft-bridge": "0.55.0",
|
|
17488
17845
|
"comment-json": "^5.0.0",
|
|
17489
17846
|
diff: "^8.0.4",
|
|
17490
17847
|
typebox: "1.1.38",
|
|
17491
17848
|
zod: "^4.4.3"
|
|
17492
17849
|
},
|
|
17493
17850
|
optionalDependencies: {
|
|
17494
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
17495
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
17496
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
17497
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
17498
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
17499
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
17851
|
+
"@cortexkit/aft-darwin-arm64": "0.55.0",
|
|
17852
|
+
"@cortexkit/aft-darwin-x64": "0.55.0",
|
|
17853
|
+
"@cortexkit/aft-linux-arm64": "0.55.0",
|
|
17854
|
+
"@cortexkit/aft-linux-x64": "0.55.0",
|
|
17855
|
+
"@cortexkit/aft-win32-arm64": "0.55.0",
|
|
17856
|
+
"@cortexkit/aft-win32-x64": "0.55.0"
|
|
17500
17857
|
},
|
|
17501
17858
|
devDependencies: {
|
|
17502
17859
|
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
@@ -17764,7 +18121,7 @@ function appendDegradedStatus(lines, status, markdown) {
|
|
|
17764
18121
|
}
|
|
17765
18122
|
|
|
17766
18123
|
// src/tools/_shared.ts
|
|
17767
|
-
import { existsSync as
|
|
18124
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
17768
18125
|
import { Type } from "typebox";
|
|
17769
18126
|
var optionalInt = (min, max, description = "(integer)") => Type.Optional(Type.Union([Type.Integer({ minimum: min, maximum: max }), Type.String()], {
|
|
17770
18127
|
description
|
|
@@ -17785,7 +18142,7 @@ function withPathAliasPreparation(tool) {
|
|
|
17785
18142
|
};
|
|
17786
18143
|
}
|
|
17787
18144
|
function bridgeFor(ctx, cwd) {
|
|
17788
|
-
if (!
|
|
18145
|
+
if (!existsSync10(cwd)) {
|
|
17789
18146
|
throw new Error(`project directory no longer exists: ${cwd} (stale restored session?)`);
|
|
17790
18147
|
}
|
|
17791
18148
|
return ctx.pool.getBridge(cwd);
|
|
@@ -17833,8 +18190,10 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
|
|
|
17833
18190
|
return response;
|
|
17834
18191
|
}
|
|
17835
18192
|
async function callToolCall(bridge, name, rawArgs = {}, extCtx, options) {
|
|
18193
|
+
return callToolCallForSession(bridge, name, rawArgs, extCtx ? resolveSessionId(extCtx) : undefined, extCtx, options);
|
|
18194
|
+
}
|
|
18195
|
+
async function callToolCallForSession(bridge, name, rawArgs, sessionId, extCtx, options) {
|
|
17836
18196
|
const timeoutMs = timeoutForCommand(name);
|
|
17837
|
-
const sessionId = extCtx ? resolveSessionId(extCtx) : undefined;
|
|
17838
18197
|
const sendOptions = {
|
|
17839
18198
|
...timeoutMs !== undefined ? { timeoutMs } : {},
|
|
17840
18199
|
configureWarningClient: extCtx,
|
|
@@ -18157,7 +18516,7 @@ function registerStatusCommand(pi, ctx) {
|
|
|
18157
18516
|
}
|
|
18158
18517
|
|
|
18159
18518
|
// src/config.ts
|
|
18160
|
-
import { existsSync as
|
|
18519
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
18161
18520
|
import { homedir as homedir12 } from "node:os";
|
|
18162
18521
|
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
18163
18522
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
@@ -19773,8 +20132,8 @@ function emoji() {
|
|
|
19773
20132
|
}
|
|
19774
20133
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
19775
20134
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
19776
|
-
var mac = (
|
|
19777
|
-
const escapedDelim = escapeRegex(
|
|
20135
|
+
var mac = (delimiter3) => {
|
|
20136
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
19778
20137
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
19779
20138
|
};
|
|
19780
20139
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -32439,6 +32798,26 @@ function date4(params) {
|
|
|
32439
32798
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
32440
32799
|
config(en_default());
|
|
32441
32800
|
// src/config.ts
|
|
32801
|
+
var ACTIVE_HARNESS = "pi";
|
|
32802
|
+
function isConfigRecord(value) {
|
|
32803
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32804
|
+
}
|
|
32805
|
+
function normalizeConfigForActiveHarness(value) {
|
|
32806
|
+
const config2 = stripHarnessSpecificConfigKeys(value, OPENCODE_ONLY_KEYS);
|
|
32807
|
+
if (!isConfigRecord(config2) || !isConfigRecord(config2.harnesses))
|
|
32808
|
+
return config2;
|
|
32809
|
+
const override = config2.harnesses[ACTIVE_HARNESS];
|
|
32810
|
+
return {
|
|
32811
|
+
...config2,
|
|
32812
|
+
harnesses: override === undefined ? {} : { [ACTIVE_HARNESS]: stripHarnessSpecificConfigKeys(override, OPENCODE_ONLY_KEYS) }
|
|
32813
|
+
};
|
|
32814
|
+
}
|
|
32815
|
+
function warnIgnoredNestedHarnesses(rawConfig, configPath) {
|
|
32816
|
+
const override = isConfigRecord(rawConfig.harnesses) ? rawConfig.harnesses[ACTIVE_HARNESS] : undefined;
|
|
32817
|
+
if (isConfigRecord(override) && Object.hasOwn(override, "harnesses")) {
|
|
32818
|
+
warn2(`Ignoring nested harnesses in harnesses.${ACTIVE_HARNESS} from ${configPath}; harness overrides cannot recurse`);
|
|
32819
|
+
}
|
|
32820
|
+
}
|
|
32442
32821
|
var DEFAULT_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 120000;
|
|
32443
32822
|
var MIN_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 1e4;
|
|
32444
32823
|
var MAX_INSPECT_DIAGNOSTICS_TIMEOUT_MS = 600000;
|
|
@@ -32457,6 +32836,7 @@ function resolveBashConfig(config2) {
|
|
|
32457
32836
|
const surfaceDefaultEnabled = surface !== "minimal";
|
|
32458
32837
|
const reminderEnabled = (typeof top === "object" && top !== null ? top.long_running_reminder_enabled : undefined) ?? legacy?.long_running_reminder_enabled;
|
|
32459
32838
|
const reminderInterval = (typeof top === "object" && top !== null ? top.long_running_reminder_interval_ms : undefined) ?? legacy?.long_running_reminder_interval_ms;
|
|
32839
|
+
const topDetachOnUserMessage = typeof top === "object" && top !== null ? top.detach_on_user_message ?? true : true;
|
|
32460
32840
|
const rawForegroundWait = typeof top === "object" && top !== null ? top.foreground_wait_window_ms : undefined;
|
|
32461
32841
|
const foregroundWaitWindowMs = Math.max(FOREGROUND_WAIT_WINDOW_MIN_MS, rawForegroundWait ?? FOREGROUND_WAIT_WINDOW_DEFAULT_MS);
|
|
32462
32842
|
const base = {
|
|
@@ -32465,9 +32845,11 @@ function resolveBashConfig(config2) {
|
|
|
32465
32845
|
compress: false,
|
|
32466
32846
|
background: false,
|
|
32467
32847
|
host_fallback: false,
|
|
32848
|
+
detach_on_user_message: true,
|
|
32468
32849
|
long_running_reminder_enabled: reminderEnabled,
|
|
32469
32850
|
long_running_reminder_interval_ms: reminderInterval,
|
|
32470
|
-
foreground_wait_window_ms: foregroundWaitWindowMs
|
|
32851
|
+
foreground_wait_window_ms: foregroundWaitWindowMs,
|
|
32852
|
+
powershell_tool: typeof top === "object" && top !== null ? top.powershell_tool ?? false : false
|
|
32471
32853
|
};
|
|
32472
32854
|
if (top === false)
|
|
32473
32855
|
return base;
|
|
@@ -32481,7 +32863,8 @@ function resolveBashConfig(config2) {
|
|
|
32481
32863
|
rewrite: top.rewrite ?? true,
|
|
32482
32864
|
compress: top.compress ?? true,
|
|
32483
32865
|
background: top.background ?? true,
|
|
32484
|
-
host_fallback: top.host_fallback ?? false
|
|
32866
|
+
host_fallback: top.host_fallback ?? false,
|
|
32867
|
+
detach_on_user_message: topDetachOnUserMessage
|
|
32485
32868
|
};
|
|
32486
32869
|
}
|
|
32487
32870
|
const hasLegacyFeatureFlag = legacy && (legacy.rewrite !== undefined || legacy.compress !== undefined || legacy.background !== undefined);
|
|
@@ -32595,9 +32978,11 @@ var BashFeaturesSchema = exports_external.object({
|
|
|
32595
32978
|
compress: exports_external.boolean().optional(),
|
|
32596
32979
|
background: exports_external.boolean().optional(),
|
|
32597
32980
|
host_fallback: exports_external.boolean().optional(),
|
|
32981
|
+
detach_on_user_message: exports_external.boolean().optional(),
|
|
32598
32982
|
long_running_reminder_enabled: exports_external.boolean().optional(),
|
|
32599
32983
|
long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
|
|
32600
|
-
foreground_wait_window_ms: exports_external.number().int().positive().optional()
|
|
32984
|
+
foreground_wait_window_ms: exports_external.number().int().positive().optional(),
|
|
32985
|
+
powershell_tool: exports_external.boolean().optional()
|
|
32601
32986
|
});
|
|
32602
32987
|
var BashConfigSchema = exports_external.union([exports_external.boolean(), BashFeaturesSchema]);
|
|
32603
32988
|
var SandboxConfigSchema = exports_external.object({
|
|
@@ -32617,6 +33002,9 @@ var GhShimConfigSchema = exports_external.object({
|
|
|
32617
33002
|
enabled: exports_external.boolean().optional(),
|
|
32618
33003
|
binary_path: exports_external.string().trim().refine(isAbsolute6, "gh_shim.binary_path must be absolute").optional()
|
|
32619
33004
|
});
|
|
33005
|
+
var GhReadConfigSchema = exports_external.object({
|
|
33006
|
+
enabled: exports_external.boolean().optional()
|
|
33007
|
+
});
|
|
32620
33008
|
var GitCoAuthorSchema = exports_external.string().trim().refine((value) => value === "off" || value === "auto" || /^[^<>\r\n]+\s+<[^<>\s@]+@[^<>\s@]+>$/.test(value), "git.co_author must be 'off', 'auto', or an explicit 'Name <email>' identity");
|
|
32621
33009
|
var GitConfigSchema = exports_external.object({
|
|
32622
33010
|
co_author: GitCoAuthorSchema.optional()
|
|
@@ -32640,7 +33028,7 @@ var BackupConfigSchema = exports_external.object({
|
|
|
32640
33028
|
max_depth: exports_external.number().int().positive().optional(),
|
|
32641
33029
|
max_file_size: exports_external.number().int().positive().optional()
|
|
32642
33030
|
});
|
|
32643
|
-
var
|
|
33031
|
+
var AftConfigFieldsSchema = exports_external.object({
|
|
32644
33032
|
$schema: exports_external.string().optional(),
|
|
32645
33033
|
enabled: exports_external.boolean().optional(),
|
|
32646
33034
|
edit_mode: exports_external.enum(["default", "hashline"]).optional(),
|
|
@@ -32671,8 +33059,22 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
|
|
|
32671
33059
|
bridge: BridgeConfigSchema.optional(),
|
|
32672
33060
|
subc: SubcConfigSchema.optional(),
|
|
32673
33061
|
gh_shim: GhShimConfigSchema.optional(),
|
|
33062
|
+
gh_read: GhReadConfigSchema.optional(),
|
|
32674
33063
|
git: GitConfigSchema.optional()
|
|
33064
|
+
});
|
|
33065
|
+
var HarnessOverrideSchema = exports_external.preprocess((value) => {
|
|
33066
|
+
if (!isConfigRecord(value) || !Object.hasOwn(value, "harnesses"))
|
|
33067
|
+
return value;
|
|
33068
|
+
const { harnesses: _nestedHarnesses, ...override } = value;
|
|
33069
|
+
return override;
|
|
33070
|
+
}, AftConfigFieldsSchema.strict());
|
|
33071
|
+
var AftConfigSchema = exports_external.preprocess(normalizeConfigForActiveHarness, AftConfigFieldsSchema.extend({
|
|
33072
|
+
harnesses: exports_external.record(exports_external.string(), HarnessOverrideSchema).optional()
|
|
32675
33073
|
}).strict());
|
|
33074
|
+
function applyActiveHarnessOverride(config2) {
|
|
33075
|
+
const { harnesses: _harnesses, ...base } = config2;
|
|
33076
|
+
return { ...base, ...config2.harnesses?.[ACTIVE_HARNESS] };
|
|
33077
|
+
}
|
|
32676
33078
|
var CONFIG_MIGRATIONS = [
|
|
32677
33079
|
{ oldKey: "experimental_search_index", newPath: ["search_index"] },
|
|
32678
33080
|
{ oldKey: "experimental_semantic_search", newPath: ["semantic_search"] },
|
|
@@ -32783,7 +33185,7 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
|
|
|
32783
33185
|
return movedKeys;
|
|
32784
33186
|
}
|
|
32785
33187
|
function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
|
|
32786
|
-
if (!
|
|
33188
|
+
if (!existsSync11(configPath)) {
|
|
32787
33189
|
return { migrated: false, oldKeys: [] };
|
|
32788
33190
|
}
|
|
32789
33191
|
let tmpPath = null;
|
|
@@ -32842,7 +33244,7 @@ function warnIgnoredHarnessSpecificConfigKeys(config2, configPath) {
|
|
|
32842
33244
|
}
|
|
32843
33245
|
function loadConfigFromPath(configPath) {
|
|
32844
33246
|
try {
|
|
32845
|
-
if (!
|
|
33247
|
+
if (!existsSync11(configPath))
|
|
32846
33248
|
return null;
|
|
32847
33249
|
const content = readFileSync7(configPath, "utf-8");
|
|
32848
33250
|
const rawConfig = import_comment_json.parse(content);
|
|
@@ -32853,14 +33255,15 @@ function loadConfigFromPath(configPath) {
|
|
|
32853
33255
|
migrateRawConfig(rawConfig, configPath, { log: log2, warn: warn2 });
|
|
32854
33256
|
const cleanConfig = stripJsoncSymbols(rawConfig);
|
|
32855
33257
|
warnIgnoredHarnessSpecificConfigKeys(cleanConfig, configPath);
|
|
33258
|
+
warnIgnoredNestedHarnesses(cleanConfig, configPath);
|
|
32856
33259
|
const result = AftConfigSchema.safeParse(cleanConfig);
|
|
32857
33260
|
if (result.success) {
|
|
32858
33261
|
log2(`Config loaded from ${configPath}`);
|
|
32859
|
-
return result.data;
|
|
33262
|
+
return applyActiveHarnessOverride(result.data);
|
|
32860
33263
|
}
|
|
32861
33264
|
const errorMsg = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
|
|
32862
33265
|
warn2(`Config validation error in ${configPath}: ${errorMsg}`);
|
|
32863
|
-
return parseConfigPartially(cleanConfig);
|
|
33266
|
+
return applyActiveHarnessOverride(parseConfigPartially(cleanConfig));
|
|
32864
33267
|
} catch (err) {
|
|
32865
33268
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
32866
33269
|
error2(`Error loading config from ${configPath}: ${errorMsg}`);
|
|
@@ -33059,6 +33462,8 @@ function getStrippedTopLevelKeys(override) {
|
|
|
33059
33462
|
stripped.push("subc");
|
|
33060
33463
|
if (override.gh_shim !== undefined)
|
|
33061
33464
|
stripped.push("gh_shim");
|
|
33465
|
+
if (override.gh_read !== undefined)
|
|
33466
|
+
stripped.push("gh_read");
|
|
33062
33467
|
if (override.disabled_tools?.includes("aft_safety"))
|
|
33063
33468
|
stripped.push("disabled_tools.aft_safety");
|
|
33064
33469
|
return stripped;
|
|
@@ -33172,11 +33577,11 @@ function loadAftConfig(projectDirectory) {
|
|
|
33172
33577
|
}
|
|
33173
33578
|
|
|
33174
33579
|
// src/lsp-auto-install.ts
|
|
33175
|
-
import { spawn as
|
|
33580
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
33176
33581
|
import { createHash as createHash4 } from "node:crypto";
|
|
33177
33582
|
import {
|
|
33178
33583
|
createReadStream,
|
|
33179
|
-
existsSync as
|
|
33584
|
+
existsSync as existsSync13,
|
|
33180
33585
|
mkdirSync as mkdirSync7,
|
|
33181
33586
|
readFileSync as readFileSync10,
|
|
33182
33587
|
renameSync as renameSync6,
|
|
@@ -33184,9 +33589,10 @@ import {
|
|
|
33184
33589
|
statSync as statSync8,
|
|
33185
33590
|
writeFileSync as writeFileSync6
|
|
33186
33591
|
} from "node:fs";
|
|
33187
|
-
import { join as
|
|
33592
|
+
import { join as join15 } from "node:path";
|
|
33188
33593
|
|
|
33189
33594
|
// src/lsp-cache.ts
|
|
33595
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
33190
33596
|
import {
|
|
33191
33597
|
closeSync as closeSync5,
|
|
33192
33598
|
mkdirSync as mkdirSync6,
|
|
@@ -33196,23 +33602,23 @@ import {
|
|
|
33196
33602
|
unlinkSync as unlinkSync6,
|
|
33197
33603
|
writeFileSync as writeFileSync5
|
|
33198
33604
|
} from "node:fs";
|
|
33199
|
-
import { join as
|
|
33605
|
+
import { join as join13 } from "node:path";
|
|
33200
33606
|
function lspCacheRoot() {
|
|
33201
33607
|
return getAftLspPackagesDir();
|
|
33202
33608
|
}
|
|
33203
33609
|
function lspPackageDir(npmPackage) {
|
|
33204
|
-
return
|
|
33610
|
+
return join13(lspCacheRoot(), encodeURIComponent(npmPackage));
|
|
33205
33611
|
}
|
|
33206
33612
|
function lspBinaryPath(npmPackage, binary) {
|
|
33207
|
-
return
|
|
33613
|
+
return join13(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
|
|
33208
33614
|
}
|
|
33209
33615
|
function lspBinDir(npmPackage) {
|
|
33210
|
-
return
|
|
33616
|
+
return join13(lspPackageDir(npmPackage), "node_modules", ".bin");
|
|
33211
33617
|
}
|
|
33212
33618
|
function isInstalled(npmPackage, binary) {
|
|
33213
33619
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
33214
33620
|
try {
|
|
33215
|
-
if (statSync7(
|
|
33621
|
+
if (statSync7(join13(lspBinDir(npmPackage), candidate)).isFile())
|
|
33216
33622
|
return true;
|
|
33217
33623
|
} catch {}
|
|
33218
33624
|
}
|
|
@@ -33232,13 +33638,13 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
|
|
|
33232
33638
|
installedAt: new Date().toISOString(),
|
|
33233
33639
|
...sha256 ? { sha256 } : {}
|
|
33234
33640
|
};
|
|
33235
|
-
writeFileSync5(
|
|
33641
|
+
writeFileSync5(join13(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
|
|
33236
33642
|
} catch (err) {
|
|
33237
33643
|
log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
|
|
33238
33644
|
}
|
|
33239
33645
|
}
|
|
33240
33646
|
function readInstalledMetaIn(installDir) {
|
|
33241
|
-
const path2 =
|
|
33647
|
+
const path2 = join13(installDir, INSTALLED_META_FILE);
|
|
33242
33648
|
try {
|
|
33243
33649
|
if (!statSync7(path2).isFile())
|
|
33244
33650
|
return null;
|
|
@@ -33262,33 +33668,52 @@ function readInstalledMeta(packageKey) {
|
|
|
33262
33668
|
return readInstalledMetaIn(lspPackageDir(packageKey));
|
|
33263
33669
|
}
|
|
33264
33670
|
function lockPath(npmPackage) {
|
|
33265
|
-
return
|
|
33671
|
+
return join13(lspPackageDir(npmPackage), ".aft-installing");
|
|
33266
33672
|
}
|
|
33267
33673
|
var STALE_LOCK_MS2 = 30 * 60 * 1000;
|
|
33268
33674
|
function acquireInstallLock(lockKey) {
|
|
33269
33675
|
mkdirSync6(lspPackageDir(lockKey), { recursive: true });
|
|
33270
33676
|
const lock = lockPath(lockKey);
|
|
33677
|
+
const token = randomUUID2();
|
|
33271
33678
|
const tryClaim = () => {
|
|
33272
33679
|
try {
|
|
33273
33680
|
const fd = openSync5(lock, "wx");
|
|
33274
33681
|
try {
|
|
33275
33682
|
writeFileSync5(fd, `${process.pid}
|
|
33276
33683
|
${new Date().toISOString()}
|
|
33684
|
+
${token}
|
|
33277
33685
|
`);
|
|
33278
33686
|
} finally {
|
|
33279
33687
|
closeSync5(fd);
|
|
33280
33688
|
}
|
|
33281
|
-
|
|
33689
|
+
let retained = false;
|
|
33690
|
+
let released = false;
|
|
33691
|
+
return {
|
|
33692
|
+
retain() {
|
|
33693
|
+
retained = true;
|
|
33694
|
+
},
|
|
33695
|
+
release() {
|
|
33696
|
+
if (released)
|
|
33697
|
+
return;
|
|
33698
|
+
released = true;
|
|
33699
|
+
if (retained) {
|
|
33700
|
+
warn2(`[lsp] retaining install lock for ${lockKey} after unconfirmed npm termination; ` + `cross-process retries remain blocked until stale-lock recovery`);
|
|
33701
|
+
return;
|
|
33702
|
+
}
|
|
33703
|
+
releaseInstallLock(lockKey, token);
|
|
33704
|
+
}
|
|
33705
|
+
};
|
|
33282
33706
|
} catch (err) {
|
|
33283
33707
|
const code = err.code;
|
|
33284
33708
|
if (code === "EEXIST")
|
|
33285
|
-
return
|
|
33709
|
+
return null;
|
|
33286
33710
|
warn2(`[lsp] unexpected error acquiring install lock for ${lockKey}: ${err}`);
|
|
33287
|
-
return
|
|
33711
|
+
return null;
|
|
33288
33712
|
}
|
|
33289
33713
|
};
|
|
33290
|
-
|
|
33291
|
-
|
|
33714
|
+
const claimed = tryClaim();
|
|
33715
|
+
if (claimed)
|
|
33716
|
+
return claimed;
|
|
33292
33717
|
let owningPid = null;
|
|
33293
33718
|
let lockMtimeMs = 0;
|
|
33294
33719
|
try {
|
|
@@ -33306,7 +33731,7 @@ ${new Date().toISOString()}
|
|
|
33306
33731
|
const skipLiveness = process.platform === "win32";
|
|
33307
33732
|
const ownerAlive = !skipLiveness && owningPid !== null && isProcessAlive3(owningPid);
|
|
33308
33733
|
if (skipLiveness ? ageWithinFresh : ownerAlive && ageWithinFresh) {
|
|
33309
|
-
return
|
|
33734
|
+
return null;
|
|
33310
33735
|
}
|
|
33311
33736
|
log2(`[lsp] reclaiming install lock for ${lockKey} (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
|
|
33312
33737
|
try {
|
|
@@ -33325,16 +33750,18 @@ function isProcessAlive3(pid) {
|
|
|
33325
33750
|
return true;
|
|
33326
33751
|
}
|
|
33327
33752
|
}
|
|
33328
|
-
function releaseInstallLock(lockKey) {
|
|
33753
|
+
function releaseInstallLock(lockKey, acquisitionToken) {
|
|
33329
33754
|
const lock = lockPath(lockKey);
|
|
33330
33755
|
try {
|
|
33331
33756
|
let owningPid = null;
|
|
33757
|
+
let owningToken = "";
|
|
33332
33758
|
try {
|
|
33333
33759
|
const raw = readFileSync8(lock, "utf8");
|
|
33334
|
-
const
|
|
33335
|
-
const parsed = Number.parseInt(
|
|
33760
|
+
const lines = raw.split(/\r?\n/);
|
|
33761
|
+
const parsed = Number.parseInt(lines[0]?.trim() ?? "", 10);
|
|
33336
33762
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
33337
33763
|
owningPid = parsed;
|
|
33764
|
+
owningToken = lines[2]?.trim() ?? "";
|
|
33338
33765
|
} catch (readErr) {
|
|
33339
33766
|
const code = readErr.code;
|
|
33340
33767
|
if (code === "ENOENT")
|
|
@@ -33342,8 +33769,8 @@ function releaseInstallLock(lockKey) {
|
|
|
33342
33769
|
warn2(`[lsp] could not read install lock for ${lockKey} during release: ${readErr}`);
|
|
33343
33770
|
return;
|
|
33344
33771
|
}
|
|
33345
|
-
if (owningPid !== process.pid) {
|
|
33346
|
-
log2(`[lsp] not releasing install lock for ${lockKey}:
|
|
33772
|
+
if (owningPid !== process.pid || owningToken !== acquisitionToken) {
|
|
33773
|
+
log2(`[lsp] not releasing install lock for ${lockKey}: acquisition ownership changed`);
|
|
33347
33774
|
return;
|
|
33348
33775
|
}
|
|
33349
33776
|
try {
|
|
@@ -33359,17 +33786,18 @@ function releaseInstallLock(lockKey) {
|
|
|
33359
33786
|
}
|
|
33360
33787
|
}
|
|
33361
33788
|
async function withInstallLock(lockKey, task) {
|
|
33362
|
-
|
|
33789
|
+
const lease = acquireInstallLock(lockKey);
|
|
33790
|
+
if (!lease)
|
|
33363
33791
|
return null;
|
|
33364
33792
|
try {
|
|
33365
|
-
return await task();
|
|
33793
|
+
return await task(lease);
|
|
33366
33794
|
} finally {
|
|
33367
|
-
|
|
33795
|
+
lease.release();
|
|
33368
33796
|
}
|
|
33369
33797
|
}
|
|
33370
33798
|
var VERSION_CHECK_FILE = ".aft-version-check";
|
|
33371
33799
|
function readVersionCheck(npmPackage) {
|
|
33372
|
-
const file2 =
|
|
33800
|
+
const file2 = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
33373
33801
|
try {
|
|
33374
33802
|
const raw = readFileSync8(file2, "utf8");
|
|
33375
33803
|
const parsed = JSON.parse(raw);
|
|
@@ -33386,7 +33814,7 @@ function readVersionCheck(npmPackage) {
|
|
|
33386
33814
|
}
|
|
33387
33815
|
function writeVersionCheck(npmPackage, latest) {
|
|
33388
33816
|
mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
|
|
33389
|
-
const file2 =
|
|
33817
|
+
const file2 = join13(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
33390
33818
|
const record2 = {
|
|
33391
33819
|
last_checked: new Date().toISOString(),
|
|
33392
33820
|
latest_eligible: latest
|
|
@@ -33548,8 +33976,8 @@ var NPM_LSP_TABLE = [
|
|
|
33548
33976
|
];
|
|
33549
33977
|
|
|
33550
33978
|
// src/lsp-project-relevance.ts
|
|
33551
|
-
import { existsSync as
|
|
33552
|
-
import { join as
|
|
33979
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
|
|
33980
|
+
import { join as join14 } from "node:path";
|
|
33553
33981
|
var MAX_WALK_DIRS = 200;
|
|
33554
33982
|
var MAX_WALK_DEPTH = 4;
|
|
33555
33983
|
var NOISE_DIRS = new Set([
|
|
@@ -33566,7 +33994,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
|
|
|
33566
33994
|
if (!rootMarkers)
|
|
33567
33995
|
return false;
|
|
33568
33996
|
for (const marker of rootMarkers) {
|
|
33569
|
-
if (
|
|
33997
|
+
if (existsSync12(join14(projectRoot, marker)))
|
|
33570
33998
|
return true;
|
|
33571
33999
|
}
|
|
33572
34000
|
return false;
|
|
@@ -33590,7 +34018,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
|
|
|
33590
34018
|
}
|
|
33591
34019
|
function readPackageJson(projectRoot) {
|
|
33592
34020
|
try {
|
|
33593
|
-
const raw = readFileSync9(
|
|
34021
|
+
const raw = readFileSync9(join14(projectRoot, "package.json"), "utf8");
|
|
33594
34022
|
const parsed = JSON.parse(raw);
|
|
33595
34023
|
if (typeof parsed !== "object" || parsed === null)
|
|
33596
34024
|
return null;
|
|
@@ -33620,7 +34048,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
|
|
|
33620
34048
|
for (const entry of entries) {
|
|
33621
34049
|
if (entry.isDirectory()) {
|
|
33622
34050
|
if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
|
|
33623
|
-
queue.push({ dir:
|
|
34051
|
+
queue.push({ dir: join14(current.dir, entry.name), depth: current.depth + 1 });
|
|
33624
34052
|
}
|
|
33625
34053
|
continue;
|
|
33626
34054
|
}
|
|
@@ -33709,6 +34137,7 @@ function buildExtensionMap(specs) {
|
|
|
33709
34137
|
return byExt;
|
|
33710
34138
|
}
|
|
33711
34139
|
var inFlightAutoInstalls = new Set;
|
|
34140
|
+
var quarantinedNpmInstalls = new Set;
|
|
33712
34141
|
function trackInFlightAutoInstall(controller, promise2) {
|
|
33713
34142
|
const entry = { controller, promise: promise2 };
|
|
33714
34143
|
inFlightAutoInstalls.add(entry);
|
|
@@ -33747,8 +34176,8 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
|
|
|
33747
34176
|
}
|
|
33748
34177
|
function ensureInstallAnchor(cwd) {
|
|
33749
34178
|
try {
|
|
33750
|
-
const stub =
|
|
33751
|
-
if (!
|
|
34179
|
+
const stub = join15(cwd, "package.json");
|
|
34180
|
+
if (!existsSync13(stub)) {
|
|
33752
34181
|
writeFileSync6(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
|
|
33753
34182
|
`);
|
|
33754
34183
|
}
|
|
@@ -33756,7 +34185,7 @@ function ensureInstallAnchor(cwd) {
|
|
|
33756
34185
|
warn2(`[lsp] could not write package.json stub in ${cwd}: ${err}`);
|
|
33757
34186
|
}
|
|
33758
34187
|
}
|
|
33759
|
-
function runInstall(spec, version2, cwd, signal) {
|
|
34188
|
+
function runInstall(spec, version2, cwd, installLock, signal) {
|
|
33760
34189
|
return new Promise((resolve8) => {
|
|
33761
34190
|
const target = `${spec.npm}@${version2}`;
|
|
33762
34191
|
log2(`[lsp] installing ${target} to ${cwd}`);
|
|
@@ -33772,19 +34201,25 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
33772
34201
|
return;
|
|
33773
34202
|
}
|
|
33774
34203
|
ensureInstallAnchor(cwd);
|
|
33775
|
-
const
|
|
34204
|
+
const invocation = npmInvocation(npm, [
|
|
34205
|
+
"install",
|
|
34206
|
+
"--no-save",
|
|
34207
|
+
"--ignore-scripts",
|
|
34208
|
+
"--silent",
|
|
34209
|
+
target
|
|
34210
|
+
]);
|
|
34211
|
+
const child = spawn4(invocation.command, invocation.args, {
|
|
33776
34212
|
stdio: ["ignore", "pipe", "pipe"],
|
|
33777
34213
|
cwd,
|
|
33778
|
-
env: npmSpawnEnv(npm)
|
|
34214
|
+
env: { ...npmSpawnEnv(npm), ...invocation.env },
|
|
34215
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments
|
|
33779
34216
|
});
|
|
33780
34217
|
child.unref();
|
|
33781
34218
|
let stderrBuf = "";
|
|
33782
34219
|
let settled = false;
|
|
33783
|
-
let
|
|
34220
|
+
let terminationPromise = null;
|
|
33784
34221
|
const cleanup = () => {
|
|
33785
34222
|
signal?.removeEventListener("abort", onAbort);
|
|
33786
|
-
if (killTimer)
|
|
33787
|
-
clearTimeout(killTimer);
|
|
33788
34223
|
};
|
|
33789
34224
|
const finish = (ok) => {
|
|
33790
34225
|
if (settled)
|
|
@@ -33793,14 +34228,31 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
33793
34228
|
cleanup();
|
|
33794
34229
|
resolve8(ok);
|
|
33795
34230
|
};
|
|
34231
|
+
const childCompletedSuccessfully = () => child.exitCode === 0 && child.signalCode === null;
|
|
34232
|
+
const finishAfterConfirmedTermination = () => {
|
|
34233
|
+
const completedSuccessfully = childCompletedSuccessfully();
|
|
34234
|
+
if (completedSuccessfully)
|
|
34235
|
+
log2(`[lsp] installed ${target}`);
|
|
34236
|
+
finish(completedSuccessfully);
|
|
34237
|
+
};
|
|
33796
34238
|
const onAbort = () => {
|
|
34239
|
+
if (childCompletedSuccessfully()) {
|
|
34240
|
+
finishAfterConfirmedTermination();
|
|
34241
|
+
return;
|
|
34242
|
+
}
|
|
33797
34243
|
warn2(`[lsp] install ${target} aborted during shutdown`);
|
|
33798
|
-
child
|
|
33799
|
-
|
|
33800
|
-
if (
|
|
33801
|
-
|
|
33802
|
-
|
|
33803
|
-
|
|
34244
|
+
terminationPromise ??= terminateNpmProcessTree(child, invocation);
|
|
34245
|
+
terminationPromise.then(finishAfterConfirmedTermination, (terminationError) => {
|
|
34246
|
+
if (child.pid === undefined) {
|
|
34247
|
+
error2(`[lsp] install ${target} failed to spawn during shutdown: ${terminationError}`);
|
|
34248
|
+
finish(false);
|
|
34249
|
+
return;
|
|
34250
|
+
}
|
|
34251
|
+
quarantinedNpmInstalls.add(spec.npm);
|
|
34252
|
+
installLock.retain();
|
|
34253
|
+
error2(`[lsp] install ${target} termination outcome unknown; quarantining retries for this session: ${String(terminationError)}`);
|
|
34254
|
+
finish(false);
|
|
34255
|
+
});
|
|
33804
34256
|
};
|
|
33805
34257
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
33806
34258
|
if (signal?.aborted)
|
|
@@ -33814,10 +34266,16 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
33814
34266
|
}
|
|
33815
34267
|
});
|
|
33816
34268
|
child.on("error", (err) => {
|
|
33817
|
-
|
|
34269
|
+
if (settled)
|
|
34270
|
+
return;
|
|
34271
|
+
error2(`[lsp] install ${target} child-process error: ${err}`);
|
|
34272
|
+
if (terminationPromise && child.pid !== undefined)
|
|
34273
|
+
return;
|
|
33818
34274
|
finish(false);
|
|
33819
34275
|
});
|
|
33820
34276
|
child.on("exit", (code) => {
|
|
34277
|
+
if (settled || terminationPromise)
|
|
34278
|
+
return;
|
|
33821
34279
|
if (code === 0) {
|
|
33822
34280
|
log2(`[lsp] installed ${target}`);
|
|
33823
34281
|
finish(true);
|
|
@@ -33830,7 +34288,13 @@ ${stderrBuf.trim()}`);
|
|
|
33830
34288
|
});
|
|
33831
34289
|
}
|
|
33832
34290
|
async function ensureServerInstalled(spec, config2, fetchImpl, signal) {
|
|
33833
|
-
|
|
34291
|
+
if (quarantinedNpmInstalls.has(spec.npm)) {
|
|
34292
|
+
return {
|
|
34293
|
+
started: false,
|
|
34294
|
+
reason: "install blocked after unconfirmed npm termination; restart the host to retry"
|
|
34295
|
+
};
|
|
34296
|
+
}
|
|
34297
|
+
const outcome = await withInstallLock(spec.npm, async (installLock) => {
|
|
33834
34298
|
const { version: version2, probe } = await resolveTargetVersion(spec, config2, fetchImpl);
|
|
33835
34299
|
if (!version2) {
|
|
33836
34300
|
const installed = isInstalled(spec.npm, spec.binary);
|
|
@@ -33866,7 +34330,7 @@ async function ensureServerInstalled(spec, config2, fetchImpl, signal) {
|
|
|
33866
34330
|
log2(`[lsp] reinstalling ${spec.npm}@${version2}: no installed-version metadata recorded`);
|
|
33867
34331
|
}
|
|
33868
34332
|
}
|
|
33869
|
-
const ok = await runInstall(spec, version2, cachedPackageDir(spec.npm), signal).catch((err) => {
|
|
34333
|
+
const ok = await runInstall(spec, version2, cachedPackageDir(spec.npm), installLock, signal).catch((err) => {
|
|
33870
34334
|
error2(`[lsp] background install ${spec.npm} crashed: ${err}`);
|
|
33871
34335
|
return false;
|
|
33872
34336
|
});
|
|
@@ -33939,10 +34403,10 @@ function sha256OfFileSync(path2) {
|
|
|
33939
34403
|
}
|
|
33940
34404
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
33941
34405
|
const packageDir = lspPackageDir(spec.npm);
|
|
33942
|
-
const dest =
|
|
34406
|
+
const dest = join15(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
|
|
33943
34407
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
33944
34408
|
try {
|
|
33945
|
-
mkdirSync7(
|
|
34409
|
+
mkdirSync7(join15(dest, ".."), { recursive: true });
|
|
33946
34410
|
rmSync4(dest, { recursive: true, force: true });
|
|
33947
34411
|
renameSync6(packageDir, dest);
|
|
33948
34412
|
} catch (err) {
|
|
@@ -34030,7 +34494,7 @@ import {
|
|
|
34030
34494
|
copyFileSync as copyFileSync4,
|
|
34031
34495
|
createReadStream as createReadStream2,
|
|
34032
34496
|
createWriteStream as createWriteStream3,
|
|
34033
|
-
existsSync as
|
|
34497
|
+
existsSync as existsSync14,
|
|
34034
34498
|
lstatSync as lstatSync2,
|
|
34035
34499
|
mkdirSync as mkdirSync8,
|
|
34036
34500
|
readdirSync as readdirSync5,
|
|
@@ -34043,7 +34507,7 @@ import {
|
|
|
34043
34507
|
unlinkSync as unlinkSync7,
|
|
34044
34508
|
writeFileSync as writeFileSync7
|
|
34045
34509
|
} from "node:fs";
|
|
34046
|
-
import { dirname as dirname6, join as
|
|
34510
|
+
import { dirname as dirname6, join as join16, relative as relative3, resolve as resolve8 } from "node:path";
|
|
34047
34511
|
import { Readable as Readable3 } from "node:stream";
|
|
34048
34512
|
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
34049
34513
|
|
|
@@ -34136,23 +34600,23 @@ function ghCacheRoot() {
|
|
|
34136
34600
|
return getAftLspBinariesDir();
|
|
34137
34601
|
}
|
|
34138
34602
|
function ghPackageDir(spec) {
|
|
34139
|
-
return
|
|
34603
|
+
return join16(ghCacheRoot(), spec.id);
|
|
34140
34604
|
}
|
|
34141
34605
|
function ghBinDir(spec) {
|
|
34142
|
-
return
|
|
34606
|
+
return join16(ghPackageDir(spec), "bin");
|
|
34143
34607
|
}
|
|
34144
34608
|
function ghExtractDir(spec) {
|
|
34145
|
-
return
|
|
34609
|
+
return join16(ghPackageDir(spec), "extracted");
|
|
34146
34610
|
}
|
|
34147
34611
|
var INSTALLED_META_FILE2 = ".aft-installed";
|
|
34148
34612
|
function ghBinaryPath(spec, platform) {
|
|
34149
34613
|
const ext = platform === "win32" ? ".exe" : "";
|
|
34150
|
-
return
|
|
34614
|
+
return join16(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
34151
34615
|
}
|
|
34152
34616
|
function isGithubInstalled(spec, platform) {
|
|
34153
34617
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
34154
34618
|
try {
|
|
34155
|
-
if (statSync9(
|
|
34619
|
+
if (statSync9(join16(ghBinDir(spec), candidate)).isFile())
|
|
34156
34620
|
return true;
|
|
34157
34621
|
} catch {}
|
|
34158
34622
|
}
|
|
@@ -34165,7 +34629,7 @@ function ghBinaryCandidates(spec, platform) {
|
|
|
34165
34629
|
}
|
|
34166
34630
|
function readGithubInstalledMetaIn(installDir) {
|
|
34167
34631
|
try {
|
|
34168
|
-
const path2 =
|
|
34632
|
+
const path2 = join16(installDir, INSTALLED_META_FILE2);
|
|
34169
34633
|
if (!statSync9(path2).isFile())
|
|
34170
34634
|
return null;
|
|
34171
34635
|
const parsed = JSON.parse(readFileSync11(path2, "utf8"));
|
|
@@ -34192,7 +34656,7 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
|
|
|
34192
34656
|
binarySha256,
|
|
34193
34657
|
...archiveSha256 ? { archiveSha256 } : {}
|
|
34194
34658
|
};
|
|
34195
|
-
writeFileSync7(
|
|
34659
|
+
writeFileSync7(join16(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
|
|
34196
34660
|
} catch (err) {
|
|
34197
34661
|
warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
|
|
34198
34662
|
}
|
|
@@ -34441,7 +34905,7 @@ function validateExtraction(stagingRoot) {
|
|
|
34441
34905
|
throw new Error(`failed to read staging dir ${dir}: ${err}`);
|
|
34442
34906
|
}
|
|
34443
34907
|
for (const entry of entries) {
|
|
34444
|
-
const full =
|
|
34908
|
+
const full = join16(dir, entry);
|
|
34445
34909
|
let lst;
|
|
34446
34910
|
try {
|
|
34447
34911
|
lst = lstatSync2(full);
|
|
@@ -34529,7 +34993,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
34529
34993
|
}
|
|
34530
34994
|
function quarantineCachedGithubInstall(spec, reason) {
|
|
34531
34995
|
const packageDir = ghPackageDir(spec);
|
|
34532
|
-
const dest =
|
|
34996
|
+
const dest = join16(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
|
|
34533
34997
|
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
34534
34998
|
try {
|
|
34535
34999
|
mkdirSync8(dirname6(dest), { recursive: true });
|
|
@@ -34542,7 +35006,7 @@ function quarantineCachedGithubInstall(spec, reason) {
|
|
|
34542
35006
|
function validateCachedGithubInstall(spec, platform) {
|
|
34543
35007
|
const packageDir = ghPackageDir(spec);
|
|
34544
35008
|
const meta3 = readGithubInstalledMetaIn(packageDir);
|
|
34545
|
-
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) =>
|
|
35009
|
+
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join16(ghBinDir(spec), candidate)).find((candidate) => {
|
|
34546
35010
|
try {
|
|
34547
35011
|
return statSync9(candidate).isFile();
|
|
34548
35012
|
} catch {
|
|
@@ -34620,7 +35084,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
34620
35084
|
}
|
|
34621
35085
|
const pkgDir = ghPackageDir(spec);
|
|
34622
35086
|
const extractDir = ghExtractDir(spec);
|
|
34623
|
-
const archivePath =
|
|
35087
|
+
const archivePath = join16(pkgDir, expected.name);
|
|
34624
35088
|
log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
|
|
34625
35089
|
try {
|
|
34626
35090
|
await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
|
|
@@ -34660,8 +35124,8 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
34660
35124
|
unlinkSync7(archivePath);
|
|
34661
35125
|
} catch {}
|
|
34662
35126
|
}
|
|
34663
|
-
const innerBinaryPath =
|
|
34664
|
-
if (!
|
|
35127
|
+
const innerBinaryPath = join16(extractDir, spec.binaryPathInArchive(platform, arch, version2));
|
|
35128
|
+
if (!existsSync14(innerBinaryPath)) {
|
|
34665
35129
|
error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
|
|
34666
35130
|
return null;
|
|
34667
35131
|
}
|
|
@@ -34745,7 +35209,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
|
|
|
34745
35209
|
if (!host) {
|
|
34746
35210
|
for (const spec of GITHUB_LSP_TABLE) {
|
|
34747
35211
|
try {
|
|
34748
|
-
if (
|
|
35212
|
+
if (existsSync14(ghBinDir(spec))) {
|
|
34749
35213
|
cachedBinDirs.push(ghBinDir(spec));
|
|
34750
35214
|
}
|
|
34751
35215
|
} catch {}
|
|
@@ -34972,6 +35436,26 @@ function sendFeatureAnnouncement(version2, features, footer, storageDir) {
|
|
|
34972
35436
|
|
|
34973
35437
|
// src/bash-wait-detach.ts
|
|
34974
35438
|
var BASH_TRANSPORT_TIMEOUT_MS = 30000;
|
|
35439
|
+
var BASH_WAIT_DETACH_MAGIC_KEYWORD = "&detach";
|
|
35440
|
+
var EMPTY_DETACH_MESSAGE = "(requested background detach)";
|
|
35441
|
+
var STANDALONE_DETACH_KEYWORD_SOURCE = `(^|[^\\p{L}\\p{N}_])${BASH_WAIT_DETACH_MAGIC_KEYWORD}(?![\\p{L}\\p{N}_])`;
|
|
35442
|
+
var STANDALONE_DETACH_KEYWORD_PATTERN = new RegExp(STANDALONE_DETACH_KEYWORD_SOURCE, "u");
|
|
35443
|
+
var STANDALONE_DETACH_KEYWORDS_PATTERN = new RegExp(STANDALONE_DETACH_KEYWORD_SOURCE, "gu");
|
|
35444
|
+
function containsStandaloneDetachKeyword(messageText) {
|
|
35445
|
+
return STANDALONE_DETACH_KEYWORD_PATTERN.test(messageText);
|
|
35446
|
+
}
|
|
35447
|
+
function stripStandaloneDetachKeywords(messageText) {
|
|
35448
|
+
return messageText.replace(STANDALONE_DETACH_KEYWORDS_PATTERN, "$1");
|
|
35449
|
+
}
|
|
35450
|
+
function stripUserMessageDetachKeyword(messageText) {
|
|
35451
|
+
if (!containsStandaloneDetachKeyword(messageText))
|
|
35452
|
+
return messageText;
|
|
35453
|
+
const stripped = stripStandaloneDetachKeywords(messageText).replace(/[ \t]{2,}/g, " ");
|
|
35454
|
+
return stripped.trim() === "" ? EMPTY_DETACH_MESSAGE : stripped;
|
|
35455
|
+
}
|
|
35456
|
+
function shouldDetachBashWaitOnUserMessage(config2, messageText) {
|
|
35457
|
+
return resolveBashConfig(config2).detach_on_user_message || containsStandaloneDetachKeyword(messageText);
|
|
35458
|
+
}
|
|
34975
35459
|
async function sendBashWaitDetach(bridge, sessionID) {
|
|
34976
35460
|
const response = await bridge.send("bash_wait_detach", { session_id: sessionID }, { keepBridgeOnTimeout: true, transportTimeoutMs: BASH_TRANSPORT_TIMEOUT_MS });
|
|
34977
35461
|
if (response.success === false) {
|
|
@@ -35433,8 +35917,16 @@ function formatReadAttachmentText(attachment) {
|
|
|
35433
35917
|
}
|
|
35434
35918
|
return `Read attachment [${mime}]${size ? ` ${size}` : ""}`;
|
|
35435
35919
|
}
|
|
35920
|
+
var ISSUE_AND_PR_READ_DESCRIPTION = "GitHub issues and pull requests can be read with `issue://NUMBER` and `pr://NUMBER` (or `issue://OWNER/REPO/NUMBER` and `pr://OWNER/REPO/NUMBER`).";
|
|
35921
|
+
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.";
|
|
35922
|
+
function readDescription(ghReadEnabled) {
|
|
35923
|
+
return ghReadEnabled ? `${READ_DESCRIPTION} ${ISSUE_AND_PR_READ_DESCRIPTION}` : READ_DESCRIPTION;
|
|
35924
|
+
}
|
|
35925
|
+
function visionCapabilityForPiModel(extCtx) {
|
|
35926
|
+
return Array.isArray(extCtx.model?.input) ? extCtx.model.input.includes("image") : undefined;
|
|
35927
|
+
}
|
|
35436
35928
|
function modelSupportsImages(extCtx) {
|
|
35437
|
-
return
|
|
35929
|
+
return visionCapabilityForPiModel(extCtx) === true;
|
|
35438
35930
|
}
|
|
35439
35931
|
var NON_VISION_IMAGE_NOTE = "[Current model does not support images. The image will be omitted from this request.]";
|
|
35440
35932
|
function containsPath(parent, child) {
|
|
@@ -35652,7 +36144,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
35652
36144
|
pi.registerTool(withPathAliasPreparation({
|
|
35653
36145
|
name: readName,
|
|
35654
36146
|
label: readName,
|
|
35655
|
-
description:
|
|
36147
|
+
description: readDescription(ctx.config.gh_read?.enabled === true),
|
|
35656
36148
|
promptSnippet: "Read file contents (supports offset/limit for large files)",
|
|
35657
36149
|
promptGuidelines: [`Use ${readName} to examine files instead of cat or sed.`],
|
|
35658
36150
|
parameters: ReadParams,
|
|
@@ -35680,6 +36172,9 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
35680
36172
|
rawArgs.offset = offset;
|
|
35681
36173
|
if (limit !== undefined)
|
|
35682
36174
|
rawArgs.limit = limit;
|
|
36175
|
+
const visionCapability = visionCapabilityForPiModel(extCtx);
|
|
36176
|
+
if (visionCapability !== undefined)
|
|
36177
|
+
rawArgs.vision_capability = visionCapability;
|
|
35683
36178
|
const response = await callToolCall(bridge, "read", rawArgs, extCtx);
|
|
35684
36179
|
if (response.success === false) {
|
|
35685
36180
|
throw new Error(response.text || response.message || "read failed");
|
|
@@ -35763,8 +36258,9 @@ PDFs aren't supported on the Pi harness yet.`, response);
|
|
|
35763
36258
|
parameters: HashlineEditParams,
|
|
35764
36259
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
35765
36260
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
36261
|
+
const sessionId = resolveSessionId(extCtx);
|
|
35766
36262
|
const rawArgs = { patch: params.patch };
|
|
35767
|
-
const preflight = await
|
|
36263
|
+
const preflight = await callToolCallForSession(bridge, "hashline_preflight", rawArgs, sessionId, extCtx);
|
|
35768
36264
|
if (preflight.success === false)
|
|
35769
36265
|
throw toolErrorFromResponse("edit", preflight);
|
|
35770
36266
|
for (const target of [
|
|
@@ -35775,10 +36271,12 @@ PDFs aren't supported on the Pi harness yet.`, response);
|
|
|
35775
36271
|
restrictToProjectRoot: surface.restrictToProjectRoot
|
|
35776
36272
|
});
|
|
35777
36273
|
}
|
|
35778
|
-
const preview = await
|
|
36274
|
+
const preview = await callToolCallForSession(bridge, "edit", rawArgs, sessionId, extCtx, {
|
|
36275
|
+
preview: true
|
|
36276
|
+
});
|
|
35779
36277
|
if (preview.success === false)
|
|
35780
36278
|
throw toolErrorFromResponse("edit", preview);
|
|
35781
|
-
const response = await
|
|
36279
|
+
const response = await callToolCallForSession(bridge, "edit", rawArgs, sessionId, extCtx);
|
|
35782
36280
|
if (response.success === false)
|
|
35783
36281
|
throw toolErrorFromResponse("edit", response);
|
|
35784
36282
|
return buildMutationResult(response);
|
|
@@ -36328,7 +36826,7 @@ var BashBaseParams = {
|
|
|
36328
36826
|
description: "Human-readable description shown in UI logs. Helps users understand what the command does without reading shell syntax."
|
|
36329
36827
|
})),
|
|
36330
36828
|
wait: Type4.Optional(Type4.Boolean({
|
|
36331
|
-
description: "When true, run in the foreground without auto-promoting and wait until the command finishes or reaches its timeout;
|
|
36829
|
+
description: "When true, run in the foreground without auto-promoting and wait until the command finishes or reaches its timeout; a new user message detaches by default, while `bash.detach_on_user_message: false` keeps it blocking unless the message contains the literal `&detach`. The token is stripped before delivery; the rest of the message is preserved, and a token-only message becomes `(requested background detach)`. Use only when you know the result is required before doing anything else."
|
|
36332
36830
|
})),
|
|
36333
36831
|
sandbox: Type4.Optional(Type4.Literal("host", {
|
|
36334
36832
|
description: "Request one-command approval to run unsandboxed on the host; use only when native sandboxing blocks required work, and note that it is a no-op when sandboxing is disabled."
|
|
@@ -36423,11 +36921,17 @@ ${ask.command ?? ""}
|
|
|
36423
36921
|
Working directory:
|
|
36424
36922
|
${ask.cwd ?? ""}`;
|
|
36425
36923
|
}
|
|
36426
|
-
|
|
36924
|
+
function piPowerShellAskText(command) {
|
|
36925
|
+
return `PowerShell commands are conservatively approved one at a time because AFT's POSIX shell scanner cannot safely interpret PowerShell syntax.
|
|
36926
|
+
|
|
36927
|
+
Exact command:
|
|
36928
|
+
${command}`;
|
|
36929
|
+
}
|
|
36930
|
+
async function callBashWithPermissionLoop(bridge, params, extCtx, options, bridgeCommand = "bash") {
|
|
36427
36931
|
const granted = Array.isArray(params.permissions_granted) ? params.permissions_granted.filter((value) => typeof value === "string") : [];
|
|
36428
36932
|
for (let round = 0;round < 8; round++) {
|
|
36429
36933
|
try {
|
|
36430
|
-
return await callBashBridge(bridge,
|
|
36934
|
+
return await callBashBridge(bridge, bridgeCommand, { ...params, ...granted.length > 0 ? { permissions_granted: granted } : {} }, extCtx, options);
|
|
36431
36935
|
} catch (error53) {
|
|
36432
36936
|
if (!(error53 instanceof BridgeError)) {
|
|
36433
36937
|
if (error53 instanceof Error && error53.message.includes("permission_required")) {
|
|
@@ -36438,19 +36942,30 @@ async function callBashWithPermissionLoop(bridge, params, extCtx, options) {
|
|
|
36438
36942
|
if (error53.code !== "permission_required")
|
|
36439
36943
|
throw error53;
|
|
36440
36944
|
const asks = Array.isArray(error53.response?.asks) ? error53.response.asks : [];
|
|
36441
|
-
if (asks.length === 0 ||
|
|
36442
|
-
throw new
|
|
36443
|
-
}
|
|
36444
|
-
if (!extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
|
|
36445
|
-
throw new BridgeError("Permission denied: host escalation approval requires an interactive UI.", "permission_denied");
|
|
36945
|
+
if (asks.length === 0 || !extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
|
|
36946
|
+
throw new BridgeError("Permission denied: command approval requires an interactive UI.", "permission_denied");
|
|
36446
36947
|
}
|
|
36447
36948
|
for (const ask of asks) {
|
|
36448
|
-
|
|
36949
|
+
if (ask.kind === "escalation") {
|
|
36950
|
+
const approved2 = await extCtx.ui.confirm("Run command unsandboxed on host?", piEscalationAskText(ask), { signal: extCtx.signal });
|
|
36951
|
+
if (!approved2) {
|
|
36952
|
+
throw new BridgeError("Permission denied: unsandboxed host execution was denied.", "permission_denied");
|
|
36953
|
+
}
|
|
36954
|
+
if (ask.grant_id && !granted.includes(ask.grant_id))
|
|
36955
|
+
granted.push(ask.grant_id);
|
|
36956
|
+
continue;
|
|
36957
|
+
}
|
|
36958
|
+
if (bridgeCommand !== "powershell") {
|
|
36959
|
+
throw new Error("Permission ask reached Pi adapter without a host escalation grant — this is a bug.");
|
|
36960
|
+
}
|
|
36961
|
+
const approved = await extCtx.ui.confirm("Allow PowerShell command?", piPowerShellAskText(String(params.command ?? "")), { signal: extCtx.signal });
|
|
36449
36962
|
if (!approved) {
|
|
36450
|
-
throw new BridgeError("Permission denied:
|
|
36963
|
+
throw new BridgeError("Permission denied: PowerShell command was denied.", "permission_denied");
|
|
36964
|
+
}
|
|
36965
|
+
for (const grant of [...ask.always ?? [], ...ask.patterns ?? []]) {
|
|
36966
|
+
if (!granted.includes(grant))
|
|
36967
|
+
granted.push(grant);
|
|
36451
36968
|
}
|
|
36452
|
-
if (ask.grant_id && !granted.includes(ask.grant_id))
|
|
36453
|
-
granted.push(ask.grant_id);
|
|
36454
36969
|
}
|
|
36455
36970
|
}
|
|
36456
36971
|
}
|
|
@@ -36477,23 +36992,27 @@ function getBashSpawnHook(pi) {
|
|
|
36477
36992
|
}
|
|
36478
36993
|
return api2.hooks?.bashSpawn;
|
|
36479
36994
|
}
|
|
36480
|
-
function registerBashTool(pi, ctx, aftSearchRegistered = false, registeredName = "bash", registerCompanions = true) {
|
|
36481
|
-
const
|
|
36995
|
+
function registerBashTool(pi, ctx, aftSearchRegistered = false, registeredName = "bash", registerCompanions = true, shell = "bash") {
|
|
36996
|
+
const isPowerShell = shell === "powershell";
|
|
36997
|
+
const spawnHook = isPowerShell ? undefined : getBashSpawnHook(pi);
|
|
36482
36998
|
const readToolName = registeredName === "bash" ? "read" : "aft_read";
|
|
36483
36999
|
const grepToolName = registeredName === "bash" ? "grep" : "aft_grep";
|
|
36484
37000
|
const searchSteer = aftSearchRegistered ? `use \`aft_search\` (concepts, identifiers, regex, literals), \`${readToolName}\`, \`aft_outline\`, or \`aft_zoom\` instead` : `use the \`${grepToolName}\` tool, \`${readToolName}\`, \`aft_outline\`, or \`aft_zoom\` instead`;
|
|
36485
37001
|
const bashCfg = resolveBashConfig(ctx.config);
|
|
36486
37002
|
let hostFallbackActive = false;
|
|
36487
37003
|
const compressionSentence = bashCfg.compress ? " Output is compressed by default; pass `compressed: false` for raw output. Piped commands run verbatim and show the pipeline's output; for AFT's test/build summary, run the runner without `| head`, `| tail`, or `| grep`." : "";
|
|
36488
|
-
const
|
|
37004
|
+
const detachSentence = bashCfg.detach_on_user_message ? "A new user message detaches this wait. Set `bash.detach_on_user_message: false` to keep it blocking; even then, a message containing the literal `&detach` forces detachment, and the token is stripped before delivery; the rest of the message is preserved, while a token-only message becomes `(requested background detach)`." : "Because `bash.detach_on_user_message` is false, a new user message leaves this wait blocking; include the literal `&detach` anywhere to force detachment, and the token is stripped before delivery; the rest of the message is preserved, while a token-only message becomes `(requested background detach)`.";
|
|
37005
|
+
const tasksSentence = bashCfg.background ? ` Commands run in the foreground and return inline; \`wait: true\` blocks until a long command finishes instead of auto-promoting; ${detachSentence} Use it when you need the result before doing anything else; keep it off otherwise so auto-promote can remind you while you work. Use \`background: true\` yourself ONLY when you have other useful work to do while it runs; then \`bash_watch\` waits on the task (sync blocks until exit/pattern, async notifies) and \`bash_status\` peeks at it — never background a command and immediately \`bash_watch\` it (that wastes a turn for what foreground returns in one), and never loop \`bash_status\` to wait. \`pty: true\` runs interactive programs (REPLs, TUIs), implies background, and is driven with \`bash_status({ output_mode: "screen" })\` plus \`bash_write\`.` : " Commands run in the foreground to completion; `timeout` is the hard kill cap (default 30 minutes).";
|
|
36489
37006
|
pi.registerTool({
|
|
36490
37007
|
name: registeredName,
|
|
36491
37008
|
label: registeredName,
|
|
36492
|
-
description: `Execute
|
|
37009
|
+
description: isPowerShell ? `Execute PowerShell commands through AFT.${compressionSentence}${tasksSentence}
|
|
37010
|
+
|
|
37011
|
+
PowerShell syntax is not analyzed as POSIX shell. Each command requires explicit approval so syntax AFT cannot safely interpret is never auto-allowed.` : `Execute shell commands.${compressionSentence}${tasksSentence}
|
|
36493
37012
|
|
|
36494
37013
|
DO NOT use bash for code search or code exploration. If you are about to run grep, rg, sed, awk, find, or cat through bash to locate or read code: STOP — ${searchSteer}.`,
|
|
36495
|
-
promptSnippet: bashCfg.background ? "Run shell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : "Run shell commands (timeout in milliseconds; supports workdir and compressed output)",
|
|
36496
|
-
promptGuidelines: [
|
|
37014
|
+
promptSnippet: isPowerShell ? "Run PowerShell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : bashCfg.background ? "Run shell commands (timeout in milliseconds; supports workdir, background tasks, compressed output, PTY mode)" : "Run shell commands (timeout in milliseconds; supports workdir and compressed output)",
|
|
37015
|
+
promptGuidelines: isPowerShell ? ["Use PowerShell syntax. Every command requires explicit approval."] : [
|
|
36497
37016
|
`DO NOT use bash for code search or exploration — ${searchSteer}.`,
|
|
36498
37017
|
"Set compressed: false when you need ANSI color codes in the output.",
|
|
36499
37018
|
"Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
|
|
@@ -36552,7 +37071,8 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36552
37071
|
foreground_orchestrate: true,
|
|
36553
37072
|
block_to_completion: blockToCompletion,
|
|
36554
37073
|
wait: requestedWait,
|
|
36555
|
-
sandbox: params.sandbox
|
|
37074
|
+
sandbox: params.sandbox,
|
|
37075
|
+
...isPowerShell ? { shell: "powershell" } : {}
|
|
36556
37076
|
}, extCtx, {
|
|
36557
37077
|
transportTimeoutMs: orchestratedTransportTimeoutMs(blockToCompletion, requestedWait, effectiveTimeout, foregroundWaitMs),
|
|
36558
37078
|
onProgress: ({ text }) => {
|
|
@@ -36560,9 +37080,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36560
37080
|
const displayText = truncateToVisualLines(streamed, 100);
|
|
36561
37081
|
onUpdate?.(bashResult(displayText, { streaming: true }));
|
|
36562
37082
|
}
|
|
36563
|
-
});
|
|
37083
|
+
}, isPowerShell ? "powershell" : "bash");
|
|
36564
37084
|
} catch (error53) {
|
|
36565
|
-
if (!bashCfg2.host_fallback || !isBashTransportDeadError(error53))
|
|
37085
|
+
if (isPowerShell || !bashCfg2.host_fallback || !isBashTransportDeadError(error53))
|
|
36566
37086
|
throw error53;
|
|
36567
37087
|
if (rawRequestedBackground) {
|
|
36568
37088
|
throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
|
|
@@ -36609,7 +37129,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36609
37129
|
task_id: taskId
|
|
36610
37130
|
};
|
|
36611
37131
|
const output = response.output ?? "";
|
|
36612
|
-
return bashResult(usedHostFallback ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
37132
|
+
return bashResult(usedHostFallback || isPowerShell ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
36613
37133
|
},
|
|
36614
37134
|
renderCall(args, theme, context) {
|
|
36615
37135
|
return renderBashCall(args?.command, args?.description, theme, context);
|
|
@@ -37622,25 +38142,39 @@ function formatPhase(entry) {
|
|
|
37622
38142
|
return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
|
|
37623
38143
|
}
|
|
37624
38144
|
function renderInspectTerminal(terminal, serverText) {
|
|
37625
|
-
const lines = [terminal.kind];
|
|
37626
38145
|
if (terminal.kind === "FRESH") {
|
|
37627
|
-
lines
|
|
38146
|
+
const lines = [
|
|
38147
|
+
terminal.kind,
|
|
38148
|
+
`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`
|
|
38149
|
+
];
|
|
38150
|
+
lines.push(terminal.phases.length > 0 ? `completed phases:
|
|
38151
|
+
${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
|
|
38152
|
+
`)}` : "completed phases: none");
|
|
38153
|
+
if (serverText?.trim())
|
|
38154
|
+
lines.push(serverText);
|
|
38155
|
+
return lines.join(`
|
|
38156
|
+
`);
|
|
37628
38157
|
}
|
|
37629
38158
|
if (terminal.kind === "PHASE-FAILED") {
|
|
37630
|
-
|
|
37631
|
-
|
|
37632
|
-
|
|
37633
|
-
|
|
37634
|
-
|
|
38159
|
+
const detail = compactTerminalField(terminal.failureDetail, "not supplied");
|
|
38160
|
+
const reason = compactTerminalField(terminal.failureReason, "not supplied");
|
|
38161
|
+
return [
|
|
38162
|
+
`inspect could not complete: ${detail} (${reason}).`,
|
|
38163
|
+
`Completed phases: ${terminal.phases.length}. Retry, or narrow with sections=...`
|
|
38164
|
+
].join(`
|
|
38165
|
+
`);
|
|
37635
38166
|
}
|
|
37636
|
-
|
|
37637
|
-
|
|
37638
|
-
`
|
|
37639
|
-
|
|
37640
|
-
|
|
37641
|
-
return lines.join(`
|
|
38167
|
+
const phaseLabel = terminal.phases.length === 1 ? "phase" : "phases";
|
|
38168
|
+
return [
|
|
38169
|
+
`inspect was interrupted before it could complete (after ${terminal.phases.length} completed ${phaseLabel}); no fresh snapshot was produced.`,
|
|
38170
|
+
"Retry is safe; retry inspect, or narrow with sections=..."
|
|
38171
|
+
].join(`
|
|
37642
38172
|
`);
|
|
37643
38173
|
}
|
|
38174
|
+
function compactTerminalField(value, fallback) {
|
|
38175
|
+
const compact = value?.trim().replace(/\s+/g, " ");
|
|
38176
|
+
return compact || fallback;
|
|
38177
|
+
}
|
|
37644
38178
|
function diagnosticsSummaryPart(summary) {
|
|
37645
38179
|
const section = asRecord3(summary?.diagnostics);
|
|
37646
38180
|
if (!section)
|
|
@@ -37762,9 +38296,19 @@ function renderInspectCall(args, theme, context) {
|
|
|
37762
38296
|
function renderInspectResult(result, theme, context, options = { expanded: true }) {
|
|
37763
38297
|
const payload = extractStructuredPayload(result);
|
|
37764
38298
|
const terminal = parseInspectTerminal(payload);
|
|
38299
|
+
if (terminal) {
|
|
38300
|
+
const sections2 = [renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))];
|
|
38301
|
+
return collapsibleResult({
|
|
38302
|
+
summary: sections2[0]?.split(`
|
|
38303
|
+
`)[0] ?? "inspect",
|
|
38304
|
+
full: renderSections(sections2, context),
|
|
38305
|
+
expanded: options.expanded,
|
|
38306
|
+
context
|
|
38307
|
+
});
|
|
38308
|
+
}
|
|
37765
38309
|
if (context.isError)
|
|
37766
38310
|
return renderErrorResult(result, "inspect failed", theme, context);
|
|
37767
|
-
const sections =
|
|
38311
|
+
const sections = buildInspectSections(payload, theme);
|
|
37768
38312
|
return collapsibleResult({
|
|
37769
38313
|
summary: sections[0] ?? "inspect completed",
|
|
37770
38314
|
full: renderSections(sections, context),
|
|
@@ -38429,7 +38973,7 @@ var SafetyParams = Type12.Object({
|
|
|
38429
38973
|
})),
|
|
38430
38974
|
name: Type12.Optional(Type12.String({ description: "Checkpoint name (required for checkpoint, restore)" })),
|
|
38431
38975
|
files: Type12.Optional(Type12.Array(Type12.String(), {
|
|
38432
|
-
description: "Specific files for checkpoint (optional, defaults to all tracked)"
|
|
38976
|
+
description: "Specific files for checkpoint (optional, defaults to all backup-tracked files; explicit files may be untracked or gitignored)"
|
|
38433
38977
|
}))
|
|
38434
38978
|
});
|
|
38435
38979
|
function buildSafetySections(args, payload, theme) {
|
|
@@ -38474,14 +39018,16 @@ function buildSafetySections(args, payload, theme) {
|
|
|
38474
39018
|
`${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}`,
|
|
38475
39019
|
skipped.length > 0 ? `${theme.fg("warning", "skipped")}
|
|
38476
39020
|
${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)")}: ${asString2(entry.error) ?? "unknown error"}`).join(`
|
|
38477
|
-
`)}` : theme.fg("muted", "No skipped files.")
|
|
38478
|
-
|
|
39021
|
+
`)}` : theme.fg("muted", "No skipped files."),
|
|
39022
|
+
asString2(response.durability)
|
|
39023
|
+
].filter((section) => Boolean(section));
|
|
38479
39024
|
}
|
|
38480
39025
|
if (args.op === "restore") {
|
|
38481
39026
|
return [
|
|
38482
39027
|
`${theme.fg("success", "checkpoint restored")} ${theme.fg("accent", asString2(response.name) ?? args.name ?? "(checkpoint)")}`,
|
|
38483
|
-
`${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}
|
|
38484
|
-
|
|
39028
|
+
`${theme.fg("muted", "files")} ${asNumber2(response.file_count) ?? 0}`,
|
|
39029
|
+
asString2(response.durability)
|
|
39030
|
+
].filter((section) => Boolean(section));
|
|
38485
39031
|
}
|
|
38486
39032
|
const checkpoints = asRecords2(response.checkpoints);
|
|
38487
39033
|
const sections = [
|
|
@@ -38489,6 +39035,9 @@ ${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)"
|
|
|
38489
39035
|
];
|
|
38490
39036
|
if (checkpoints.length === 0) {
|
|
38491
39037
|
sections.push(theme.fg("muted", "No checkpoints saved."));
|
|
39038
|
+
const durability2 = asString2(response.durability);
|
|
39039
|
+
if (durability2)
|
|
39040
|
+
sections.push(theme.fg("muted", durability2));
|
|
38492
39041
|
return sections;
|
|
38493
39042
|
}
|
|
38494
39043
|
sections.push(checkpoints.map((checkpoint, index) => {
|
|
@@ -38498,6 +39047,9 @@ ${skipped.map((entry) => ` ↳ ${shortenPath2(asString2(entry.file) ?? "(file)"
|
|
|
38498
39047
|
return `${index + 1}. ${name} ${theme.fg("muted", `${count} file${count === 1 ? "" : "s"} · ${created}`)}`;
|
|
38499
39048
|
}).join(`
|
|
38500
39049
|
`));
|
|
39050
|
+
const durability = asString2(response.durability);
|
|
39051
|
+
if (durability)
|
|
39052
|
+
sections.push(theme.fg("muted", durability));
|
|
38501
39053
|
return sections;
|
|
38502
39054
|
}
|
|
38503
39055
|
function renderSafetyCall(args, theme, context) {
|
|
@@ -38718,7 +39270,7 @@ function registerSemanticTool(pi, ctx) {
|
|
|
38718
39270
|
].join(`
|
|
38719
39271
|
`),
|
|
38720
39272
|
parameters: SearchParams2,
|
|
38721
|
-
async execute(_toolCallId, params,
|
|
39273
|
+
async execute(_toolCallId, params, signal, _onUpdate, extCtx) {
|
|
38722
39274
|
if (isEmptyParam(params.query) || typeof params.query !== "string" || params.query.trim().length === 0) {
|
|
38723
39275
|
throw new Error("semantic_search: invalid params: `query` must be a non-empty string");
|
|
38724
39276
|
}
|
|
@@ -38730,7 +39282,7 @@ function registerSemanticTool(pi, ctx) {
|
|
|
38730
39282
|
req.includeTests = params.includeTests;
|
|
38731
39283
|
if (params.path !== undefined)
|
|
38732
39284
|
req.path = params.path;
|
|
38733
|
-
const response = await callToolCall(bridge, "search", req, extCtx);
|
|
39285
|
+
const response = await callToolCall(bridge, "search", req, extCtx, signal ? { abortSignal: signal } : undefined);
|
|
38734
39286
|
if (response.success === false) {
|
|
38735
39287
|
throw new Error(response.text || response.message || "search failed");
|
|
38736
39288
|
}
|
|
@@ -38747,7 +39299,25 @@ function registerSemanticTool(pi, ctx) {
|
|
|
38747
39299
|
|
|
38748
39300
|
// src/tool-registration.ts
|
|
38749
39301
|
var ALL_ONLY_TOOLS = new Set(["aft_callgraph", "aft_delete", "aft_move", "aft_refactor"]);
|
|
38750
|
-
function
|
|
39302
|
+
function resolvePiPowerShellFallback(config2) {
|
|
39303
|
+
return resolveBashConfig(config2).powershell_tool;
|
|
39304
|
+
}
|
|
39305
|
+
function piPowerShellEnabledFromHost(pi) {
|
|
39306
|
+
const api2 = pi;
|
|
39307
|
+
if (typeof api2.getActiveTools !== "function" || typeof api2.getAllTools !== "function") {
|
|
39308
|
+
return;
|
|
39309
|
+
}
|
|
39310
|
+
try {
|
|
39311
|
+
const tool = api2.getAllTools().find((candidate) => candidate.name === "powershell");
|
|
39312
|
+
const source = tool?.sourceInfo?.source ?? tool?.source;
|
|
39313
|
+
if (!tool || source === undefined)
|
|
39314
|
+
return;
|
|
39315
|
+
return source === "builtin" && api2.getActiveTools().some((active) => (typeof active === "string" ? active : active.name) === "powershell");
|
|
39316
|
+
} catch {
|
|
39317
|
+
return;
|
|
39318
|
+
}
|
|
39319
|
+
}
|
|
39320
|
+
function resolvePiToolSurface(config2, pi) {
|
|
38751
39321
|
const surface = config2.tool_surface ?? "recommended";
|
|
38752
39322
|
const disabled = new Set(config2.disabled_tools ?? []);
|
|
38753
39323
|
const hoistBuiltinTools = config2.hoist_builtin_tools !== false;
|
|
@@ -38755,10 +39325,12 @@ function resolvePiToolSurface(config2) {
|
|
|
38755
39325
|
const builtinToolEnabled = (bareName) => ok(hoistBuiltinTools ? bareName : `aft_${bareName}`);
|
|
38756
39326
|
const allOnly = (name) => ALL_ONLY_TOOLS.has(name) && ok(name);
|
|
38757
39327
|
const restrictToProjectRoot = config2.restrict_to_project_root ?? false;
|
|
39328
|
+
const powershellEnabled = (pi ? piPowerShellEnabledFromHost(pi) : undefined) ?? resolvePiPowerShellFallback(config2);
|
|
38758
39329
|
if (surface === "minimal") {
|
|
38759
39330
|
return {
|
|
38760
39331
|
hoistBuiltinTools,
|
|
38761
39332
|
hoistBash: builtinToolEnabled("bash"),
|
|
39333
|
+
hoistPowershell: powershellEnabled && builtinToolEnabled("powershell"),
|
|
38762
39334
|
hoistRead: false,
|
|
38763
39335
|
hoistWrite: false,
|
|
38764
39336
|
hoistEdit: false,
|
|
@@ -38782,6 +39354,7 @@ function resolvePiToolSurface(config2) {
|
|
|
38782
39354
|
const base = {
|
|
38783
39355
|
hoistBuiltinTools,
|
|
38784
39356
|
hoistBash: builtinToolEnabled("bash"),
|
|
39357
|
+
hoistPowershell: powershellEnabled && builtinToolEnabled("powershell"),
|
|
38785
39358
|
hoistRead: builtinToolEnabled("read"),
|
|
38786
39359
|
hoistWrite: builtinToolEnabled("write"),
|
|
38787
39360
|
hoistEdit: builtinToolEnabled("edit"),
|
|
@@ -38813,14 +39386,20 @@ function resolvePiToolSurface(config2) {
|
|
|
38813
39386
|
return base;
|
|
38814
39387
|
}
|
|
38815
39388
|
function registerPiToolSurface(pi, ctx, surface) {
|
|
38816
|
-
|
|
39389
|
+
const bashCfg = resolveBashConfig(ctx.config);
|
|
39390
|
+
const bashRegistered = surface.hoistBash && bashCfg.enabled;
|
|
39391
|
+
const powershellRegistered = surface.hoistPowershell && bashCfg.enabled;
|
|
39392
|
+
if (bashRegistered) {
|
|
38817
39393
|
registerBashTool(pi, ctx, surface.semantic, surface.hoistBuiltinTools ? "bash" : "aft_bash", false);
|
|
38818
|
-
registerBashCompanionTools(pi, ctx);
|
|
38819
39394
|
}
|
|
39395
|
+
if (powershellRegistered) {
|
|
39396
|
+
registerBashTool(pi, ctx, surface.semantic, surface.hoistBuiltinTools ? "powershell" : "aft_powershell", false, "powershell");
|
|
39397
|
+
}
|
|
39398
|
+
if (bashRegistered || powershellRegistered)
|
|
39399
|
+
registerBashCompanionTools(pi, ctx);
|
|
38820
39400
|
registerHoistedTools(pi, ctx, surface);
|
|
38821
|
-
if (surface.outline || surface.zoom)
|
|
39401
|
+
if (surface.outline || surface.zoom)
|
|
38822
39402
|
registerReadingTools(pi, ctx, surface);
|
|
38823
|
-
}
|
|
38824
39403
|
if (surface.semantic)
|
|
38825
39404
|
registerSemanticTool(pi, ctx);
|
|
38826
39405
|
if (surface.inspect)
|
|
@@ -39003,7 +39582,7 @@ var PLUGIN_VERSION = (() => {
|
|
|
39003
39582
|
return "0.0.0";
|
|
39004
39583
|
}
|
|
39005
39584
|
})();
|
|
39006
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
39585
|
+
var ANNOUNCEMENT_VERSION = "0.55.0";
|
|
39007
39586
|
var ANNOUNCEMENT_FEATURES = [
|
|
39008
39587
|
"Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
|
|
39009
39588
|
"aft_zoom handles real-world .jsonc: files with comment banners above the opening brace now resolve, and not-found errors point at the segment that actually failed (thanks @iceteaSA).",
|
|
@@ -39322,7 +39901,7 @@ ${lines}
|
|
|
39322
39901
|
});
|
|
39323
39902
|
}
|
|
39324
39903
|
pool.setConfigureOverride("harness", "pi");
|
|
39325
|
-
const surface = resolvePiToolSurface(config2);
|
|
39904
|
+
const surface = resolvePiToolSurface(config2, pi);
|
|
39326
39905
|
const hashlineEditRegistered = config2.edit_mode === "hashline" && surface.hoistEdit;
|
|
39327
39906
|
pool.setConfigureOverride("edit_slot_survives", hashlineEditRegistered);
|
|
39328
39907
|
pool.setConfigureOverride("aft_search_registered", surface.semantic);
|
|
@@ -39370,6 +39949,17 @@ ${lines}
|
|
|
39370
39949
|
sendFeatureAnnouncement(ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, storageDir);
|
|
39371
39950
|
}
|
|
39372
39951
|
registerPiToolSurface(pi, ctx, surface);
|
|
39952
|
+
let powershellRegistered = surface.hoistPowershell && resolveBashConfig(config2).enabled;
|
|
39953
|
+
pi.on("session_start", () => {
|
|
39954
|
+
if (powershellRegistered)
|
|
39955
|
+
return;
|
|
39956
|
+
const liveSurface = resolvePiToolSurface(config2, pi);
|
|
39957
|
+
if (!liveSurface.hoistPowershell || !resolveBashConfig(config2).enabled)
|
|
39958
|
+
return;
|
|
39959
|
+
registerBashTool(pi, ctx, liveSurface.semantic, liveSurface.hoistBuiltinTools ? "powershell" : "aft_powershell", false, "powershell");
|
|
39960
|
+
registerBashCompanionTools(pi, ctx);
|
|
39961
|
+
powershellRegistered = true;
|
|
39962
|
+
});
|
|
39373
39963
|
registerWorkflowHints(pi, config2, surface);
|
|
39374
39964
|
registerStatusCommand(pi, ctx);
|
|
39375
39965
|
pi.on("tool_result", async (event, extCtx) => {
|
|
@@ -39401,10 +39991,18 @@ ${lines}
|
|
|
39401
39991
|
});
|
|
39402
39992
|
}
|
|
39403
39993
|
});
|
|
39404
|
-
pi.on("input", (
|
|
39994
|
+
pi.on("input", (event, extCtx) => {
|
|
39405
39995
|
const sessionId = resolveSessionId(extCtx);
|
|
39406
39996
|
signalSyncWatchAbort(sessionId);
|
|
39407
|
-
|
|
39997
|
+
const originalText = event.text;
|
|
39998
|
+
const transformedText = stripUserMessageDetachKeyword(originalText);
|
|
39999
|
+
const shouldDetach = shouldDetachBashWaitOnUserMessage(config2, originalText);
|
|
40000
|
+
if (shouldDetach) {
|
|
40001
|
+
signalBashWaitDetachForProject(pool, extCtx.cwd, sessionId);
|
|
40002
|
+
}
|
|
40003
|
+
if (transformedText !== originalText) {
|
|
40004
|
+
return { action: "transform", text: transformedText };
|
|
40005
|
+
}
|
|
39408
40006
|
});
|
|
39409
40007
|
const unregisterShutdownCleanup = registerShutdownCleanup(async () => {
|
|
39410
40008
|
try {
|