@cortexkit/aft-pi 0.39.3 → 0.40.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/config.d.ts +12 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1087 -1096
- package/dist/lsp-cache.d.ts +3 -3
- package/dist/lsp-github-install.d.ts +5 -5
- package/dist/lsp-github-install.d.ts.map +1 -1
- package/dist/lsp-github-probe.d.ts +1 -1
- package/dist/lsp-github-probe.d.ts.map +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.d.ts.map +1 -1
- package/dist/tools/ast.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/fs.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts +11 -5
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/inspect.d.ts.map +1 -1
- package/dist/tools/reading.d.ts.map +1 -1
- package/dist/tools/semantic.d.ts +1 -0
- package/dist/tools/semantic.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-hints.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -11675,11 +11675,6 @@ function error(message, meta) {
|
|
|
11675
11675
|
}
|
|
11676
11676
|
}
|
|
11677
11677
|
// ../aft-bridge/dist/bash-format.js
|
|
11678
|
-
function appendPipeStripNote(output, note) {
|
|
11679
|
-
return note ? `${output}
|
|
11680
|
-
|
|
11681
|
-
${note}` : output;
|
|
11682
|
-
}
|
|
11683
11678
|
function formatSeconds(ms) {
|
|
11684
11679
|
return `${Number((ms / 1000).toFixed(1))}s`;
|
|
11685
11680
|
}
|
|
@@ -11757,12 +11752,16 @@ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered, project
|
|
|
11757
11752
|
${hint}`;
|
|
11758
11753
|
}
|
|
11759
11754
|
function shouldSuppressGrepSearchHint(command, projectRoot) {
|
|
11760
|
-
const root = projectRoot?.trim();
|
|
11761
|
-
if (!root)
|
|
11762
|
-
return false;
|
|
11763
11755
|
const statements = splitTopLevelStatements(command);
|
|
11764
11756
|
if (statements === null)
|
|
11765
11757
|
return false;
|
|
11758
|
+
if (allSearchPathOperandsAreDynamic(statements))
|
|
11759
|
+
return true;
|
|
11760
|
+
const root = projectRoot?.trim();
|
|
11761
|
+
if (!root)
|
|
11762
|
+
return false;
|
|
11763
|
+
const resolvedRoot = path.resolve(root);
|
|
11764
|
+
let effectiveCwd = resolvedRoot;
|
|
11766
11765
|
let sawCodeSearchStatement = false;
|
|
11767
11766
|
for (const statement of statements) {
|
|
11768
11767
|
const firstStage = firstPipelineStage(statement);
|
|
@@ -11771,19 +11770,84 @@ function shouldSuppressGrepSearchHint(command, projectRoot) {
|
|
|
11771
11770
|
const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
|
|
11772
11771
|
if (firstToken === null)
|
|
11773
11772
|
continue;
|
|
11774
|
-
|
|
11773
|
+
const head = firstToken.token;
|
|
11774
|
+
if (head === "cd") {
|
|
11775
|
+
effectiveCwd = nextCwdAfterCd(effectiveCwd, firstStage, firstToken.end);
|
|
11776
|
+
continue;
|
|
11777
|
+
}
|
|
11778
|
+
if (head !== "grep" && head !== "rg")
|
|
11775
11779
|
continue;
|
|
11776
11780
|
sawCodeSearchStatement = true;
|
|
11781
|
+
if (effectiveCwd === null)
|
|
11782
|
+
continue;
|
|
11783
|
+
if (!isDirInsideProject(resolvedRoot, effectiveCwd))
|
|
11784
|
+
continue;
|
|
11777
11785
|
const operands = collectPathOperands(firstStage, firstToken.end);
|
|
11778
11786
|
if (operands.length === 0)
|
|
11779
11787
|
return false;
|
|
11780
11788
|
for (const operand of operands) {
|
|
11781
|
-
if (
|
|
11789
|
+
if (isDynamicPathOperand(operand))
|
|
11790
|
+
continue;
|
|
11791
|
+
if (isPathInsideProject(resolvedRoot, effectiveCwd, operand))
|
|
11782
11792
|
return false;
|
|
11783
11793
|
}
|
|
11784
11794
|
}
|
|
11785
11795
|
return sawCodeSearchStatement;
|
|
11786
11796
|
}
|
|
11797
|
+
function allSearchPathOperandsAreDynamic(statements) {
|
|
11798
|
+
let sawDynamicOnlySearch = false;
|
|
11799
|
+
for (const statement of statements) {
|
|
11800
|
+
const firstStage = firstPipelineStage(statement);
|
|
11801
|
+
if (firstStage === null)
|
|
11802
|
+
continue;
|
|
11803
|
+
const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
|
|
11804
|
+
if (firstToken === null)
|
|
11805
|
+
continue;
|
|
11806
|
+
const head = firstToken.token;
|
|
11807
|
+
if (head !== "grep" && head !== "rg")
|
|
11808
|
+
continue;
|
|
11809
|
+
const operands = collectPathOperands(firstStage, firstToken.end);
|
|
11810
|
+
if (operands.length === 0)
|
|
11811
|
+
return false;
|
|
11812
|
+
if (operands.some((operand) => !isDynamicPathOperand(operand)))
|
|
11813
|
+
return false;
|
|
11814
|
+
sawDynamicOnlySearch = true;
|
|
11815
|
+
}
|
|
11816
|
+
return sawDynamicOnlySearch;
|
|
11817
|
+
}
|
|
11818
|
+
function nextCwdAfterCd(currentCwd, firstStage, afterCd) {
|
|
11819
|
+
let index = skipSpaces(firstStage, afterCd);
|
|
11820
|
+
let target = null;
|
|
11821
|
+
while (index < firstStage.length) {
|
|
11822
|
+
const tokenResult = readShellToken(firstStage, index);
|
|
11823
|
+
if (tokenResult === null)
|
|
11824
|
+
break;
|
|
11825
|
+
const { token, end } = tokenResult;
|
|
11826
|
+
if (end <= index)
|
|
11827
|
+
break;
|
|
11828
|
+
index = skipSpaces(firstStage, end);
|
|
11829
|
+
if (token === "-")
|
|
11830
|
+
return null;
|
|
11831
|
+
if (token.length > 1 && token.startsWith("-"))
|
|
11832
|
+
continue;
|
|
11833
|
+
target = token;
|
|
11834
|
+
break;
|
|
11835
|
+
}
|
|
11836
|
+
if (target === null)
|
|
11837
|
+
return path.resolve(os.homedir());
|
|
11838
|
+
if (target.includes("$") || target.includes("`"))
|
|
11839
|
+
return null;
|
|
11840
|
+
const expanded = expandTilde(target);
|
|
11841
|
+
if (path.isAbsolute(expanded))
|
|
11842
|
+
return path.resolve(expanded);
|
|
11843
|
+
if (currentCwd === null)
|
|
11844
|
+
return null;
|
|
11845
|
+
return path.resolve(currentCwd, expanded);
|
|
11846
|
+
}
|
|
11847
|
+
function isDirInsideProject(resolvedRoot, dir) {
|
|
11848
|
+
const rel = path.relative(resolvedRoot, path.resolve(dir));
|
|
11849
|
+
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
11850
|
+
}
|
|
11787
11851
|
function collectPathOperands(firstStage, startAfterCommand) {
|
|
11788
11852
|
const operands = [];
|
|
11789
11853
|
let index = skipSpaces(firstStage, startAfterCommand);
|
|
@@ -11805,6 +11869,9 @@ function collectPathOperands(firstStage, startAfterCommand) {
|
|
|
11805
11869
|
function looksLikePathOperand(token) {
|
|
11806
11870
|
return token.includes("/") || token.startsWith("~") || token.startsWith("./") || token.startsWith("../");
|
|
11807
11871
|
}
|
|
11872
|
+
function isDynamicPathOperand(token) {
|
|
11873
|
+
return token.startsWith("~") || token.includes("$") || token.includes("`");
|
|
11874
|
+
}
|
|
11808
11875
|
function expandTilde(target) {
|
|
11809
11876
|
if (!target.startsWith("~"))
|
|
11810
11877
|
return target;
|
|
@@ -11817,10 +11884,9 @@ function resolvePathOperand(projectRoot, operand) {
|
|
|
11817
11884
|
const expanded = expandTilde(operand);
|
|
11818
11885
|
return path.isAbsolute(expanded) ? path.resolve(expanded) : path.resolve(projectRoot, expanded);
|
|
11819
11886
|
}
|
|
11820
|
-
function isPathInsideProject(
|
|
11821
|
-
const
|
|
11822
|
-
const
|
|
11823
|
-
const rel = path.relative(root, resolved);
|
|
11887
|
+
function isPathInsideProject(resolvedRoot, baseCwd, operand) {
|
|
11888
|
+
const resolved = resolvePathOperand(baseCwd, operand);
|
|
11889
|
+
const rel = path.relative(resolvedRoot, resolved);
|
|
11824
11890
|
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
11825
11891
|
}
|
|
11826
11892
|
function splitTopLevelStatements(command) {
|
|
@@ -12013,6 +12079,7 @@ var LONG_RUNNING_COMMAND_TIMEOUT_MS = {
|
|
|
12013
12079
|
trace_to_symbol: 60000,
|
|
12014
12080
|
trace_data: 60000,
|
|
12015
12081
|
impact: 60000,
|
|
12082
|
+
inspect: 60000,
|
|
12016
12083
|
grep: 60000,
|
|
12017
12084
|
glob: 60000,
|
|
12018
12085
|
semantic_search: 60000
|
|
@@ -12071,7 +12138,6 @@ function formatStatusBar(counts) {
|
|
|
12071
12138
|
// ../aft-bridge/dist/bridge.js
|
|
12072
12139
|
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
|
|
12073
12140
|
var BRIDGE_HANG_TIMEOUT_THRESHOLD = 2;
|
|
12074
|
-
var SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000;
|
|
12075
12141
|
var MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
|
|
12076
12142
|
var STDOUT_BUFFER_COMPACT_THRESHOLD = 64 * 1024;
|
|
12077
12143
|
var TERMINAL_BASH_STATUSES = new Set([
|
|
@@ -12144,28 +12210,19 @@ function compareSemver(a, b) {
|
|
|
12144
12210
|
}
|
|
12145
12211
|
return 0;
|
|
12146
12212
|
}
|
|
12147
|
-
function
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
const maxSemanticTimeoutMs = semanticTransportBudgetMs > SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS ? semanticTransportBudgetMs - SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS : Math.max(1, semanticTransportBudgetMs - 1);
|
|
12158
|
-
if (timeoutMs <= maxSemanticTimeoutMs) {
|
|
12159
|
-
return configOverrides;
|
|
12160
|
-
}
|
|
12161
|
-
warn(`semantic.timeout_ms=${timeoutMs} exceeds the semantic transport budget; clamping to ${maxSemanticTimeoutMs}ms (budget: ${semanticTransportBudgetMs}ms)`);
|
|
12162
|
-
return {
|
|
12163
|
-
...configOverrides,
|
|
12164
|
-
semantic: {
|
|
12165
|
-
...semantic,
|
|
12166
|
-
timeout_ms: maxSemanticTimeoutMs
|
|
12213
|
+
function coerceConfigureDroppedKeys(value) {
|
|
12214
|
+
if (!Array.isArray(value))
|
|
12215
|
+
return [];
|
|
12216
|
+
const dropped = [];
|
|
12217
|
+
for (const item of value) {
|
|
12218
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
12219
|
+
continue;
|
|
12220
|
+
const record = item;
|
|
12221
|
+
if (typeof record.key === "string" && typeof record.tier === "string" && typeof record.reason === "string") {
|
|
12222
|
+
dropped.push({ key: record.key, tier: record.tier, reason: record.reason });
|
|
12167
12223
|
}
|
|
12168
|
-
}
|
|
12224
|
+
}
|
|
12225
|
+
return dropped;
|
|
12169
12226
|
}
|
|
12170
12227
|
|
|
12171
12228
|
class BridgeReplacedDuringVersionCheck extends Error {
|
|
@@ -12177,6 +12234,21 @@ class BridgeReplacedDuringVersionCheck extends Error {
|
|
|
12177
12234
|
}
|
|
12178
12235
|
}
|
|
12179
12236
|
|
|
12237
|
+
class BridgeTransportTimeoutError extends Error {
|
|
12238
|
+
command;
|
|
12239
|
+
timeoutMs;
|
|
12240
|
+
code = "transport_timeout";
|
|
12241
|
+
constructor(command, timeoutMs, message) {
|
|
12242
|
+
super(message);
|
|
12243
|
+
this.command = command;
|
|
12244
|
+
this.timeoutMs = timeoutMs;
|
|
12245
|
+
this.name = "BridgeTransportTimeoutError";
|
|
12246
|
+
}
|
|
12247
|
+
}
|
|
12248
|
+
function isBridgeTransportTimeout(err) {
|
|
12249
|
+
return err instanceof Error && err.code === "transport_timeout";
|
|
12250
|
+
}
|
|
12251
|
+
|
|
12180
12252
|
class BinaryBridge {
|
|
12181
12253
|
static RESTART_RESET_MS = 5 * 60 * 1000;
|
|
12182
12254
|
static STDERR_TAIL_MAX = 20;
|
|
@@ -12220,7 +12292,7 @@ class BinaryBridge {
|
|
|
12220
12292
|
this.timeoutMs = options?.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS;
|
|
12221
12293
|
this.hangThreshold = options?.hangThreshold ?? BRIDGE_HANG_TIMEOUT_THRESHOLD;
|
|
12222
12294
|
this.maxRestarts = options?.maxRestarts ?? 3;
|
|
12223
|
-
this.configOverrides =
|
|
12295
|
+
this.configOverrides = configOverrides ?? {};
|
|
12224
12296
|
this.minVersion = options?.minVersion;
|
|
12225
12297
|
this.onVersionMismatch = options?.onVersionMismatch;
|
|
12226
12298
|
this.onConfigureWarnings = options?.onConfigureWarnings;
|
|
@@ -12404,7 +12476,7 @@ class BinaryBridge {
|
|
|
12404
12476
|
} else {
|
|
12405
12477
|
this.warnVia(timeoutMsg2);
|
|
12406
12478
|
}
|
|
12407
|
-
entry.reject(new
|
|
12479
|
+
entry.reject(new BridgeTransportTimeoutError(command, effectiveTimeoutMs, `${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
|
|
12408
12480
|
return;
|
|
12409
12481
|
}
|
|
12410
12482
|
const childActiveSinceRequest = this.lastChildActivityAt > requestSentAt;
|
|
@@ -12457,18 +12529,24 @@ class BinaryBridge {
|
|
|
12457
12529
|
}
|
|
12458
12530
|
}
|
|
12459
12531
|
async deliverConfigureWarnings(configResult, params, options) {
|
|
12460
|
-
if (!this.onConfigureWarnings
|
|
12532
|
+
if (!this.onConfigureWarnings)
|
|
12461
12533
|
return;
|
|
12462
|
-
|
|
12534
|
+
const warnings = Array.isArray(configResult.warnings) ? configResult.warnings : [];
|
|
12535
|
+
const configDroppedKeys = coerceConfigureDroppedKeys(configResult.config_dropped_keys);
|
|
12536
|
+
if (warnings.length === 0 && configDroppedKeys.length === 0)
|
|
12463
12537
|
return;
|
|
12464
12538
|
const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
|
|
12539
|
+
const context = {
|
|
12540
|
+
projectRoot: this.cwd,
|
|
12541
|
+
sessionId,
|
|
12542
|
+
client: options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined),
|
|
12543
|
+
warnings
|
|
12544
|
+
};
|
|
12545
|
+
if (configDroppedKeys.length > 0) {
|
|
12546
|
+
context.configDroppedKeys = configDroppedKeys;
|
|
12547
|
+
}
|
|
12465
12548
|
try {
|
|
12466
|
-
await this.onConfigureWarnings(
|
|
12467
|
-
projectRoot: this.cwd,
|
|
12468
|
-
sessionId,
|
|
12469
|
-
client: options?.configureWarningClient ?? (sessionId ? this.configureWarningClients.get(sessionId) : undefined),
|
|
12470
|
-
warnings: configResult.warnings
|
|
12471
|
-
});
|
|
12549
|
+
await this.onConfigureWarnings(context);
|
|
12472
12550
|
} catch (err) {
|
|
12473
12551
|
this.warnVia(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
12474
12552
|
} finally {
|
|
@@ -12974,13 +13052,17 @@ function joinNonEmpty(parts, separator = " · ") {
|
|
|
12974
13052
|
function treeLine(depth, text) {
|
|
12975
13053
|
return `${" ".repeat(depth)}${depth === 0 ? "" : "↳ "}${text}`;
|
|
12976
13054
|
}
|
|
13055
|
+
function nameMatchEdgeMarker(record, theme) {
|
|
13056
|
+
return asString(record.resolved_by) === "name_match" ? ` ${theme.fg("warning", "~")}` : "";
|
|
13057
|
+
}
|
|
12977
13058
|
function renderCallTreeNode(node, depth, lines, theme) {
|
|
12978
13059
|
const name = asString(node.name) ?? "(unknown)";
|
|
12979
13060
|
const file = shortenPath(asString(node.file) ?? "(unknown file)");
|
|
12980
13061
|
const line = asNumber(node.line);
|
|
12981
13062
|
const unresolved = node.resolved === false ? ` ${theme.fg("warning", "[unresolved]")}` : "";
|
|
13063
|
+
const nameMatch = nameMatchEdgeMarker(node, theme);
|
|
12982
13064
|
const location = line !== undefined ? `[${file}:${line}]` : `[${file}]`;
|
|
12983
|
-
lines.push(treeLine(depth, `${name} ${location}${unresolved}`));
|
|
13065
|
+
lines.push(treeLine(depth, `${name} ${location}${unresolved}${nameMatch}`));
|
|
12984
13066
|
asRecords(node.children).forEach((child) => {
|
|
12985
13067
|
renderCallTreeNode(child, depth + 1, lines, theme);
|
|
12986
13068
|
});
|
|
@@ -12993,34 +13075,39 @@ function depthWarning(response, theme, depthField = "depth_limited", truncatedFi
|
|
|
12993
13075
|
const detail = truncated > 0 ? `, ${truncated} truncated` : "";
|
|
12994
13076
|
return theme.fg("warning", `(depth limited${detail})`);
|
|
12995
13077
|
}
|
|
12996
|
-
function renderTracePath(path2, index, lines) {
|
|
13078
|
+
function renderTracePath(path2, index, lines, theme) {
|
|
12997
13079
|
lines.push(`Path ${index + 1}`);
|
|
12998
13080
|
asRecords(path2.hops).forEach((hop, hopIndex) => {
|
|
12999
13081
|
const symbol = asString(hop.symbol) ?? "(unknown)";
|
|
13000
13082
|
const file = shortenPath(asString(hop.file) ?? "(unknown file)");
|
|
13001
13083
|
const line = asNumber(hop.line);
|
|
13002
13084
|
const entry = hop.is_entry_point === true ? " [entry]" : "";
|
|
13003
|
-
|
|
13085
|
+
const nameMatch = nameMatchEdgeMarker(hop, theme);
|
|
13086
|
+
lines.push(treeLine(hopIndex + 1, `${symbol}${entry} ${line !== undefined ? `[${file}:${line}]` : `[${file}]`}${nameMatch}`));
|
|
13004
13087
|
});
|
|
13005
13088
|
}
|
|
13006
13089
|
function renderCallersGroupLines(group, theme) {
|
|
13007
13090
|
const file = shortenPath(asString(group.file) ?? "(unknown file)");
|
|
13008
13091
|
const lines = [theme.fg("accent", file)];
|
|
13009
13092
|
const callers = asRecords(group.callers);
|
|
13010
|
-
const
|
|
13093
|
+
const bySymbolProvenance = new Map;
|
|
13011
13094
|
for (const caller of callers) {
|
|
13012
13095
|
const symbol = asString(caller.symbol) ?? "(unknown)";
|
|
13096
|
+
const provenanceKey = asString(caller.resolved_by) === "name_match" ? `${symbol}\x00name_match` : `${symbol}\x00exact`;
|
|
13013
13097
|
const line = asNumber(caller.line);
|
|
13014
|
-
const bucket =
|
|
13098
|
+
const bucket = bySymbolProvenance.get(provenanceKey) ?? [];
|
|
13015
13099
|
if (line !== undefined)
|
|
13016
13100
|
bucket.push(line);
|
|
13017
|
-
|
|
13101
|
+
bySymbolProvenance.set(provenanceKey, bucket);
|
|
13018
13102
|
}
|
|
13019
|
-
const
|
|
13020
|
-
for (const
|
|
13021
|
-
const
|
|
13103
|
+
const keys = [...bySymbolProvenance.keys()].sort((a, b) => a.localeCompare(b));
|
|
13104
|
+
for (const key of keys) {
|
|
13105
|
+
const symbol = key.split("\x00")[0] ?? "(unknown)";
|
|
13106
|
+
const isNameMatch = key.endsWith("\x00name_match");
|
|
13107
|
+
const lineNums = (bySymbolProvenance.get(key) ?? []).sort((a, b) => a - b);
|
|
13022
13108
|
const linePart = lineNums.length > 0 ? lineNums.map(String).join(", ") : "?";
|
|
13023
|
-
|
|
13109
|
+
const marker = isNameMatch ? ` ${theme.fg("warning", "~")}` : "";
|
|
13110
|
+
lines.push(` ↳ ${symbol}:${linePart}${marker}`);
|
|
13024
13111
|
}
|
|
13025
13112
|
return lines;
|
|
13026
13113
|
}
|
|
@@ -13066,7 +13153,8 @@ function formatCallgraphSections(op, response, theme = PLAIN_CALLGRAPH_THEME) {
|
|
|
13066
13153
|
const symbol = asString(hop.symbol) ?? "(unknown)";
|
|
13067
13154
|
const file = shortenPath(asString(hop.file) ?? "(unknown file)");
|
|
13068
13155
|
const line = asNumber(hop.line);
|
|
13069
|
-
|
|
13156
|
+
const nameMatch = nameMatchEdgeMarker(hop, theme);
|
|
13157
|
+
lines.push(treeLine(index + 1, `${symbol} ${line !== undefined ? `[${file}:${line}]` : `[${file}]`}${nameMatch}`));
|
|
13070
13158
|
});
|
|
13071
13159
|
return lines;
|
|
13072
13160
|
}
|
|
@@ -13086,7 +13174,7 @@ function formatCallgraphSections(op, response, theme = PLAIN_CALLGRAPH_THEME) {
|
|
|
13086
13174
|
sections2.push(theme.fg("muted", "No entry paths found."));
|
|
13087
13175
|
paths.forEach((path2, index) => {
|
|
13088
13176
|
const lines = [];
|
|
13089
|
-
renderTracePath(path2, index, lines);
|
|
13177
|
+
renderTracePath(path2, index, lines, theme);
|
|
13090
13178
|
sections2.push(lines.join(`
|
|
13091
13179
|
`));
|
|
13092
13180
|
});
|
|
@@ -13111,11 +13199,12 @@ function formatCallgraphSections(op, response, theme = PLAIN_CALLGRAPH_THEME) {
|
|
|
13111
13199
|
const symbol = asString(caller.caller_symbol) ?? "(unknown)";
|
|
13112
13200
|
const line = asNumber(caller.line) ?? 0;
|
|
13113
13201
|
const entry = caller.is_entry_point === true ? ` ${theme.fg("warning", "[entry]")}` : "";
|
|
13202
|
+
const nameMatch = nameMatchEdgeMarker(caller, theme);
|
|
13114
13203
|
const expression = asString(caller.call_expression);
|
|
13115
13204
|
const params = Array.isArray(caller.parameters) ? caller.parameters.map(String).join(", ") : "";
|
|
13116
13205
|
sections2.push([
|
|
13117
13206
|
`${theme.fg("accent", file)}:${line}`,
|
|
13118
|
-
` ↳ ${symbol}${entry}`,
|
|
13207
|
+
` ↳ ${symbol}${entry}${nameMatch}`,
|
|
13119
13208
|
expression ? ` ${theme.fg("muted", expression)}` : undefined,
|
|
13120
13209
|
params ? ` ${theme.fg("muted", `params: ${params}`)}` : undefined
|
|
13121
13210
|
].filter(Boolean).join(`
|
|
@@ -13138,7 +13227,8 @@ function formatCallgraphSections(op, response, theme = PLAIN_CALLGRAPH_THEME) {
|
|
|
13138
13227
|
const variable = asString(hop.variable) ?? "(unknown)";
|
|
13139
13228
|
const line = asNumber(hop.line) ?? 0;
|
|
13140
13229
|
const approximate = hop.approximate === true ? ` ${theme.fg("warning", "[approx]")}` : "";
|
|
13141
|
-
|
|
13230
|
+
const nameMatch = nameMatchEdgeMarker(hop, theme);
|
|
13231
|
+
sections.push(treeLine(index, `${variable} ${theme.fg("muted", `${asString(hop.flow_type) ?? "flow"}`)} ${symbol} [${file}:${line}]${approximate}${nameMatch}`));
|
|
13142
13232
|
});
|
|
13143
13233
|
return sections;
|
|
13144
13234
|
}
|
|
@@ -13163,6 +13253,48 @@ function coerceStringArray(value) {
|
|
|
13163
13253
|
}
|
|
13164
13254
|
return [];
|
|
13165
13255
|
}
|
|
13256
|
+
function coerceTargetParam(value) {
|
|
13257
|
+
if (Array.isArray(value)) {
|
|
13258
|
+
return value.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
13259
|
+
}
|
|
13260
|
+
if (typeof value === "string") {
|
|
13261
|
+
const trimmed = value.trim();
|
|
13262
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
13263
|
+
try {
|
|
13264
|
+
const parsed = JSON.parse(trimmed);
|
|
13265
|
+
if (Array.isArray(parsed)) {
|
|
13266
|
+
return parsed.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
13267
|
+
}
|
|
13268
|
+
} catch {}
|
|
13269
|
+
}
|
|
13270
|
+
return value;
|
|
13271
|
+
}
|
|
13272
|
+
return value;
|
|
13273
|
+
}
|
|
13274
|
+
function coerceBoolean(value, defaultValue = false) {
|
|
13275
|
+
if (defaultValue) {
|
|
13276
|
+
if (value === undefined)
|
|
13277
|
+
return true;
|
|
13278
|
+
if (typeof value === "boolean")
|
|
13279
|
+
return value;
|
|
13280
|
+
if (typeof value === "number")
|
|
13281
|
+
return value !== 0;
|
|
13282
|
+
if (typeof value === "string") {
|
|
13283
|
+
const normalized = value.trim().toLowerCase();
|
|
13284
|
+
return normalized !== "false" && normalized !== "0";
|
|
13285
|
+
}
|
|
13286
|
+
return true;
|
|
13287
|
+
}
|
|
13288
|
+
if (typeof value === "boolean")
|
|
13289
|
+
return value;
|
|
13290
|
+
if (typeof value === "number")
|
|
13291
|
+
return value === 1;
|
|
13292
|
+
if (typeof value === "string") {
|
|
13293
|
+
const normalized = value.trim().toLowerCase();
|
|
13294
|
+
return normalized === "true" || normalized === "1";
|
|
13295
|
+
}
|
|
13296
|
+
return false;
|
|
13297
|
+
}
|
|
13166
13298
|
function coerceOptionalInt(v, paramName, min, max) {
|
|
13167
13299
|
if (v === undefined || v === null || v === "")
|
|
13168
13300
|
return;
|
|
@@ -13188,10 +13320,43 @@ function isEmptyParam(value) {
|
|
|
13188
13320
|
return Object.keys(value).length === 0;
|
|
13189
13321
|
return false;
|
|
13190
13322
|
}
|
|
13323
|
+
// ../aft-bridge/dist/config-tiers.js
|
|
13324
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13325
|
+
import { resolve as resolve2 } from "node:path";
|
|
13326
|
+
function readConfigTiers(opts) {
|
|
13327
|
+
const tiers = [];
|
|
13328
|
+
try {
|
|
13329
|
+
if (existsSync(opts.userConfigPath)) {
|
|
13330
|
+
const doc = readFileSync(opts.userConfigPath, "utf-8");
|
|
13331
|
+
tiers.push({
|
|
13332
|
+
tier: "user",
|
|
13333
|
+
source: resolve2(opts.userConfigPath),
|
|
13334
|
+
doc
|
|
13335
|
+
});
|
|
13336
|
+
}
|
|
13337
|
+
} catch {}
|
|
13338
|
+
try {
|
|
13339
|
+
if (existsSync(opts.projectConfigPath)) {
|
|
13340
|
+
const doc = readFileSync(opts.projectConfigPath, "utf-8");
|
|
13341
|
+
tiers.push({
|
|
13342
|
+
tier: "project",
|
|
13343
|
+
source: resolve2(opts.projectConfigPath),
|
|
13344
|
+
doc
|
|
13345
|
+
});
|
|
13346
|
+
}
|
|
13347
|
+
} catch {}
|
|
13348
|
+
return tiers;
|
|
13349
|
+
}
|
|
13350
|
+
function formatDroppedKeyWarnings(dropped) {
|
|
13351
|
+
if (!dropped || !Array.isArray(dropped)) {
|
|
13352
|
+
return [];
|
|
13353
|
+
}
|
|
13354
|
+
return dropped.map((item) => `Ignoring ${item.key} from ${item.tier} config (${item.reason})`);
|
|
13355
|
+
}
|
|
13191
13356
|
// ../aft-bridge/dist/downloader.js
|
|
13192
13357
|
import { spawnSync } from "node:child_process";
|
|
13193
13358
|
import { createHash, randomUUID } from "node:crypto";
|
|
13194
|
-
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
|
|
13359
|
+
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readFileSync as readFileSync2, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
|
|
13195
13360
|
import { homedir as homedir4 } from "node:os";
|
|
13196
13361
|
import { join as join3 } from "node:path";
|
|
13197
13362
|
import { Readable } from "node:stream";
|
|
@@ -13263,7 +13428,7 @@ function getCachedBinaryPath(version) {
|
|
|
13263
13428
|
if (!version)
|
|
13264
13429
|
return null;
|
|
13265
13430
|
const binaryPath = join3(getCacheDir(), version, getBinaryName());
|
|
13266
|
-
return
|
|
13431
|
+
return existsSync2(binaryPath) ? binaryPath : null;
|
|
13267
13432
|
}
|
|
13268
13433
|
async function downloadBinary(version) {
|
|
13269
13434
|
const archMap = PLATFORM_ARCH_MAP[process.platform] ?? {};
|
|
@@ -13282,7 +13447,7 @@ async function downloadBinary(version) {
|
|
|
13282
13447
|
const versionedCacheDir = join3(getCacheDir(), tag);
|
|
13283
13448
|
const binaryName = getBinaryName();
|
|
13284
13449
|
const binaryPath = join3(versionedCacheDir, binaryName);
|
|
13285
|
-
if (
|
|
13450
|
+
if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
|
|
13286
13451
|
return binaryPath;
|
|
13287
13452
|
}
|
|
13288
13453
|
const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
|
|
@@ -13296,11 +13461,11 @@ async function downloadBinary(version) {
|
|
|
13296
13461
|
let checksumTimeout = null;
|
|
13297
13462
|
const tmpPath = `${binaryPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
13298
13463
|
try {
|
|
13299
|
-
if (!
|
|
13464
|
+
if (!existsSync2(versionedCacheDir)) {
|
|
13300
13465
|
mkdirSync(versionedCacheDir, { recursive: true });
|
|
13301
13466
|
}
|
|
13302
13467
|
releaseLock = await acquireDownloadLock(lockPath);
|
|
13303
|
-
if (
|
|
13468
|
+
if (existsSync2(binaryPath) && isExpectedCachedBinary(binaryPath, tag)) {
|
|
13304
13469
|
return binaryPath;
|
|
13305
13470
|
}
|
|
13306
13471
|
binaryController = new AbortController;
|
|
@@ -13365,7 +13530,7 @@ async function downloadBinary(version) {
|
|
|
13365
13530
|
renameSync(tmpPath, binaryPath);
|
|
13366
13531
|
}
|
|
13367
13532
|
try {
|
|
13368
|
-
if (
|
|
13533
|
+
if (existsSync2(tmpPath))
|
|
13369
13534
|
unlinkSync(tmpPath);
|
|
13370
13535
|
} catch {
|
|
13371
13536
|
warn(`Could not clean up temporary download file ${tmpPath} — it can be removed manually.`);
|
|
@@ -13375,7 +13540,7 @@ async function downloadBinary(version) {
|
|
|
13375
13540
|
} catch (err) {
|
|
13376
13541
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13377
13542
|
error(`Failed to download AFT binary: ${msg}`);
|
|
13378
|
-
if (
|
|
13543
|
+
if (existsSync2(tmpPath)) {
|
|
13379
13544
|
try {
|
|
13380
13545
|
unlinkSync(tmpPath);
|
|
13381
13546
|
} catch {}
|
|
@@ -13419,7 +13584,7 @@ async function acquireDownloadLock(lockPath) {
|
|
|
13419
13584
|
closeSync(fd);
|
|
13420
13585
|
} catch {}
|
|
13421
13586
|
try {
|
|
13422
|
-
if (
|
|
13587
|
+
if (readFileSync2(lockPath, "utf-8") === owner) {
|
|
13423
13588
|
rmSync(lockPath, { force: true });
|
|
13424
13589
|
}
|
|
13425
13590
|
} catch {}
|
|
@@ -13440,7 +13605,7 @@ async function acquireDownloadLock(lockPath) {
|
|
|
13440
13605
|
if (Date.now() - startedAt > DOWNLOAD_LOCK_TIMEOUT_MS) {
|
|
13441
13606
|
throw new Error(`Timed out waiting for download lock: ${lockPath}`);
|
|
13442
13607
|
}
|
|
13443
|
-
await new Promise((
|
|
13608
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
13444
13609
|
}
|
|
13445
13610
|
}
|
|
13446
13611
|
}
|
|
@@ -13495,7 +13660,7 @@ function formatEditSummary(data) {
|
|
|
13495
13660
|
if (data.created === true) {
|
|
13496
13661
|
let s2 = `Created file (${counts}).`;
|
|
13497
13662
|
if (data.formatted)
|
|
13498
|
-
s2 +=
|
|
13663
|
+
s2 += formatAutoFormattedSuffix(data);
|
|
13499
13664
|
return s2;
|
|
13500
13665
|
}
|
|
13501
13666
|
let detail = counts;
|
|
@@ -13506,9 +13671,21 @@ function formatEditSummary(data) {
|
|
|
13506
13671
|
}
|
|
13507
13672
|
let s = `Edited (${detail}).`;
|
|
13508
13673
|
if (data.formatted)
|
|
13509
|
-
s +=
|
|
13674
|
+
s += formatAutoFormattedSuffix(data);
|
|
13510
13675
|
return s;
|
|
13511
13676
|
}
|
|
13677
|
+
function formatAutoFormattedSuffix(data) {
|
|
13678
|
+
const reflowText = data.reformatted?.text;
|
|
13679
|
+
if (typeof reflowText === "string" && reflowText.length > 0) {
|
|
13680
|
+
return `
|
|
13681
|
+
Auto-formatted — the formatter reflowed your edit. On disk now:
|
|
13682
|
+
${reflowText}`;
|
|
13683
|
+
}
|
|
13684
|
+
if (data.reformatted?.extensive === true) {
|
|
13685
|
+
return " Auto-formatted — extensive reflow; re-read the file before your next anchored edit.";
|
|
13686
|
+
}
|
|
13687
|
+
return " Auto-formatted.";
|
|
13688
|
+
}
|
|
13512
13689
|
// ../aft-bridge/dist/format.js
|
|
13513
13690
|
function compressionSavingsPercent(original, compressed) {
|
|
13514
13691
|
if (original <= 0)
|
|
@@ -13532,20 +13709,71 @@ function stripJsoncSymbols(value) {
|
|
|
13532
13709
|
}
|
|
13533
13710
|
// ../aft-bridge/dist/migration.js
|
|
13534
13711
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
13535
|
-
import { existsSync as
|
|
13536
|
-
import { homedir as
|
|
13537
|
-
import { dirname as dirname2, join as join6 } from "node:path";
|
|
13712
|
+
import { closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync4, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
13713
|
+
import { homedir as homedir7, tmpdir } from "node:os";
|
|
13714
|
+
import { basename, dirname as dirname2, join as join6, resolve as resolve4 } from "node:path";
|
|
13538
13715
|
|
|
13539
13716
|
// ../aft-bridge/dist/paths.js
|
|
13540
|
-
import { existsSync as
|
|
13541
|
-
import {
|
|
13717
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync } from "node:fs";
|
|
13718
|
+
import { homedir as homedir5 } from "node:os";
|
|
13719
|
+
import { dirname, isAbsolute as isAbsolute2, join as join4, resolve as resolve3 } from "node:path";
|
|
13720
|
+
function homeDir() {
|
|
13721
|
+
if (process.platform === "win32")
|
|
13722
|
+
return process.env.USERPROFILE || process.env.HOME || homedir5();
|
|
13723
|
+
return process.env.HOME || homedir5();
|
|
13724
|
+
}
|
|
13725
|
+
function configHome() {
|
|
13726
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
13727
|
+
if (xdg && isAbsolute2(xdg))
|
|
13728
|
+
return xdg;
|
|
13729
|
+
return join4(homeDir(), ".config");
|
|
13730
|
+
}
|
|
13731
|
+
function legacyOpenCodeConfigDir() {
|
|
13732
|
+
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
13733
|
+
if (envDir)
|
|
13734
|
+
return resolve3(envDir);
|
|
13735
|
+
return join4(configHome(), "opencode");
|
|
13736
|
+
}
|
|
13737
|
+
function legacyPiAgentDir() {
|
|
13738
|
+
return join4(homeDir(), ".pi", "agent");
|
|
13739
|
+
}
|
|
13740
|
+
function legacySources(basePath, label, harness) {
|
|
13741
|
+
return [
|
|
13742
|
+
{ path: `${basePath}.jsonc`, label: `${label} aft.jsonc`, harness },
|
|
13743
|
+
{ path: `${basePath}.json`, label: `${label} aft.json`, harness }
|
|
13744
|
+
];
|
|
13745
|
+
}
|
|
13746
|
+
function resolveCortexKitUserConfigPath() {
|
|
13747
|
+
return join4(configHome(), "cortexkit", "aft.jsonc");
|
|
13748
|
+
}
|
|
13749
|
+
function resolveCortexKitProjectConfigPath(projectDirectory) {
|
|
13750
|
+
return join4(projectDirectory, ".cortexkit", "aft.jsonc");
|
|
13751
|
+
}
|
|
13752
|
+
function resolveCortexKitConfigPaths(projectDirectory) {
|
|
13753
|
+
return {
|
|
13754
|
+
userConfigPath: resolveCortexKitUserConfigPath(),
|
|
13755
|
+
projectConfigPath: resolveCortexKitProjectConfigPath(projectDirectory)
|
|
13756
|
+
};
|
|
13757
|
+
}
|
|
13758
|
+
function resolveLegacyAftConfigSources(projectDirectory) {
|
|
13759
|
+
return {
|
|
13760
|
+
user: [
|
|
13761
|
+
...legacySources(join4(legacyOpenCodeConfigDir(), "aft"), "OpenCode user", "opencode"),
|
|
13762
|
+
...legacySources(join4(legacyPiAgentDir(), "aft"), "Pi user", "pi")
|
|
13763
|
+
],
|
|
13764
|
+
project: [
|
|
13765
|
+
...legacySources(join4(projectDirectory, ".opencode", "aft"), "OpenCode project", "opencode"),
|
|
13766
|
+
...legacySources(join4(projectDirectory, ".pi", "aft"), "Pi project", "pi")
|
|
13767
|
+
]
|
|
13768
|
+
};
|
|
13769
|
+
}
|
|
13542
13770
|
function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
|
|
13543
13771
|
return join4(storageRoot, harness, ...segments);
|
|
13544
13772
|
}
|
|
13545
13773
|
function repairRootScopedStorageFile(storageRoot, harness, fileName) {
|
|
13546
13774
|
const harnessPath = resolveHarnessStoragePath(storageRoot, harness, fileName);
|
|
13547
13775
|
const rootPath = join4(storageRoot, fileName);
|
|
13548
|
-
if (
|
|
13776
|
+
if (existsSync3(harnessPath) || !existsSync3(rootPath))
|
|
13549
13777
|
return harnessPath;
|
|
13550
13778
|
try {
|
|
13551
13779
|
mkdirSync2(dirname(harnessPath), { recursive: true });
|
|
@@ -13559,8 +13787,8 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
|
|
|
13559
13787
|
const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
|
|
13560
13788
|
let lastVersion = "";
|
|
13561
13789
|
try {
|
|
13562
|
-
if (
|
|
13563
|
-
lastVersion =
|
|
13790
|
+
if (existsSync3(versionFile)) {
|
|
13791
|
+
lastVersion = readFileSync3(versionFile, "utf-8").trim();
|
|
13564
13792
|
}
|
|
13565
13793
|
} catch {
|
|
13566
13794
|
return false;
|
|
@@ -13588,9 +13816,9 @@ function markAnnouncementSeen(storageRoot, harness, currentVersion) {
|
|
|
13588
13816
|
|
|
13589
13817
|
// ../aft-bridge/dist/resolver.js
|
|
13590
13818
|
import { execSync } from "node:child_process";
|
|
13591
|
-
import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as
|
|
13819
|
+
import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync as openSync2, readSync, renameSync as renameSync3, unlinkSync as unlinkSync2 } from "node:fs";
|
|
13592
13820
|
import { createRequire as createRequire2 } from "node:module";
|
|
13593
|
-
import { homedir as
|
|
13821
|
+
import { homedir as homedir6 } from "node:os";
|
|
13594
13822
|
import { join as join5 } from "node:path";
|
|
13595
13823
|
var ensureBinaryForResolver = ensureBinary;
|
|
13596
13824
|
function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
@@ -13603,7 +13831,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
13603
13831
|
const versionedDir = join5(cacheDir, tag);
|
|
13604
13832
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
13605
13833
|
const cachedPath = join5(versionedDir, `aft${ext}`);
|
|
13606
|
-
if (
|
|
13834
|
+
if (existsSync4(cachedPath)) {
|
|
13607
13835
|
const cachedVersion = readBinaryVersion(cachedPath);
|
|
13608
13836
|
if (cachedVersion === version)
|
|
13609
13837
|
return cachedPath;
|
|
@@ -13615,7 +13843,7 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
13615
13843
|
if (process.platform !== "win32") {
|
|
13616
13844
|
chmodSync2(tmpPath, 493);
|
|
13617
13845
|
}
|
|
13618
|
-
if (process.platform === "win32" &&
|
|
13846
|
+
if (process.platform === "win32" && existsSync4(cachedPath)) {
|
|
13619
13847
|
try {
|
|
13620
13848
|
unlinkSync2(cachedPath);
|
|
13621
13849
|
} catch {}
|
|
@@ -13632,7 +13860,7 @@ function normalizeBareVersion(version) {
|
|
|
13632
13860
|
return version.startsWith("v") ? version.slice(1) : version;
|
|
13633
13861
|
}
|
|
13634
13862
|
function homeDirFromEnv(env) {
|
|
13635
|
-
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) ||
|
|
13863
|
+
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir6();
|
|
13636
13864
|
}
|
|
13637
13865
|
function cacheDirFromEnv(env) {
|
|
13638
13866
|
if (process.platform === "win32") {
|
|
@@ -13644,7 +13872,7 @@ function cacheDirFromEnv(env) {
|
|
|
13644
13872
|
}
|
|
13645
13873
|
function cachedBinaryPathFromEnv(version, env, ext) {
|
|
13646
13874
|
const binaryPath = join5(cacheDirFromEnv(env), version, `aft${ext}`);
|
|
13647
|
-
return
|
|
13875
|
+
return existsSync4(binaryPath) ? binaryPath : null;
|
|
13648
13876
|
}
|
|
13649
13877
|
function isExpectedCachedBinary2(binaryPath, expectedVersion) {
|
|
13650
13878
|
const expected = normalizeBareVersion(expectedVersion);
|
|
@@ -13733,7 +13961,7 @@ function findBinarySync(expectedVersion) {
|
|
|
13733
13961
|
const packageBin = `@cortexkit/aft-${key}/bin/aft${ext}`;
|
|
13734
13962
|
const req = createRequire2(import.meta.url);
|
|
13735
13963
|
const resolved = req.resolve(packageBin);
|
|
13736
|
-
if (
|
|
13964
|
+
if (existsSync4(resolved)) {
|
|
13737
13965
|
const npmVersion = readBinaryVersion(resolved);
|
|
13738
13966
|
if (npmVersion === null) {
|
|
13739
13967
|
warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
|
|
@@ -13763,7 +13991,7 @@ function findBinarySync(expectedVersion) {
|
|
|
13763
13991
|
}
|
|
13764
13992
|
} catch {}
|
|
13765
13993
|
const cargoPath = join5(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
|
|
13766
|
-
if (
|
|
13994
|
+
if (existsSync4(cargoPath)) {
|
|
13767
13995
|
const usable = probeBinaryCandidate(cargoPath, "cargo", expectedVersion);
|
|
13768
13996
|
if (usable)
|
|
13769
13997
|
return usable;
|
|
@@ -13808,23 +14036,343 @@ function dataHome() {
|
|
|
13808
14036
|
if (process.env.XDG_DATA_HOME)
|
|
13809
14037
|
return process.env.XDG_DATA_HOME;
|
|
13810
14038
|
if (process.platform === "win32") {
|
|
13811
|
-
return process.env.LOCALAPPDATA || process.env.APPDATA || join6(
|
|
14039
|
+
return process.env.LOCALAPPDATA || process.env.APPDATA || join6(homeDir2(), "AppData", "Local");
|
|
13812
14040
|
}
|
|
13813
|
-
return join6(
|
|
14041
|
+
return join6(homeDir2(), ".local", "share");
|
|
13814
14042
|
}
|
|
13815
|
-
function
|
|
14043
|
+
function homeDir2() {
|
|
13816
14044
|
if (process.platform === "win32")
|
|
13817
|
-
return process.env.USERPROFILE || process.env.HOME ||
|
|
13818
|
-
return process.env.HOME ||
|
|
14045
|
+
return process.env.USERPROFILE || process.env.HOME || homedir7();
|
|
14046
|
+
return process.env.HOME || homedir7();
|
|
13819
14047
|
}
|
|
13820
14048
|
function resolveLegacyStorageRoot(harness) {
|
|
13821
14049
|
if (harness === "pi")
|
|
13822
|
-
return join6(
|
|
14050
|
+
return join6(homeDir2(), ".pi", "agent", "aft");
|
|
13823
14051
|
return join6(dataHome(), "opencode", "storage", "plugin", "aft");
|
|
13824
14052
|
}
|
|
13825
14053
|
function resolveCortexKitStorageRoot() {
|
|
13826
14054
|
return join6(dataHome(), "cortexkit", "aft");
|
|
13827
14055
|
}
|
|
14056
|
+
function stripJsoncForParse(input) {
|
|
14057
|
+
let out = "";
|
|
14058
|
+
let inString = false;
|
|
14059
|
+
let escaped = false;
|
|
14060
|
+
for (let i = 0;i < input.length; i++) {
|
|
14061
|
+
const ch = input[i];
|
|
14062
|
+
const next = input[i + 1];
|
|
14063
|
+
if (inString) {
|
|
14064
|
+
out += ch;
|
|
14065
|
+
if (escaped) {
|
|
14066
|
+
escaped = false;
|
|
14067
|
+
} else if (ch === "\\") {
|
|
14068
|
+
escaped = true;
|
|
14069
|
+
} else if (ch === '"') {
|
|
14070
|
+
inString = false;
|
|
14071
|
+
}
|
|
14072
|
+
continue;
|
|
14073
|
+
}
|
|
14074
|
+
if (ch === '"') {
|
|
14075
|
+
inString = true;
|
|
14076
|
+
out += ch;
|
|
14077
|
+
continue;
|
|
14078
|
+
}
|
|
14079
|
+
if (ch === "/" && next === "/") {
|
|
14080
|
+
while (i < input.length && input[i] !== `
|
|
14081
|
+
`)
|
|
14082
|
+
i++;
|
|
14083
|
+
out += `
|
|
14084
|
+
`;
|
|
14085
|
+
continue;
|
|
14086
|
+
}
|
|
14087
|
+
if (ch === "/" && next === "*") {
|
|
14088
|
+
i += 2;
|
|
14089
|
+
while (i < input.length && !(input[i] === "*" && input[i + 1] === "/"))
|
|
14090
|
+
i++;
|
|
14091
|
+
i++;
|
|
14092
|
+
out += " ";
|
|
14093
|
+
continue;
|
|
14094
|
+
}
|
|
14095
|
+
out += ch;
|
|
14096
|
+
}
|
|
14097
|
+
let withoutTrailingCommas = "";
|
|
14098
|
+
inString = false;
|
|
14099
|
+
escaped = false;
|
|
14100
|
+
for (let i = 0;i < out.length; i++) {
|
|
14101
|
+
const ch = out[i];
|
|
14102
|
+
if (inString) {
|
|
14103
|
+
withoutTrailingCommas += ch;
|
|
14104
|
+
if (escaped) {
|
|
14105
|
+
escaped = false;
|
|
14106
|
+
} else if (ch === "\\") {
|
|
14107
|
+
escaped = true;
|
|
14108
|
+
} else if (ch === '"') {
|
|
14109
|
+
inString = false;
|
|
14110
|
+
}
|
|
14111
|
+
continue;
|
|
14112
|
+
}
|
|
14113
|
+
if (ch === '"') {
|
|
14114
|
+
inString = true;
|
|
14115
|
+
withoutTrailingCommas += ch;
|
|
14116
|
+
continue;
|
|
14117
|
+
}
|
|
14118
|
+
if (ch === ",") {
|
|
14119
|
+
let j = i + 1;
|
|
14120
|
+
while (j < out.length && /\s/.test(out[j]))
|
|
14121
|
+
j++;
|
|
14122
|
+
if (out[j] === "}" || out[j] === "]")
|
|
14123
|
+
continue;
|
|
14124
|
+
}
|
|
14125
|
+
withoutTrailingCommas += ch;
|
|
14126
|
+
}
|
|
14127
|
+
return withoutTrailingCommas;
|
|
14128
|
+
}
|
|
14129
|
+
function sortJson(value) {
|
|
14130
|
+
if (Array.isArray(value))
|
|
14131
|
+
return value.map(sortJson);
|
|
14132
|
+
if (value && typeof value === "object") {
|
|
14133
|
+
const sorted = {};
|
|
14134
|
+
for (const key of Object.keys(value).sort()) {
|
|
14135
|
+
sorted[key] = sortJson(value[key]);
|
|
14136
|
+
}
|
|
14137
|
+
return sorted;
|
|
14138
|
+
}
|
|
14139
|
+
return value;
|
|
14140
|
+
}
|
|
14141
|
+
function normalizedJsoncSemantics(content) {
|
|
14142
|
+
return JSON.stringify(sortJson(JSON.parse(stripJsoncForParse(content))));
|
|
14143
|
+
}
|
|
14144
|
+
function fileSemanticsMatch(a, b) {
|
|
14145
|
+
try {
|
|
14146
|
+
return normalizedJsoncSemantics(a) === normalizedJsoncSemantics(b);
|
|
14147
|
+
} catch {
|
|
14148
|
+
return a === b;
|
|
14149
|
+
}
|
|
14150
|
+
}
|
|
14151
|
+
function sleepSync(ms) {
|
|
14152
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
14153
|
+
}
|
|
14154
|
+
function acquireConfigMigrationLock(lockDir) {
|
|
14155
|
+
const deadline = Date.now() + 30000;
|
|
14156
|
+
while (true) {
|
|
14157
|
+
try {
|
|
14158
|
+
mkdirSync4(lockDir, { recursive: false });
|
|
14159
|
+
return () => {
|
|
14160
|
+
try {
|
|
14161
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
14162
|
+
} catch {}
|
|
14163
|
+
};
|
|
14164
|
+
} catch (err) {
|
|
14165
|
+
const code = err?.code;
|
|
14166
|
+
if (code !== "EEXIST")
|
|
14167
|
+
throw err;
|
|
14168
|
+
try {
|
|
14169
|
+
const ageMs = Date.now() - statSync2(lockDir).mtimeMs;
|
|
14170
|
+
if (ageMs > 60000) {
|
|
14171
|
+
rmSync2(lockDir, { recursive: true, force: true });
|
|
14172
|
+
continue;
|
|
14173
|
+
}
|
|
14174
|
+
} catch {}
|
|
14175
|
+
if (Date.now() >= deadline) {
|
|
14176
|
+
throw new Error(`timed out waiting for config migration lock ${lockDir}`);
|
|
14177
|
+
}
|
|
14178
|
+
sleepSync(25);
|
|
14179
|
+
}
|
|
14180
|
+
}
|
|
14181
|
+
}
|
|
14182
|
+
function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
14183
|
+
mkdirSync4(dirname2(targetPath), { recursive: true });
|
|
14184
|
+
const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
14185
|
+
let fd = null;
|
|
14186
|
+
try {
|
|
14187
|
+
fd = openSync3(tmpPath, "wx", 384);
|
|
14188
|
+
writeFileSync2(fd, readFileSync4(sourcePath));
|
|
14189
|
+
closeSync3(fd);
|
|
14190
|
+
fd = null;
|
|
14191
|
+
renameSync4(tmpPath, targetPath);
|
|
14192
|
+
} catch (err) {
|
|
14193
|
+
if (fd !== null) {
|
|
14194
|
+
try {
|
|
14195
|
+
closeSync3(fd);
|
|
14196
|
+
} catch {}
|
|
14197
|
+
}
|
|
14198
|
+
try {
|
|
14199
|
+
unlinkSync3(tmpPath);
|
|
14200
|
+
} catch {}
|
|
14201
|
+
throw err;
|
|
14202
|
+
}
|
|
14203
|
+
}
|
|
14204
|
+
function atomicWriteConfigFile(targetPath, content) {
|
|
14205
|
+
mkdirSync4(dirname2(targetPath), { recursive: true });
|
|
14206
|
+
const tmpPath = join6(dirname2(targetPath), `.${basename(targetPath)}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
14207
|
+
let fd = null;
|
|
14208
|
+
try {
|
|
14209
|
+
fd = openSync3(tmpPath, "wx", 384);
|
|
14210
|
+
writeFileSync2(fd, content);
|
|
14211
|
+
closeSync3(fd);
|
|
14212
|
+
fd = null;
|
|
14213
|
+
renameSync4(tmpPath, targetPath);
|
|
14214
|
+
} catch (err) {
|
|
14215
|
+
if (fd !== null) {
|
|
14216
|
+
try {
|
|
14217
|
+
closeSync3(fd);
|
|
14218
|
+
} catch {}
|
|
14219
|
+
}
|
|
14220
|
+
try {
|
|
14221
|
+
unlinkSync3(tmpPath);
|
|
14222
|
+
} catch {}
|
|
14223
|
+
throw err;
|
|
14224
|
+
}
|
|
14225
|
+
}
|
|
14226
|
+
var MOVED_MARKER_SUFFIX = ".MOVED_READPLEASE";
|
|
14227
|
+
function nonClobberingSidecarPath(desiredPath) {
|
|
14228
|
+
if (!existsSync5(desiredPath))
|
|
14229
|
+
return desiredPath;
|
|
14230
|
+
for (let index = 1;index < Number.MAX_SAFE_INTEGER; index++) {
|
|
14231
|
+
const candidate = `${desiredPath}.${index}`;
|
|
14232
|
+
if (!existsSync5(candidate))
|
|
14233
|
+
return candidate;
|
|
14234
|
+
}
|
|
14235
|
+
throw new Error(`could not find available preservation sidecar path for ${desiredPath}`);
|
|
14236
|
+
}
|
|
14237
|
+
function movedMarkerContent(targetPath, originalName, originalContent) {
|
|
14238
|
+
const header = [
|
|
14239
|
+
"// AFT configuration moved.",
|
|
14240
|
+
"//",
|
|
14241
|
+
"// AFT now reads its configuration from one shared CortexKit location",
|
|
14242
|
+
"// instead of a per-agent path. The settings that were in this file have",
|
|
14243
|
+
"// been moved to:",
|
|
14244
|
+
"//",
|
|
14245
|
+
`// ${targetPath}`,
|
|
14246
|
+
"//",
|
|
14247
|
+
"// Edit that file to change AFT settings. This location is no longer read",
|
|
14248
|
+
"// by AFT.",
|
|
14249
|
+
"//",
|
|
14250
|
+
`// To undo, rename this file back to "${originalName}" (and remove the`,
|
|
14251
|
+
"// CortexKit copy above if you want this location to take precedence).",
|
|
14252
|
+
"//",
|
|
14253
|
+
"// Your original settings are preserved below for reference.",
|
|
14254
|
+
"",
|
|
14255
|
+
""
|
|
14256
|
+
].join(`
|
|
14257
|
+
`);
|
|
14258
|
+
return `${header}${originalContent}`;
|
|
14259
|
+
}
|
|
14260
|
+
function markLegacySourcesMovedAside(sources, targetPath, logger) {
|
|
14261
|
+
const warnings = [];
|
|
14262
|
+
const info = logger?.info ?? logger?.log;
|
|
14263
|
+
for (const source of sources) {
|
|
14264
|
+
const desiredMarkerPath = `${source.path}${MOVED_MARKER_SUFFIX}`;
|
|
14265
|
+
const markerPath = nonClobberingSidecarPath(desiredMarkerPath);
|
|
14266
|
+
try {
|
|
14267
|
+
const original = readFileSync4(source.path, "utf-8");
|
|
14268
|
+
if (markerPath !== desiredMarkerPath) {
|
|
14269
|
+
logger?.warn?.(`Preserving existing legacy AFT marker ${desiredMarkerPath}; writing new marker to ${markerPath}`);
|
|
14270
|
+
}
|
|
14271
|
+
atomicWriteConfigFile(markerPath, movedMarkerContent(targetPath, basename(source.path), original));
|
|
14272
|
+
unlinkSync3(source.path);
|
|
14273
|
+
info?.(`Moved legacy AFT config ${source.path} aside to ${markerPath}; AFT now reads ${targetPath}`);
|
|
14274
|
+
} catch (err) {
|
|
14275
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14276
|
+
warnings.push(`AFT could not move legacy config ${source.path} aside (${msg}); it is now stale and ignored. Delete it manually — AFT reads ${targetPath}.`);
|
|
14277
|
+
logger?.warn?.(`Could not move legacy AFT config ${source.path} aside (${msg}); AFT reads ${targetPath}`);
|
|
14278
|
+
}
|
|
14279
|
+
}
|
|
14280
|
+
return warnings;
|
|
14281
|
+
}
|
|
14282
|
+
var PRESERVED_OLD_SUFFIX = "_OLD";
|
|
14283
|
+
function preservedOldContent(losingHarness, winningHarness, targetPath, originalContent) {
|
|
14284
|
+
const winnerLine = winningHarness ? `// configs differed, so ${winningHarness}'s config won (first harness to run the` : "// configs differed, so the config that was migrated first won and is the";
|
|
14285
|
+
const header = [
|
|
14286
|
+
`// AFT config from ${losingHarness} — preserved, NOT read.`,
|
|
14287
|
+
"//",
|
|
14288
|
+
"// AFT now reads one shared config for all harnesses. Your OpenCode and Pi",
|
|
14289
|
+
winnerLine,
|
|
14290
|
+
winningHarness ? "// migration) and is now the active config at:" : "// active config at:",
|
|
14291
|
+
"//",
|
|
14292
|
+
`// ${targetPath}`,
|
|
14293
|
+
"//",
|
|
14294
|
+
`// This file holds ${losingHarness}'s previous settings. Merge anything you`,
|
|
14295
|
+
"// want to keep into the active config above, then delete this file. AFT does",
|
|
14296
|
+
"// not read this path.",
|
|
14297
|
+
"",
|
|
14298
|
+
""
|
|
14299
|
+
].join(`
|
|
14300
|
+
`);
|
|
14301
|
+
return `${header}${originalContent}`;
|
|
14302
|
+
}
|
|
14303
|
+
function preserveDifferingSourceAsOld(source, winningHarness, targetPath, logger) {
|
|
14304
|
+
const losingHarness = source.harness ?? "pi";
|
|
14305
|
+
const desiredOldPath = `${targetPath}.${losingHarness}${PRESERVED_OLD_SUFFIX}`;
|
|
14306
|
+
const oldPath = nonClobberingSidecarPath(desiredOldPath);
|
|
14307
|
+
try {
|
|
14308
|
+
if (oldPath !== desiredOldPath) {
|
|
14309
|
+
logger?.warn?.(`Preserving existing ${losingHarness} config sidecar ${desiredOldPath}; writing new preserved config to ${oldPath}`);
|
|
14310
|
+
}
|
|
14311
|
+
atomicWriteConfigFile(oldPath, preservedOldContent(losingHarness, winningHarness, targetPath, source.content));
|
|
14312
|
+
} catch (err) {
|
|
14313
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14314
|
+
logger?.warn?.(`Could not preserve ${losingHarness} config as ${oldPath} (${msg})`);
|
|
14315
|
+
}
|
|
14316
|
+
const usingDesc = winningHarness ? `${winningHarness}'s config` : "the existing shared config";
|
|
14317
|
+
return `AFT found different OpenCode and Pi configs during config unification. ` + `Using ${usingDesc} at ${targetPath}; preserved ${losingHarness}'s previous ` + `config at ${oldPath} — merge any settings you want to keep, then delete it.`;
|
|
14318
|
+
}
|
|
14319
|
+
function visibleConfigMigrationWarning(scope, targetPath, paths, reason) {
|
|
14320
|
+
const uniquePaths = [...new Set([targetPath, ...paths])];
|
|
14321
|
+
return `AFT ${scope} config migration refused: ${reason}. ` + `Legacy and CortexKit config paths collapse to one file, but AFT will not overwrite or merge them automatically. ` + `Please consolidate manually into ${targetPath}. Paths: ${uniquePaths.join(" ; ")}`;
|
|
14322
|
+
}
|
|
14323
|
+
function migrateAftConfigFile(opts) {
|
|
14324
|
+
const warnings = [];
|
|
14325
|
+
const resolvedTarget = resolve4(opts.targetPath);
|
|
14326
|
+
const existingSources = opts.legacySources.filter((source) => existsSync5(source.path) && resolve4(source.path) !== resolvedTarget);
|
|
14327
|
+
const info = opts.logger?.info ?? opts.logger?.log;
|
|
14328
|
+
if (existingSources.length === 0) {
|
|
14329
|
+
return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
|
|
14330
|
+
}
|
|
14331
|
+
mkdirSync4(dirname2(opts.targetPath), { recursive: true });
|
|
14332
|
+
const release = acquireConfigMigrationLock(`${opts.targetPath}.lock`);
|
|
14333
|
+
try {
|
|
14334
|
+
const sources = existingSources.map((source) => ({
|
|
14335
|
+
...source,
|
|
14336
|
+
content: readFileSync4(source.path, "utf-8")
|
|
14337
|
+
}));
|
|
14338
|
+
if (existsSync5(opts.targetPath)) {
|
|
14339
|
+
const targetContent = readFileSync4(opts.targetPath, "utf-8");
|
|
14340
|
+
for (const source of sources) {
|
|
14341
|
+
if (fileSemanticsMatch(source.content, targetContent))
|
|
14342
|
+
continue;
|
|
14343
|
+
warnings.push(preserveDifferingSourceAsOld(source, undefined, opts.targetPath, opts.logger));
|
|
14344
|
+
}
|
|
14345
|
+
info?.(`AFT ${opts.scope} config already present at ${opts.targetPath}; reconciled ${sources.length} legacy source(s)`);
|
|
14346
|
+
warnings.push(...markLegacySourcesMovedAside(sources, opts.targetPath, opts.logger));
|
|
14347
|
+
return { migrated: false, conflict: false, targetPath: opts.targetPath, warnings };
|
|
14348
|
+
}
|
|
14349
|
+
const winner = (opts.operatingHarness ? sources.find((source) => source.harness === opts.operatingHarness) : undefined) ?? sources[0];
|
|
14350
|
+
atomicCopyConfigFile(winner.path, opts.targetPath);
|
|
14351
|
+
info?.(`Migrated AFT ${opts.scope} config from ${winner.path} to ${opts.targetPath}`);
|
|
14352
|
+
for (const source of sources) {
|
|
14353
|
+
if (source.path === winner.path)
|
|
14354
|
+
continue;
|
|
14355
|
+
if (fileSemanticsMatch(source.content, winner.content))
|
|
14356
|
+
continue;
|
|
14357
|
+
warnings.push(preserveDifferingSourceAsOld(source, winner.harness, opts.targetPath, opts.logger));
|
|
14358
|
+
}
|
|
14359
|
+
warnings.push(...markLegacySourcesMovedAside(sources, opts.targetPath, opts.logger));
|
|
14360
|
+
return {
|
|
14361
|
+
migrated: true,
|
|
14362
|
+
conflict: false,
|
|
14363
|
+
sourcePath: winner.path,
|
|
14364
|
+
targetPath: opts.targetPath,
|
|
14365
|
+
warnings
|
|
14366
|
+
};
|
|
14367
|
+
} catch (err) {
|
|
14368
|
+
const message = visibleConfigMigrationWarning(opts.scope, opts.targetPath, existingSources.map((source) => source.path), `migration failed (${err instanceof Error ? err.message : String(err)})`);
|
|
14369
|
+
warnings.push(message);
|
|
14370
|
+
opts.logger?.warn?.(message);
|
|
14371
|
+
return { migrated: false, conflict: true, targetPath: opts.targetPath, warnings };
|
|
14372
|
+
} finally {
|
|
14373
|
+
release();
|
|
14374
|
+
}
|
|
14375
|
+
}
|
|
13828
14376
|
function tail(value) {
|
|
13829
14377
|
if (!value)
|
|
13830
14378
|
return "";
|
|
@@ -13852,11 +14400,11 @@ async function ensureStorageMigrated(opts) {
|
|
|
13852
14400
|
const newRoot = resolveCortexKitStorageRoot();
|
|
13853
14401
|
const targetMarker = resolveHarnessStoragePath(newRoot, opts.harness, TARGET_MARKER);
|
|
13854
14402
|
const info = opts.logger?.info ?? opts.logger?.log;
|
|
13855
|
-
if (
|
|
14403
|
+
if (existsSync5(targetMarker)) {
|
|
13856
14404
|
info?.(`AFT storage already migrated for ${opts.harness}; using ${newRoot}`);
|
|
13857
14405
|
return;
|
|
13858
14406
|
}
|
|
13859
|
-
if (!
|
|
14407
|
+
if (!existsSync5(legacyRoot)) {
|
|
13860
14408
|
info?.(`AFT storage migration skipped for ${opts.harness}: no legacy data at ${legacyRoot}; ` + `using ${newRoot} for fresh install`);
|
|
13861
14409
|
return;
|
|
13862
14410
|
}
|
|
@@ -13904,14 +14452,14 @@ async function ensureStorageMigrated(opts) {
|
|
|
13904
14452
|
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}` : ""));
|
|
13905
14453
|
}
|
|
13906
14454
|
// ../aft-bridge/dist/npm-resolver.js
|
|
13907
|
-
import { readdirSync, statSync as
|
|
13908
|
-
import { homedir as
|
|
13909
|
-
import { delimiter, dirname as dirname3, isAbsolute as
|
|
14455
|
+
import { readdirSync, statSync as statSync3 } from "node:fs";
|
|
14456
|
+
import { homedir as homedir8 } from "node:os";
|
|
14457
|
+
import { delimiter, dirname as dirname3, isAbsolute as isAbsolute3, join as join7 } from "node:path";
|
|
13910
14458
|
function defaultDeps() {
|
|
13911
14459
|
return {
|
|
13912
14460
|
platform: process.platform,
|
|
13913
14461
|
env: process.env,
|
|
13914
|
-
home:
|
|
14462
|
+
home: homedir8(),
|
|
13915
14463
|
execPath: process.execPath
|
|
13916
14464
|
};
|
|
13917
14465
|
}
|
|
@@ -13920,7 +14468,7 @@ function npmBinaryName(platform) {
|
|
|
13920
14468
|
}
|
|
13921
14469
|
function isFile(p) {
|
|
13922
14470
|
try {
|
|
13923
|
-
return
|
|
14471
|
+
return statSync3(p).isFile();
|
|
13924
14472
|
} catch {
|
|
13925
14473
|
return false;
|
|
13926
14474
|
}
|
|
@@ -13930,7 +14478,7 @@ function npmFromPath(deps) {
|
|
|
13930
14478
|
const raw = deps.env.PATH ?? deps.env.Path ?? "";
|
|
13931
14479
|
for (const entry of raw.split(delimiter)) {
|
|
13932
14480
|
const dir = entry.trim().replace(/^"|"$/g, "");
|
|
13933
|
-
if (!dir || !
|
|
14481
|
+
if (!dir || !isAbsolute3(dir))
|
|
13934
14482
|
continue;
|
|
13935
14483
|
if (isFile(join7(dir, name)))
|
|
13936
14484
|
return dir;
|
|
@@ -14020,8 +14568,8 @@ function npmSpawnEnv(resolved, baseEnv = process.env) {
|
|
|
14020
14568
|
// ../aft-bridge/dist/onnx-runtime.js
|
|
14021
14569
|
import { execFileSync } from "node:child_process";
|
|
14022
14570
|
import { createHash as createHash2 } from "node:crypto";
|
|
14023
|
-
import { chmodSync as chmodSync3, closeSync as
|
|
14024
|
-
import { basename, dirname as dirname4, isAbsolute as
|
|
14571
|
+
import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, readlinkSync, realpathSync, rmSync as rmSync3, statSync as statSync4, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
14572
|
+
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative2, resolve as resolve5, win32 } from "node:path";
|
|
14025
14573
|
import { Readable as Readable2 } from "node:stream";
|
|
14026
14574
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
14027
14575
|
var ORT_VERSION = "1.24.4";
|
|
@@ -14088,7 +14636,7 @@ async function ensureOnnxRuntime(storageDir) {
|
|
|
14088
14636
|
const libName = info?.libName ?? "libonnxruntime.dylib";
|
|
14089
14637
|
const resolvedOrtDir = resolveCachedOnnxRuntimeDir(ortVersionDir, libName);
|
|
14090
14638
|
const libPath = join8(resolvedOrtDir, libName);
|
|
14091
|
-
if (
|
|
14639
|
+
if (existsSync6(libPath)) {
|
|
14092
14640
|
const meta = readOnnxInstalledMeta(ortVersionDir);
|
|
14093
14641
|
if (meta?.sha256) {
|
|
14094
14642
|
try {
|
|
@@ -14150,7 +14698,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
14150
14698
|
abandoned = true;
|
|
14151
14699
|
} else {
|
|
14152
14700
|
try {
|
|
14153
|
-
const ageMs = Date.now() -
|
|
14701
|
+
const ageMs = Date.now() - statSync4(stagingDir).mtimeMs;
|
|
14154
14702
|
abandoned = ageMs > STALE_LOCK_MS;
|
|
14155
14703
|
} catch {
|
|
14156
14704
|
abandoned = true;
|
|
@@ -14165,7 +14713,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
14165
14713
|
if (abandoned) {
|
|
14166
14714
|
log(`[onnx] removing abandoned staging dir ${stagingDir}`);
|
|
14167
14715
|
try {
|
|
14168
|
-
|
|
14716
|
+
rmSync3(stagingDir, { recursive: true, force: true });
|
|
14169
14717
|
} catch (err) {
|
|
14170
14718
|
warn(`[onnx] failed to remove ${stagingDir}: ${err}`);
|
|
14171
14719
|
}
|
|
@@ -14175,9 +14723,9 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
14175
14723
|
}
|
|
14176
14724
|
function cleanupIncompleteTargetIfUnowned(ortDir) {
|
|
14177
14725
|
try {
|
|
14178
|
-
if (
|
|
14726
|
+
if (existsSync6(ortDir) && !existsSync6(join8(ortDir, ONNX_INSTALLED_META_FILE))) {
|
|
14179
14727
|
log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
|
|
14180
|
-
|
|
14728
|
+
rmSync3(ortDir, { recursive: true, force: true });
|
|
14181
14729
|
}
|
|
14182
14730
|
} catch (err) {
|
|
14183
14731
|
warn(`[onnx] failed to sweep ${ortDir}: ${err}`);
|
|
@@ -14187,7 +14735,7 @@ var REQUIRED_ORT_MAJOR = 1;
|
|
|
14187
14735
|
var REQUIRED_ORT_MIN_MINOR = 20;
|
|
14188
14736
|
var INVALID_ORT_VERSION = "<invalid>";
|
|
14189
14737
|
function parseOnnxVersionFromPath(value) {
|
|
14190
|
-
const name =
|
|
14738
|
+
const name = basename2(value);
|
|
14191
14739
|
const semverish = name.match(/(?:^|[._-])(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)(?:\.(?:dylib|dll))?$/);
|
|
14192
14740
|
if (semverish)
|
|
14193
14741
|
return semverish[1].split(/[-+]/, 1)[0];
|
|
@@ -14204,7 +14752,7 @@ function parseOnnxVersionFromDirectoryPath(value) {
|
|
|
14204
14752
|
}
|
|
14205
14753
|
function isPathInsideRoot(root, candidate) {
|
|
14206
14754
|
const rel = relative2(root, candidate);
|
|
14207
|
-
return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !
|
|
14755
|
+
return rel === "" || !rel.startsWith("../") && !rel.startsWith("..\\") && rel !== ".." && !isAbsolute4(rel) && !win32.isAbsolute(rel);
|
|
14208
14756
|
}
|
|
14209
14757
|
function detectOnnxVersion(libDir, libName) {
|
|
14210
14758
|
try {
|
|
@@ -14220,7 +14768,7 @@ function detectOnnxVersion(libDir, libName) {
|
|
|
14220
14768
|
return version;
|
|
14221
14769
|
}
|
|
14222
14770
|
const base = join8(libDir, libName);
|
|
14223
|
-
if (
|
|
14771
|
+
if (existsSync6(base)) {
|
|
14224
14772
|
try {
|
|
14225
14773
|
const real = realpathSync(base);
|
|
14226
14774
|
const version = parseOnnxVersionFromPath(real) ?? parseOnnxVersionFromDirectoryPath(real);
|
|
@@ -14255,7 +14803,7 @@ function pathEntriesForPlatform() {
|
|
|
14255
14803
|
return pathEnvValue().split(delimiter2).map((entry) => entry.trim().replace(/^"|"$/g, "")).filter((entry) => {
|
|
14256
14804
|
if (!entry || entry === "." || entry.includes("\x00"))
|
|
14257
14805
|
return false;
|
|
14258
|
-
return
|
|
14806
|
+
return isAbsolute4(entry) || win32.isAbsolute(entry);
|
|
14259
14807
|
});
|
|
14260
14808
|
}
|
|
14261
14809
|
function directoryContainsLibrary(dir, libName) {
|
|
@@ -14271,10 +14819,10 @@ function directoryContainsLibrary(dir, libName) {
|
|
|
14271
14819
|
}
|
|
14272
14820
|
}
|
|
14273
14821
|
function resolveCachedOnnxRuntimeDir(ortVersionDir, libName) {
|
|
14274
|
-
if (
|
|
14822
|
+
if (existsSync6(join8(ortVersionDir, libName)))
|
|
14275
14823
|
return ortVersionDir;
|
|
14276
14824
|
const libSubdir = join8(ortVersionDir, "lib");
|
|
14277
|
-
if (
|
|
14825
|
+
if (existsSync6(join8(libSubdir, libName)))
|
|
14278
14826
|
return libSubdir;
|
|
14279
14827
|
return ortVersionDir;
|
|
14280
14828
|
}
|
|
@@ -14295,7 +14843,7 @@ function findSystemOnnxRuntime(libName) {
|
|
|
14295
14843
|
if (!userProfile)
|
|
14296
14844
|
return nugetPaths;
|
|
14297
14845
|
const nugetPackageDir = join8(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
|
|
14298
|
-
if (!
|
|
14846
|
+
if (!existsSync6(nugetPackageDir))
|
|
14299
14847
|
return nugetPaths;
|
|
14300
14848
|
try {
|
|
14301
14849
|
for (const entry of readdirSync2(nugetPackageDir, { withFileTypes: true })) {
|
|
@@ -14315,7 +14863,7 @@ function findSystemOnnxRuntime(libName) {
|
|
|
14315
14863
|
const normalizeCase = process.platform === "win32" || process.platform === "darwin";
|
|
14316
14864
|
const seen = new Set;
|
|
14317
14865
|
const uniquePaths = searchPaths.filter((p) => {
|
|
14318
|
-
let key =
|
|
14866
|
+
let key = resolve5(p).replace(/[/\\]+$/, "");
|
|
14319
14867
|
if (normalizeCase)
|
|
14320
14868
|
key = key.toLowerCase();
|
|
14321
14869
|
if (seen.has(key))
|
|
@@ -14329,7 +14877,7 @@ function findSystemOnnxRuntime(libName) {
|
|
|
14329
14877
|
if (process.platform === "win32") {
|
|
14330
14878
|
if (!directoryContainsLibrary(dir, libName))
|
|
14331
14879
|
continue;
|
|
14332
|
-
} else if (!
|
|
14880
|
+
} else if (!existsSync6(libPath)) {
|
|
14333
14881
|
continue;
|
|
14334
14882
|
}
|
|
14335
14883
|
const version = detectOnnxVersion(dir, libName);
|
|
@@ -14378,7 +14926,7 @@ async function downloadFileWithCap(url, destPath) {
|
|
|
14378
14926
|
await pipeline2(nodeStream, createWriteStream2(destPath), { signal: controller.signal });
|
|
14379
14927
|
} catch (err) {
|
|
14380
14928
|
try {
|
|
14381
|
-
|
|
14929
|
+
unlinkSync4(destPath);
|
|
14382
14930
|
} catch {}
|
|
14383
14931
|
throw err;
|
|
14384
14932
|
} finally {
|
|
@@ -14395,15 +14943,15 @@ function validateExtractedTree(stagingRoot) {
|
|
|
14395
14943
|
const lst = lstatSync(fullPath);
|
|
14396
14944
|
if (lst.isSymbolicLink()) {
|
|
14397
14945
|
const linkTarget = readlinkSync(fullPath);
|
|
14398
|
-
const resolvedTarget =
|
|
14946
|
+
const resolvedTarget = resolve5(dirname4(fullPath), linkTarget);
|
|
14399
14947
|
const rel2 = relative2(realRoot, resolvedTarget);
|
|
14400
|
-
if (rel2.startsWith("..") ||
|
|
14948
|
+
if (rel2.startsWith("..") || isAbsolute4(rel2) || win32.isAbsolute(rel2)) {
|
|
14401
14949
|
throw new Error(`extracted symlink ${fullPath} points outside staging root: ${linkTarget}`);
|
|
14402
14950
|
}
|
|
14403
14951
|
continue;
|
|
14404
14952
|
}
|
|
14405
14953
|
const rel = relative2(realRoot, fullPath);
|
|
14406
|
-
if (rel.startsWith("..") ||
|
|
14954
|
+
if (rel.startsWith("..") || isAbsolute4(rel) || win32.isAbsolute(rel)) {
|
|
14407
14955
|
throw new Error(`extracted entry ${fullPath} escapes staging root`);
|
|
14408
14956
|
}
|
|
14409
14957
|
if (lst.isDirectory()) {
|
|
@@ -14439,11 +14987,11 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
14439
14987
|
await extractZipArchive(archivePath, tmpDir);
|
|
14440
14988
|
}
|
|
14441
14989
|
try {
|
|
14442
|
-
|
|
14990
|
+
unlinkSync4(archivePath);
|
|
14443
14991
|
} catch {}
|
|
14444
14992
|
validateExtractedTree(tmpDir);
|
|
14445
14993
|
const extractedDir = join8(tmpDir, info.assetName, "lib");
|
|
14446
|
-
if (!
|
|
14994
|
+
if (!existsSync6(extractedDir)) {
|
|
14447
14995
|
throw new Error(`Expected directory not found: ${extractedDir}`);
|
|
14448
14996
|
}
|
|
14449
14997
|
mkdirSync5(targetDir, { recursive: true });
|
|
@@ -14474,16 +15022,16 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
14474
15022
|
warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
|
|
14475
15023
|
}
|
|
14476
15024
|
writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
|
|
14477
|
-
|
|
15025
|
+
rmSync3(tmpDir, { recursive: true, force: true });
|
|
14478
15026
|
log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
|
|
14479
15027
|
return targetDir;
|
|
14480
15028
|
} catch (err) {
|
|
14481
15029
|
error(`Failed to download ONNX Runtime: ${err}`);
|
|
14482
15030
|
try {
|
|
14483
|
-
|
|
15031
|
+
rmSync3(tmpDir, { recursive: true, force: true });
|
|
14484
15032
|
} catch {}
|
|
14485
15033
|
try {
|
|
14486
|
-
|
|
15034
|
+
rmSync3(targetDir, { recursive: true, force: true });
|
|
14487
15035
|
} catch {}
|
|
14488
15036
|
return null;
|
|
14489
15037
|
}
|
|
@@ -14500,7 +15048,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
14500
15048
|
}
|
|
14501
15049
|
} catch (copyErr) {
|
|
14502
15050
|
if (requiredLibs.has(libFile)) {
|
|
14503
|
-
|
|
15051
|
+
rmSync3(targetDir, { recursive: true, force: true });
|
|
14504
15052
|
throw copyErr;
|
|
14505
15053
|
}
|
|
14506
15054
|
log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
|
|
@@ -14510,14 +15058,14 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
14510
15058
|
for (const link of symlinks) {
|
|
14511
15059
|
const dst = join8(targetDir, link.name);
|
|
14512
15060
|
try {
|
|
14513
|
-
|
|
15061
|
+
unlinkSync4(dst);
|
|
14514
15062
|
} catch {}
|
|
14515
15063
|
const dstForContainment = join8(targetRoot, link.name);
|
|
14516
|
-
const resolvedTarget =
|
|
15064
|
+
const resolvedTarget = resolve5(dirname4(dstForContainment), link.target);
|
|
14517
15065
|
if (!isPathInsideRoot(targetRoot, resolvedTarget)) {
|
|
14518
15066
|
const message = `ONNX Runtime symlink ${link.name} points outside install dir: ${link.target}`;
|
|
14519
15067
|
if (requiredLibs.has(link.name)) {
|
|
14520
|
-
|
|
15068
|
+
rmSync3(targetDir, { recursive: true, force: true });
|
|
14521
15069
|
throw new Error(message);
|
|
14522
15070
|
}
|
|
14523
15071
|
log(`ORT extract: skipping optional symlink ${link.name}: ${message}`);
|
|
@@ -14527,15 +15075,15 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
14527
15075
|
symlinkSync(link.target, dst);
|
|
14528
15076
|
} catch (symlinkErr) {
|
|
14529
15077
|
if (requiredLibs.has(link.name)) {
|
|
14530
|
-
|
|
15078
|
+
rmSync3(targetDir, { recursive: true, force: true });
|
|
14531
15079
|
throw symlinkErr;
|
|
14532
15080
|
}
|
|
14533
15081
|
log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
|
|
14534
15082
|
}
|
|
14535
15083
|
}
|
|
14536
15084
|
const requiredPath = join8(targetDir, info.libName);
|
|
14537
|
-
if (!
|
|
14538
|
-
|
|
15085
|
+
if (!existsSync6(requiredPath)) {
|
|
15086
|
+
rmSync3(targetDir, { recursive: true, force: true });
|
|
14539
15087
|
throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
|
|
14540
15088
|
}
|
|
14541
15089
|
}
|
|
@@ -14560,7 +15108,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
|
|
|
14560
15108
|
...sha256 ? { sha256 } : {},
|
|
14561
15109
|
archiveSha256
|
|
14562
15110
|
};
|
|
14563
|
-
|
|
15111
|
+
writeFileSync3(join8(installDir, ONNX_INSTALLED_META_FILE), JSON.stringify(meta), "utf8");
|
|
14564
15112
|
} catch (err) {
|
|
14565
15113
|
log(`[onnx] failed to write installed-meta in ${installDir}: ${err}`);
|
|
14566
15114
|
}
|
|
@@ -14568,9 +15116,9 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
|
|
|
14568
15116
|
function readOnnxInstalledMeta(installDir) {
|
|
14569
15117
|
const path2 = join8(installDir, ONNX_INSTALLED_META_FILE);
|
|
14570
15118
|
try {
|
|
14571
|
-
if (!
|
|
15119
|
+
if (!statSync4(path2).isFile())
|
|
14572
15120
|
return null;
|
|
14573
|
-
const raw =
|
|
15121
|
+
const raw = readFileSync5(path2, "utf8");
|
|
14574
15122
|
const parsed = JSON.parse(raw);
|
|
14575
15123
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
14576
15124
|
return null;
|
|
@@ -14586,19 +15134,19 @@ function readOnnxInstalledMeta(installDir) {
|
|
|
14586
15134
|
}
|
|
14587
15135
|
function sha256File(path2) {
|
|
14588
15136
|
const hash = createHash2("sha256");
|
|
14589
|
-
hash.update(
|
|
15137
|
+
hash.update(readFileSync5(path2));
|
|
14590
15138
|
return hash.digest("hex");
|
|
14591
15139
|
}
|
|
14592
15140
|
function acquireLock(lockPath) {
|
|
14593
15141
|
const tryClaim = () => {
|
|
14594
15142
|
try {
|
|
14595
|
-
const fd =
|
|
15143
|
+
const fd = openSync4(lockPath, "wx");
|
|
14596
15144
|
try {
|
|
14597
|
-
|
|
15145
|
+
writeFileSync3(fd, `${process.pid}
|
|
14598
15146
|
${new Date().toISOString()}
|
|
14599
15147
|
`);
|
|
14600
15148
|
} finally {
|
|
14601
|
-
|
|
15149
|
+
closeSync4(fd);
|
|
14602
15150
|
}
|
|
14603
15151
|
return true;
|
|
14604
15152
|
} catch (err) {
|
|
@@ -14614,12 +15162,12 @@ ${new Date().toISOString()}
|
|
|
14614
15162
|
let owningPid = null;
|
|
14615
15163
|
let lockMtimeMs = 0;
|
|
14616
15164
|
try {
|
|
14617
|
-
const raw =
|
|
15165
|
+
const raw = readFileSync5(lockPath, "utf8");
|
|
14618
15166
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
14619
15167
|
const parsed = Number.parseInt(firstLine, 10);
|
|
14620
15168
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
14621
15169
|
owningPid = parsed;
|
|
14622
|
-
lockMtimeMs =
|
|
15170
|
+
lockMtimeMs = statSync4(lockPath).mtimeMs;
|
|
14623
15171
|
} catch {
|
|
14624
15172
|
return tryClaim();
|
|
14625
15173
|
}
|
|
@@ -14629,637 +15177,123 @@ ${new Date().toISOString()}
|
|
|
14629
15177
|
if (ownerAlive && ageWithinFresh) {
|
|
14630
15178
|
return false;
|
|
14631
15179
|
}
|
|
14632
|
-
log(`[onnx] reclaiming install lock (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
|
|
14633
|
-
try {
|
|
14634
|
-
|
|
14635
|
-
} catch {}
|
|
14636
|
-
return tryClaim();
|
|
14637
|
-
}
|
|
14638
|
-
function releaseLock(lockPath) {
|
|
14639
|
-
try {
|
|
14640
|
-
let owningPid = null;
|
|
14641
|
-
try {
|
|
14642
|
-
const raw = readFileSync3(lockPath, "utf8");
|
|
14643
|
-
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
14644
|
-
const parsed = Number.parseInt(firstLine, 10);
|
|
14645
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
14646
|
-
owningPid = parsed;
|
|
14647
|
-
} catch (readErr) {
|
|
14648
|
-
const code = readErr.code;
|
|
14649
|
-
if (code === "ENOENT")
|
|
14650
|
-
return;
|
|
14651
|
-
warn(`[onnx] could not read lock ${lockPath} during release: ${readErr}`);
|
|
14652
|
-
return;
|
|
14653
|
-
}
|
|
14654
|
-
if (owningPid !== process.pid) {
|
|
14655
|
-
log(`[onnx] not releasing lock ${lockPath}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
|
|
14656
|
-
return;
|
|
14657
|
-
}
|
|
14658
|
-
try {
|
|
14659
|
-
unlinkSync3(lockPath);
|
|
14660
|
-
} catch (unlinkErr) {
|
|
14661
|
-
const code = unlinkErr.code;
|
|
14662
|
-
if (code !== "ENOENT") {
|
|
14663
|
-
warn(`[onnx] failed to release lock ${lockPath}: ${unlinkErr}`);
|
|
14664
|
-
}
|
|
14665
|
-
}
|
|
14666
|
-
} catch (err) {
|
|
14667
|
-
warn(`[onnx] unexpected error releasing lock ${lockPath}: ${err}`);
|
|
14668
|
-
}
|
|
14669
|
-
}
|
|
14670
|
-
function tasklistPidFromCsvLine(line) {
|
|
14671
|
-
const quoted = line.match(/"([^"]*)"/g);
|
|
14672
|
-
if (quoted && quoted.length >= 2)
|
|
14673
|
-
return quoted[1].slice(1, -1);
|
|
14674
|
-
const cells = line.split(",").map((cell) => cell.trim().replace(/^"|"$/g, ""));
|
|
14675
|
-
return cells[1] ?? null;
|
|
14676
|
-
}
|
|
14677
|
-
function isWindowsProcessAlive(pid) {
|
|
14678
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
14679
|
-
return false;
|
|
14680
|
-
try {
|
|
14681
|
-
const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
|
|
14682
|
-
encoding: "utf8",
|
|
14683
|
-
timeout: 2000,
|
|
14684
|
-
windowsHide: true
|
|
14685
|
-
});
|
|
14686
|
-
const expected = String(pid);
|
|
14687
|
-
return output.split(/\r?\n/).some((line) => tasklistPidFromCsvLine(line) === expected);
|
|
14688
|
-
} catch {
|
|
14689
|
-
return false;
|
|
14690
|
-
}
|
|
14691
|
-
}
|
|
14692
|
-
function isProcessAlive(pid) {
|
|
14693
|
-
if (process.platform === "win32")
|
|
14694
|
-
return isWindowsProcessAlive(pid);
|
|
14695
|
-
try {
|
|
14696
|
-
process.kill(pid, 0);
|
|
14697
|
-
return true;
|
|
14698
|
-
} catch (err) {
|
|
14699
|
-
const code = err.code;
|
|
14700
|
-
if (code === "ESRCH")
|
|
14701
|
-
return false;
|
|
14702
|
-
return true;
|
|
14703
|
-
}
|
|
14704
|
-
}
|
|
14705
|
-
// ../aft-bridge/dist/pipe-strip.js
|
|
14706
|
-
var NOISE_FILTERS = new Set([
|
|
14707
|
-
"grep",
|
|
14708
|
-
"rg",
|
|
14709
|
-
"head",
|
|
14710
|
-
"tail",
|
|
14711
|
-
"cat",
|
|
14712
|
-
"less",
|
|
14713
|
-
"more",
|
|
14714
|
-
"sed",
|
|
14715
|
-
"awk",
|
|
14716
|
-
"cut",
|
|
14717
|
-
"sort",
|
|
14718
|
-
"uniq",
|
|
14719
|
-
"tr",
|
|
14720
|
-
"column",
|
|
14721
|
-
"fold"
|
|
14722
|
-
]);
|
|
14723
|
-
var GREP_GUARD_FLAGS = new Set([
|
|
14724
|
-
"c",
|
|
14725
|
-
"count",
|
|
14726
|
-
"q",
|
|
14727
|
-
"quiet",
|
|
14728
|
-
"o",
|
|
14729
|
-
"only-matching",
|
|
14730
|
-
"l",
|
|
14731
|
-
"files-with-matches"
|
|
14732
|
-
]);
|
|
14733
|
-
function maybeStripCompressorPipe(command, compressionEnabled) {
|
|
14734
|
-
if (!compressionEnabled)
|
|
14735
|
-
return { command, stripped: false };
|
|
14736
|
-
const chain = splitTopLevelCommandChain(command);
|
|
14737
|
-
if (chain === null)
|
|
14738
|
-
return { command, stripped: false };
|
|
14739
|
-
let stripped = false;
|
|
14740
|
-
const droppedFilterChains = [];
|
|
14741
|
-
const rebuilt = chain.map(({ segment, separator }) => {
|
|
14742
|
-
const result = stripSinglePipelineSegment(segment);
|
|
14743
|
-
if (result.stripped) {
|
|
14744
|
-
stripped = true;
|
|
14745
|
-
droppedFilterChains.push(result.filters);
|
|
14746
|
-
}
|
|
14747
|
-
return `${result.segment}${separator}`;
|
|
14748
|
-
}).join("");
|
|
14749
|
-
if (!stripped)
|
|
14750
|
-
return { command, stripped: false };
|
|
14751
|
-
return {
|
|
14752
|
-
command: rebuilt,
|
|
14753
|
-
stripped: true,
|
|
14754
|
-
note: formatStripNote(droppedFilterChains)
|
|
14755
|
-
};
|
|
14756
|
-
}
|
|
14757
|
-
function stripSinglePipelineSegment(segment) {
|
|
14758
|
-
const leading = /^\s*/.exec(segment)?.[0] ?? "";
|
|
14759
|
-
const trailing = /\s*$/.exec(segment)?.[0] ?? "";
|
|
14760
|
-
const coreStart = leading.length;
|
|
14761
|
-
const coreEnd = segment.length - trailing.length;
|
|
14762
|
-
if (coreEnd <= coreStart)
|
|
14763
|
-
return { segment, stripped: false };
|
|
14764
|
-
const core = segment.slice(coreStart, coreEnd);
|
|
14765
|
-
if (containsUnsplittableConstruct(core))
|
|
14766
|
-
return { segment, stripped: false };
|
|
14767
|
-
if (hasUnquotedBackground(core))
|
|
14768
|
-
return { segment, stripped: false };
|
|
14769
|
-
const stages = splitTopLevelPipeline(core);
|
|
14770
|
-
if (stages.length < 2)
|
|
14771
|
-
return { segment, stripped: false };
|
|
14772
|
-
const firstStage = stages[0]?.trim() ?? "";
|
|
14773
|
-
if (!isCompressorHandledRunner(firstStage))
|
|
14774
|
-
return { segment, stripped: false };
|
|
14775
|
-
const filterStages = stages.slice(1).map((stage) => stage.trim());
|
|
14776
|
-
for (const stage of filterStages) {
|
|
14777
|
-
if (!filterStageIsSafeToDrop(stage))
|
|
14778
|
-
return { segment, stripped: false };
|
|
14779
|
-
}
|
|
14780
|
-
return {
|
|
14781
|
-
segment: `${leading}${firstStage}${trailing}`,
|
|
14782
|
-
stripped: true,
|
|
14783
|
-
filters: filterStages.join(" | ")
|
|
14784
|
-
};
|
|
14785
|
-
}
|
|
14786
|
-
function formatStripNote(droppedFilterChains) {
|
|
14787
|
-
const filters = droppedFilterChains.map((filter) => `\`| ${filter}\``).join(", ");
|
|
14788
|
-
return `[AFT dropped ${filters} (compressed:false to keep)]`;
|
|
14789
|
-
}
|
|
14790
|
-
function splitTopLevelCommandChain(command) {
|
|
14791
|
-
const segments = [];
|
|
14792
|
-
let start = 0;
|
|
14793
|
-
let quote = null;
|
|
14794
|
-
let escaped = false;
|
|
14795
|
-
let inBacktick = false;
|
|
14796
|
-
let parenDepth = 0;
|
|
14797
|
-
for (let index = 0;index < command.length; index++) {
|
|
14798
|
-
const char = command[index];
|
|
14799
|
-
const next = command[index + 1];
|
|
14800
|
-
if (escaped) {
|
|
14801
|
-
escaped = false;
|
|
14802
|
-
continue;
|
|
14803
|
-
}
|
|
14804
|
-
if (inBacktick) {
|
|
14805
|
-
if (char === "\\")
|
|
14806
|
-
escaped = true;
|
|
14807
|
-
else if (char === "`")
|
|
14808
|
-
inBacktick = false;
|
|
14809
|
-
continue;
|
|
14810
|
-
}
|
|
14811
|
-
if (char === "\\" && quote !== "'") {
|
|
14812
|
-
escaped = true;
|
|
14813
|
-
continue;
|
|
14814
|
-
}
|
|
14815
|
-
if (quote) {
|
|
14816
|
-
if (char === quote)
|
|
14817
|
-
quote = null;
|
|
14818
|
-
continue;
|
|
14819
|
-
}
|
|
14820
|
-
if (char === "'" || char === '"') {
|
|
14821
|
-
quote = char;
|
|
14822
|
-
continue;
|
|
14823
|
-
}
|
|
14824
|
-
if (char === "`") {
|
|
14825
|
-
inBacktick = true;
|
|
14826
|
-
continue;
|
|
14827
|
-
}
|
|
14828
|
-
if (char === "(") {
|
|
14829
|
-
parenDepth++;
|
|
14830
|
-
continue;
|
|
14831
|
-
}
|
|
14832
|
-
if (char === ")") {
|
|
14833
|
-
if (parenDepth === 0)
|
|
14834
|
-
return null;
|
|
14835
|
-
parenDepth--;
|
|
14836
|
-
continue;
|
|
14837
|
-
}
|
|
14838
|
-
if (parenDepth > 0)
|
|
14839
|
-
continue;
|
|
14840
|
-
if (char === `
|
|
14841
|
-
` || char === "\r")
|
|
14842
|
-
return null;
|
|
14843
|
-
if (char === "#" && (index === 0 || command[index - 1] === " " || command[index - 1] === "\t"))
|
|
14844
|
-
return null;
|
|
14845
|
-
if (char === "&" && next === "&") {
|
|
14846
|
-
segments.push({ segment: command.slice(start, index), separator: "&&" });
|
|
14847
|
-
start = index + 2;
|
|
14848
|
-
index++;
|
|
14849
|
-
continue;
|
|
14850
|
-
}
|
|
14851
|
-
if (char === "|" && next === "|") {
|
|
14852
|
-
segments.push({ segment: command.slice(start, index), separator: "||" });
|
|
14853
|
-
start = index + 2;
|
|
14854
|
-
index++;
|
|
14855
|
-
continue;
|
|
14856
|
-
}
|
|
14857
|
-
if (char === ";") {
|
|
14858
|
-
segments.push({ segment: command.slice(start, index), separator: ";" });
|
|
14859
|
-
start = index + 1;
|
|
14860
|
-
}
|
|
14861
|
-
}
|
|
14862
|
-
if (escaped || quote || inBacktick || parenDepth !== 0)
|
|
14863
|
-
return null;
|
|
14864
|
-
segments.push({ segment: command.slice(start), separator: "" });
|
|
14865
|
-
return segments;
|
|
14866
|
-
}
|
|
14867
|
-
function splitTopLevelPipeline(command) {
|
|
14868
|
-
const stages = [];
|
|
14869
|
-
let start = 0;
|
|
14870
|
-
let quote = null;
|
|
14871
|
-
let escaped = false;
|
|
14872
|
-
for (let index = 0;index < command.length; index++) {
|
|
14873
|
-
const char = command[index];
|
|
14874
|
-
const next = command[index + 1];
|
|
14875
|
-
const previous = command[index - 1];
|
|
14876
|
-
if (escaped) {
|
|
14877
|
-
escaped = false;
|
|
14878
|
-
continue;
|
|
14879
|
-
}
|
|
14880
|
-
if (char === "\\" && quote !== "'") {
|
|
14881
|
-
escaped = true;
|
|
14882
|
-
continue;
|
|
14883
|
-
}
|
|
14884
|
-
if (quote) {
|
|
14885
|
-
if (char === quote)
|
|
14886
|
-
quote = null;
|
|
14887
|
-
continue;
|
|
14888
|
-
}
|
|
14889
|
-
if (char === "'" || char === '"') {
|
|
14890
|
-
quote = char;
|
|
14891
|
-
continue;
|
|
14892
|
-
}
|
|
14893
|
-
if (char === "|" && previous !== "|" && next !== "|") {
|
|
14894
|
-
stages.push(command.slice(start, index));
|
|
14895
|
-
start = index + 1;
|
|
14896
|
-
}
|
|
14897
|
-
}
|
|
14898
|
-
stages.push(command.slice(start));
|
|
14899
|
-
return stages;
|
|
14900
|
-
}
|
|
14901
|
-
function isCompressorHandledRunner(stage) {
|
|
14902
|
-
const tokens = tokenizeStage(stage);
|
|
14903
|
-
if (tokens.length === 0)
|
|
14904
|
-
return false;
|
|
14905
|
-
if (tokens.some((token) => token === "&&" || token === "||" || token.includes(";"))) {
|
|
14906
|
-
return false;
|
|
14907
|
-
}
|
|
14908
|
-
let tokenOffset = 0;
|
|
14909
|
-
while (tokenOffset < tokens.length && isEnvAssignment(tokens[tokenOffset])) {
|
|
14910
|
-
tokenOffset++;
|
|
14911
|
-
}
|
|
14912
|
-
const first = runnerName(tokens[tokenOffset]);
|
|
14913
|
-
const runnerArgs = tokens.slice(tokenOffset + 1);
|
|
14914
|
-
const second = runnerArgs[0];
|
|
14915
|
-
const third = runnerArgs[1];
|
|
14916
|
-
const rest = runnerArgs;
|
|
14917
|
-
if (!first)
|
|
14918
|
-
return false;
|
|
14919
|
-
if (first === "bun") {
|
|
14920
|
-
let args = rest;
|
|
14921
|
-
if (args[0] === "--cwd")
|
|
14922
|
-
args = args.slice(2);
|
|
14923
|
-
else if (args[0]?.startsWith("--cwd="))
|
|
14924
|
-
args = args.slice(1);
|
|
14925
|
-
const sub = args[0];
|
|
14926
|
-
const subNext = args[1];
|
|
14927
|
-
return sub === "test" || sub === "run" && isJsVerificationScript(subNext);
|
|
14928
|
-
}
|
|
14929
|
-
if (first === "npm" || first === "pnpm") {
|
|
14930
|
-
return second === "test" || second === "run" && isJsVerificationScript(third);
|
|
14931
|
-
}
|
|
14932
|
-
if (first === "yarn") {
|
|
14933
|
-
return isJsVerificationScript(second) || second === "run" && isJsVerificationScript(third);
|
|
14934
|
-
}
|
|
14935
|
-
if (first === "deno")
|
|
14936
|
-
return ["test", "lint", "check", "bench"].includes(second ?? "");
|
|
14937
|
-
if (first === "npx") {
|
|
14938
|
-
return ["tsc", "eslint", "vitest", "jest", "playwright", "biome"].includes(second ?? "");
|
|
14939
|
-
}
|
|
14940
|
-
if (first === "playwright")
|
|
14941
|
-
return second === "test";
|
|
14942
|
-
if (first === "cargo") {
|
|
14943
|
-
return ["test", "build", "check", "clippy", "nextest"].includes(second ?? "");
|
|
14944
|
-
}
|
|
14945
|
-
if (first === "go")
|
|
14946
|
-
return ["test", "build", "vet"].includes(second ?? "");
|
|
14947
|
-
if (first === "gradle" || first === "gradlew") {
|
|
14948
|
-
return hasBuildTask(rest, ["test", "check", "build", "assemble", "clean"]);
|
|
14949
|
-
}
|
|
14950
|
-
if (first === "mvn" || first === "mvnw") {
|
|
14951
|
-
return hasBuildTask(rest, ["test", "verify", "package", "install", "clean"]);
|
|
14952
|
-
}
|
|
14953
|
-
if (first === "dotnet")
|
|
14954
|
-
return ["test", "build"].includes(second ?? "");
|
|
14955
|
-
if (first === "rspec")
|
|
14956
|
-
return true;
|
|
14957
|
-
if (first === "rake") {
|
|
14958
|
-
const positionals = rest.filter((a) => !a.startsWith("-"));
|
|
14959
|
-
if (positionals.length === 0)
|
|
14960
|
-
return false;
|
|
14961
|
-
if (positionals.some((a) => a.includes("/") || a.includes(".") || a.includes("=")))
|
|
14962
|
-
return false;
|
|
14963
|
-
return positionals.some((a) => a === "test" || a === "spec");
|
|
14964
|
-
}
|
|
14965
|
-
if (first === "phpunit" || first === "pest")
|
|
14966
|
-
return true;
|
|
14967
|
-
if (first === "xcodebuild")
|
|
14968
|
-
return xcodebuildHasBuildAction(rest);
|
|
14969
|
-
if (first === "swift")
|
|
14970
|
-
return second === "test" || second === "build";
|
|
14971
|
-
if (first === "make" || first === "gmake") {
|
|
14972
|
-
return hasBuildTask(rest, ["test", "check", "lint", "clean"]);
|
|
14973
|
-
}
|
|
14974
|
-
return [
|
|
14975
|
-
"vitest",
|
|
14976
|
-
"jest",
|
|
14977
|
-
"pytest",
|
|
14978
|
-
"tsc",
|
|
14979
|
-
"eslint",
|
|
14980
|
-
"biome",
|
|
14981
|
-
"ruff",
|
|
14982
|
-
"mypy",
|
|
14983
|
-
"tox",
|
|
14984
|
-
"nox"
|
|
14985
|
-
].includes(first);
|
|
14986
|
-
}
|
|
14987
|
-
function isEnvAssignment(token) {
|
|
14988
|
-
if (!token)
|
|
14989
|
-
return false;
|
|
14990
|
-
return /^[a-zA-Z_][a-zA-Z0-9_]*=/.test(token);
|
|
14991
|
-
}
|
|
14992
|
-
function runnerName(token) {
|
|
14993
|
-
if (!token)
|
|
14994
|
-
return "";
|
|
14995
|
-
const slash = token.lastIndexOf("/");
|
|
14996
|
-
return slash === -1 ? token : token.slice(slash + 1);
|
|
14997
|
-
}
|
|
14998
|
-
function hasBuildTask(args, tasks) {
|
|
14999
|
-
const isAllowedTask = (arg) => tasks.some((task) => arg === task || arg.endsWith(`:${task}`));
|
|
15000
|
-
const isFlagOrProperty = (arg) => arg.startsWith("-") || arg.includes("=");
|
|
15001
|
-
let sawAllowed = false;
|
|
15002
|
-
for (const arg of args) {
|
|
15003
|
-
if (isFlagOrProperty(arg))
|
|
15004
|
-
continue;
|
|
15005
|
-
if (!isAllowedTask(arg))
|
|
15006
|
-
return false;
|
|
15007
|
-
sawAllowed = true;
|
|
15008
|
-
}
|
|
15009
|
-
return sawAllowed;
|
|
15010
|
-
}
|
|
15011
|
-
function isJsVerificationScript(token) {
|
|
15012
|
-
if (!token)
|
|
15013
|
-
return false;
|
|
15014
|
-
return token.startsWith("test") || token === "typecheck" || token.startsWith("typecheck:");
|
|
15015
|
-
}
|
|
15016
|
-
var XCODEBUILD_VALUE_FLAGS = new Set([
|
|
15017
|
-
"-scheme",
|
|
15018
|
-
"-target",
|
|
15019
|
-
"-project",
|
|
15020
|
-
"-workspace",
|
|
15021
|
-
"-configuration",
|
|
15022
|
-
"-sdk",
|
|
15023
|
-
"-destination",
|
|
15024
|
-
"-arch",
|
|
15025
|
-
"-derivedDataPath",
|
|
15026
|
-
"-resultBundlePath",
|
|
15027
|
-
"-xcconfig",
|
|
15028
|
-
"-toolchain"
|
|
15029
|
-
]);
|
|
15030
|
-
var XCODEBUILD_BUILD_ACTIONS = new Set([
|
|
15031
|
-
"build",
|
|
15032
|
-
"test",
|
|
15033
|
-
"build-for-testing",
|
|
15034
|
-
"test-without-building",
|
|
15035
|
-
"analyze"
|
|
15036
|
-
]);
|
|
15037
|
-
function xcodebuildHasBuildAction(args) {
|
|
15038
|
-
for (let i = 0;i < args.length; i++) {
|
|
15039
|
-
const arg = args[i];
|
|
15040
|
-
if (arg.startsWith("-")) {
|
|
15041
|
-
if (XCODEBUILD_VALUE_FLAGS.has(arg))
|
|
15042
|
-
i++;
|
|
15043
|
-
continue;
|
|
15044
|
-
}
|
|
15045
|
-
if (XCODEBUILD_BUILD_ACTIONS.has(arg))
|
|
15046
|
-
return true;
|
|
15047
|
-
}
|
|
15048
|
-
return false;
|
|
15180
|
+
log(`[onnx] reclaiming install lock (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
|
|
15181
|
+
try {
|
|
15182
|
+
unlinkSync4(lockPath);
|
|
15183
|
+
} catch {}
|
|
15184
|
+
return tryClaim();
|
|
15049
15185
|
}
|
|
15050
|
-
function
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
quote = null;
|
|
15066
|
-
continue;
|
|
15186
|
+
function releaseLock(lockPath) {
|
|
15187
|
+
try {
|
|
15188
|
+
let owningPid = null;
|
|
15189
|
+
try {
|
|
15190
|
+
const raw = readFileSync5(lockPath, "utf8");
|
|
15191
|
+
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
15192
|
+
const parsed = Number.parseInt(firstLine, 10);
|
|
15193
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
15194
|
+
owningPid = parsed;
|
|
15195
|
+
} catch (readErr) {
|
|
15196
|
+
const code = readErr.code;
|
|
15197
|
+
if (code === "ENOENT")
|
|
15198
|
+
return;
|
|
15199
|
+
warn(`[onnx] could not read lock ${lockPath} during release: ${readErr}`);
|
|
15200
|
+
return;
|
|
15067
15201
|
}
|
|
15068
|
-
if (
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
else if (char === "`")
|
|
15072
|
-
return true;
|
|
15073
|
-
else if (char === "$" && command[i + 1] === "(")
|
|
15074
|
-
return true;
|
|
15075
|
-
continue;
|
|
15202
|
+
if (owningPid !== process.pid) {
|
|
15203
|
+
log(`[onnx] not releasing lock ${lockPath}: owned by pid ${owningPid ?? "unknown"} (we are ${process.pid})`);
|
|
15204
|
+
return;
|
|
15076
15205
|
}
|
|
15077
|
-
|
|
15078
|
-
|
|
15079
|
-
|
|
15206
|
+
try {
|
|
15207
|
+
unlinkSync4(lockPath);
|
|
15208
|
+
} catch (unlinkErr) {
|
|
15209
|
+
const code = unlinkErr.code;
|
|
15210
|
+
if (code !== "ENOENT") {
|
|
15211
|
+
warn(`[onnx] failed to release lock ${lockPath}: ${unlinkErr}`);
|
|
15212
|
+
}
|
|
15080
15213
|
}
|
|
15081
|
-
|
|
15082
|
-
|
|
15083
|
-
if (char === "(" || char === ")")
|
|
15084
|
-
return true;
|
|
15214
|
+
} catch (err) {
|
|
15215
|
+
warn(`[onnx] unexpected error releasing lock ${lockPath}: ${err}`);
|
|
15085
15216
|
}
|
|
15086
|
-
return false;
|
|
15087
15217
|
}
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
if (/[<>]/.test(stage))
|
|
15218
|
+
function tasklistPidFromCsvLine(line) {
|
|
15219
|
+
const quoted = line.match(/"([^"]*)"/g);
|
|
15220
|
+
if (quoted && quoted.length >= 2)
|
|
15221
|
+
return quoted[1].slice(1, -1);
|
|
15222
|
+
const cells = line.split(",").map((cell) => cell.trim().replace(/^"|"$/g, ""));
|
|
15223
|
+
return cells[1] ?? null;
|
|
15224
|
+
}
|
|
15225
|
+
function isWindowsProcessAlive(pid) {
|
|
15226
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
15098
15227
|
return false;
|
|
15099
|
-
|
|
15228
|
+
try {
|
|
15229
|
+
const output = execFileSync("tasklist.exe", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
|
|
15230
|
+
encoding: "utf8",
|
|
15231
|
+
timeout: 2000,
|
|
15232
|
+
windowsHide: true
|
|
15233
|
+
});
|
|
15234
|
+
const expected = String(pid);
|
|
15235
|
+
return output.split(/\r?\n/).some((line) => tasklistPidFromCsvLine(line) === expected);
|
|
15236
|
+
} catch {
|
|
15100
15237
|
return false;
|
|
15101
|
-
const args = tokenizeStage(stage).slice(1);
|
|
15102
|
-
const hasFlag = (...names) => args.some((a) => names.some((n) => a === n || a.startsWith(`${n}=`)));
|
|
15103
|
-
if (head === "grep" || head === "rg") {
|
|
15104
|
-
if (hasIntentChangingGrepFlag(args))
|
|
15105
|
-
return false;
|
|
15106
|
-
if (countBareOperands(args) > 1)
|
|
15107
|
-
return false;
|
|
15108
|
-
return true;
|
|
15109
|
-
}
|
|
15110
|
-
if (head === "head" || head === "tail") {
|
|
15111
|
-
if (bareOperands(args).some((op) => !/^\d+$/.test(op)))
|
|
15112
|
-
return false;
|
|
15113
|
-
return true;
|
|
15114
15238
|
}
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
return
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
if (hasFlag("-i", "--in-place"))
|
|
15122
|
-
return false;
|
|
15123
|
-
if (countBareOperands(args) > 1)
|
|
15124
|
-
return false;
|
|
15239
|
+
}
|
|
15240
|
+
function isProcessAlive(pid) {
|
|
15241
|
+
if (process.platform === "win32")
|
|
15242
|
+
return isWindowsProcessAlive(pid);
|
|
15243
|
+
try {
|
|
15244
|
+
process.kill(pid, 0);
|
|
15125
15245
|
return true;
|
|
15126
|
-
}
|
|
15127
|
-
|
|
15128
|
-
if (
|
|
15246
|
+
} catch (err) {
|
|
15247
|
+
const code = err.code;
|
|
15248
|
+
if (code === "ESRCH")
|
|
15129
15249
|
return false;
|
|
15130
15250
|
return true;
|
|
15131
15251
|
}
|
|
15132
|
-
if (head === "sort" && hasFlag("-o", "--output"))
|
|
15133
|
-
return false;
|
|
15134
|
-
if (bareOperands(args).some((op) => op.includes("/") || op.includes(".")))
|
|
15135
|
-
return false;
|
|
15136
|
-
return true;
|
|
15137
|
-
}
|
|
15138
|
-
function bareOperands(args) {
|
|
15139
|
-
const out = [];
|
|
15140
|
-
let afterDoubleDash = false;
|
|
15141
|
-
for (const arg of args) {
|
|
15142
|
-
if (!afterDoubleDash && arg === "--") {
|
|
15143
|
-
afterDoubleDash = true;
|
|
15144
|
-
continue;
|
|
15145
|
-
}
|
|
15146
|
-
if (!afterDoubleDash && arg.startsWith("-") && arg !== "-")
|
|
15147
|
-
continue;
|
|
15148
|
-
out.push(arg);
|
|
15149
|
-
}
|
|
15150
|
-
return out;
|
|
15151
|
-
}
|
|
15152
|
-
function countBareOperands(args) {
|
|
15153
|
-
return bareOperands(args).length;
|
|
15154
15252
|
}
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
if (quote) {
|
|
15169
|
-
if (char === quote)
|
|
15170
|
-
quote = null;
|
|
15171
|
-
continue;
|
|
15172
|
-
}
|
|
15173
|
-
if (char === "'" || char === '"') {
|
|
15174
|
-
quote = char;
|
|
15175
|
-
continue;
|
|
15176
|
-
}
|
|
15177
|
-
if (char === "&") {
|
|
15178
|
-
const prev = stage[i - 1];
|
|
15179
|
-
const next = stage[i + 1];
|
|
15180
|
-
if (prev === "&" || next === "&" || prev === ">" || next === ">")
|
|
15181
|
-
continue;
|
|
15182
|
-
return true;
|
|
15183
|
-
}
|
|
15253
|
+
// ../aft-bridge/dist/pool.js
|
|
15254
|
+
import { homedir as homedir9 } from "node:os";
|
|
15255
|
+
|
|
15256
|
+
// ../aft-bridge/dist/project-identity.js
|
|
15257
|
+
import { realpathSync as realpathSync2 } from "node:fs";
|
|
15258
|
+
import { resolve as resolve6 } from "node:path";
|
|
15259
|
+
function canonicalizeProjectRoot(dir) {
|
|
15260
|
+
const trimmed = dir.replace(/[/\\]+$/, "");
|
|
15261
|
+
let canonical;
|
|
15262
|
+
try {
|
|
15263
|
+
canonical = realpathSync2(trimmed);
|
|
15264
|
+
} catch {
|
|
15265
|
+
canonical = resolve6(trimmed);
|
|
15184
15266
|
}
|
|
15185
|
-
return
|
|
15267
|
+
return normalizeWindowsRoot(canonical);
|
|
15186
15268
|
}
|
|
15187
|
-
function
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
if (GREP_GUARD_FLAGS.has(flag))
|
|
15196
|
-
return true;
|
|
15197
|
-
continue;
|
|
15198
|
-
}
|
|
15199
|
-
for (const flag of arg.slice(1)) {
|
|
15200
|
-
if (GREP_GUARD_FLAGS.has(flag))
|
|
15201
|
-
return true;
|
|
15202
|
-
}
|
|
15269
|
+
function normalizeWindowsRoot(p) {
|
|
15270
|
+
if (process.platform !== "win32")
|
|
15271
|
+
return p;
|
|
15272
|
+
let s = p;
|
|
15273
|
+
if (s.startsWith("\\\\?\\UNC\\")) {
|
|
15274
|
+
s = `\\\\${s.slice("\\\\?\\UNC\\".length)}`;
|
|
15275
|
+
} else if (s.startsWith("\\\\?\\")) {
|
|
15276
|
+
s = s.slice("\\\\?\\".length);
|
|
15203
15277
|
}
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
let current = "";
|
|
15209
|
-
let quote = null;
|
|
15210
|
-
let escaped = false;
|
|
15211
|
-
for (let index = 0;index < stage.length; index++) {
|
|
15212
|
-
const char = stage[index];
|
|
15213
|
-
if (escaped) {
|
|
15214
|
-
current += char;
|
|
15215
|
-
escaped = false;
|
|
15216
|
-
continue;
|
|
15217
|
-
}
|
|
15218
|
-
if (char === "\\" && quote !== "'") {
|
|
15219
|
-
escaped = true;
|
|
15220
|
-
continue;
|
|
15221
|
-
}
|
|
15222
|
-
if (quote) {
|
|
15223
|
-
if (char === quote) {
|
|
15224
|
-
quote = null;
|
|
15225
|
-
} else {
|
|
15226
|
-
current += char;
|
|
15227
|
-
}
|
|
15228
|
-
continue;
|
|
15229
|
-
}
|
|
15230
|
-
if (char === "'" || char === '"') {
|
|
15231
|
-
quote = char;
|
|
15232
|
-
continue;
|
|
15233
|
-
}
|
|
15234
|
-
if (/\s/.test(char)) {
|
|
15235
|
-
if (current.length > 0) {
|
|
15236
|
-
tokens.push(current);
|
|
15237
|
-
current = "";
|
|
15238
|
-
}
|
|
15239
|
-
continue;
|
|
15278
|
+
if (s.length >= 2 && s[1] === ":") {
|
|
15279
|
+
const drive = s.charCodeAt(0);
|
|
15280
|
+
if (drive >= 97 && drive <= 122) {
|
|
15281
|
+
s = s[0].toUpperCase() + s.slice(1);
|
|
15240
15282
|
}
|
|
15241
|
-
current += char;
|
|
15242
15283
|
}
|
|
15243
|
-
|
|
15244
|
-
tokens.push(current);
|
|
15245
|
-
return tokens;
|
|
15284
|
+
return s;
|
|
15246
15285
|
}
|
|
15286
|
+
|
|
15247
15287
|
// ../aft-bridge/dist/pool.js
|
|
15248
|
-
import { realpathSync as realpathSync2 } from "node:fs";
|
|
15249
|
-
import { homedir as homedir8 } from "node:os";
|
|
15250
15288
|
var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
15251
15289
|
var DEFAULT_MAX_POOL_SIZE = 8;
|
|
15252
15290
|
var CLEANUP_INTERVAL_MS = 60 * 1000;
|
|
15253
15291
|
function canonicalHomeDir() {
|
|
15254
15292
|
try {
|
|
15255
|
-
const home =
|
|
15293
|
+
const home = homedir9();
|
|
15256
15294
|
if (!home)
|
|
15257
15295
|
return null;
|
|
15258
|
-
|
|
15259
|
-
return realpathSync2(home);
|
|
15260
|
-
} catch {
|
|
15261
|
-
return home.replace(/[/\\]+$/, "");
|
|
15262
|
-
}
|
|
15296
|
+
return canonicalizeProjectRoot(home);
|
|
15263
15297
|
} catch {
|
|
15264
15298
|
return null;
|
|
15265
15299
|
}
|
|
@@ -15438,12 +15472,7 @@ class BridgePool {
|
|
|
15438
15472
|
}
|
|
15439
15473
|
}
|
|
15440
15474
|
function normalizeKey(projectRoot) {
|
|
15441
|
-
|
|
15442
|
-
try {
|
|
15443
|
-
return realpathSync2(stripped);
|
|
15444
|
-
} catch {
|
|
15445
|
-
return stripped;
|
|
15446
|
-
}
|
|
15475
|
+
return canonicalizeProjectRoot(projectRoot);
|
|
15447
15476
|
}
|
|
15448
15477
|
// ../aft-bridge/dist/tool-format.js
|
|
15449
15478
|
function asPlainObject(value) {
|
|
@@ -16275,7 +16304,7 @@ import {
|
|
|
16275
16304
|
// package.json
|
|
16276
16305
|
var package_default = {
|
|
16277
16306
|
name: "@cortexkit/aft-pi",
|
|
16278
|
-
version: "0.
|
|
16307
|
+
version: "0.40.0",
|
|
16279
16308
|
type: "module",
|
|
16280
16309
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
16281
16310
|
main: "dist/index.js",
|
|
@@ -16298,7 +16327,7 @@ var package_default = {
|
|
|
16298
16327
|
"test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
|
|
16299
16328
|
},
|
|
16300
16329
|
dependencies: {
|
|
16301
|
-
"@cortexkit/aft-bridge": "0.
|
|
16330
|
+
"@cortexkit/aft-bridge": "0.40.0",
|
|
16302
16331
|
"@xterm/headless": "^5.5.0",
|
|
16303
16332
|
"comment-json": "^5.0.0",
|
|
16304
16333
|
diff: "^8.0.4",
|
|
@@ -16306,12 +16335,12 @@ var package_default = {
|
|
|
16306
16335
|
zod: "^4.1.8"
|
|
16307
16336
|
},
|
|
16308
16337
|
optionalDependencies: {
|
|
16309
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
16310
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
16311
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
16312
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
16313
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
16314
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
16338
|
+
"@cortexkit/aft-darwin-arm64": "0.40.0",
|
|
16339
|
+
"@cortexkit/aft-darwin-x64": "0.40.0",
|
|
16340
|
+
"@cortexkit/aft-linux-arm64": "0.40.0",
|
|
16341
|
+
"@cortexkit/aft-linux-x64": "0.40.0",
|
|
16342
|
+
"@cortexkit/aft-win32-arm64": "0.40.0",
|
|
16343
|
+
"@cortexkit/aft-win32-x64": "0.40.0"
|
|
16315
16344
|
},
|
|
16316
16345
|
devDependencies: {
|
|
16317
16346
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -16885,9 +16914,7 @@ function registerStatusCommand(pi, ctx) {
|
|
|
16885
16914
|
}
|
|
16886
16915
|
|
|
16887
16916
|
// src/config.ts
|
|
16888
|
-
import { existsSync as
|
|
16889
|
-
import { homedir as homedir9 } from "node:os";
|
|
16890
|
-
import { join as join10 } from "node:path";
|
|
16917
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
16891
16918
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
16892
16919
|
|
|
16893
16920
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
@@ -30423,7 +30450,7 @@ function date4(params) {
|
|
|
30423
30450
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
30424
30451
|
config(en_default());
|
|
30425
30452
|
// src/config.ts
|
|
30426
|
-
var FOREGROUND_WAIT_WINDOW_DEFAULT_MS =
|
|
30453
|
+
var FOREGROUND_WAIT_WINDOW_DEFAULT_MS = 15000;
|
|
30427
30454
|
var FOREGROUND_WAIT_WINDOW_MIN_MS = 5000;
|
|
30428
30455
|
function resolveBashConfig(config2) {
|
|
30429
30456
|
const top = config2.bash;
|
|
@@ -30594,105 +30621,6 @@ var AftConfigSchema = exports_external.object({
|
|
|
30594
30621
|
max_callgraph_files: exports_external.number().int().positive().optional(),
|
|
30595
30622
|
bridge: BridgeConfigSchema.optional()
|
|
30596
30623
|
}).strict();
|
|
30597
|
-
function normalizeLspExtension(extension) {
|
|
30598
|
-
return extension.trim().replace(/^\.+/, "");
|
|
30599
|
-
}
|
|
30600
|
-
function resolveLspConfigForConfigure(config2) {
|
|
30601
|
-
const overrides = {};
|
|
30602
|
-
const disabled = new Set(config2.lsp?.disabled ?? []);
|
|
30603
|
-
let experimentalTy = config2.experimental?.lsp_ty;
|
|
30604
|
-
switch (config2.lsp?.python ?? "auto") {
|
|
30605
|
-
case "ty":
|
|
30606
|
-
experimentalTy = true;
|
|
30607
|
-
disabled.add("python");
|
|
30608
|
-
break;
|
|
30609
|
-
case "pyright":
|
|
30610
|
-
experimentalTy = false;
|
|
30611
|
-
disabled.add("ty");
|
|
30612
|
-
break;
|
|
30613
|
-
case "auto":
|
|
30614
|
-
break;
|
|
30615
|
-
}
|
|
30616
|
-
if (experimentalTy !== undefined) {
|
|
30617
|
-
overrides.experimental_lsp_ty = experimentalTy;
|
|
30618
|
-
}
|
|
30619
|
-
const servers = Object.entries(config2.lsp?.servers ?? {}).map(([id, server]) => {
|
|
30620
|
-
const entry = {
|
|
30621
|
-
id,
|
|
30622
|
-
args: server.args,
|
|
30623
|
-
root_markers: server.root_markers,
|
|
30624
|
-
disabled: server.disabled
|
|
30625
|
-
};
|
|
30626
|
-
if (server.extensions && server.extensions.length > 0) {
|
|
30627
|
-
entry.extensions = server.extensions.map(normalizeLspExtension);
|
|
30628
|
-
}
|
|
30629
|
-
if (server.binary) {
|
|
30630
|
-
entry.binary = server.binary;
|
|
30631
|
-
}
|
|
30632
|
-
if (server.env && Object.keys(server.env).length > 0) {
|
|
30633
|
-
entry.env = server.env;
|
|
30634
|
-
}
|
|
30635
|
-
if (server.initialization_options !== undefined) {
|
|
30636
|
-
entry.initialization_options = server.initialization_options;
|
|
30637
|
-
}
|
|
30638
|
-
return entry;
|
|
30639
|
-
});
|
|
30640
|
-
if (servers.length > 0) {
|
|
30641
|
-
overrides.lsp_servers = servers;
|
|
30642
|
-
}
|
|
30643
|
-
if (disabled.size > 0) {
|
|
30644
|
-
overrides.disabled_lsp = [...disabled];
|
|
30645
|
-
}
|
|
30646
|
-
return overrides;
|
|
30647
|
-
}
|
|
30648
|
-
function resolveProjectOverridesForConfigure(config2) {
|
|
30649
|
-
const overrides = {};
|
|
30650
|
-
if (config2.format_on_edit !== undefined)
|
|
30651
|
-
overrides.format_on_edit = config2.format_on_edit;
|
|
30652
|
-
if (config2.formatter_timeout_secs !== undefined)
|
|
30653
|
-
overrides.formatter_timeout_secs = config2.formatter_timeout_secs;
|
|
30654
|
-
if (config2.validate_on_edit !== undefined)
|
|
30655
|
-
overrides.validate_on_edit = config2.validate_on_edit;
|
|
30656
|
-
if (config2.formatter !== undefined)
|
|
30657
|
-
overrides.formatter = config2.formatter;
|
|
30658
|
-
if (config2.checker !== undefined)
|
|
30659
|
-
overrides.checker = config2.checker;
|
|
30660
|
-
overrides.restrict_to_project_root = config2.restrict_to_project_root ?? false;
|
|
30661
|
-
if (config2.search_index !== undefined)
|
|
30662
|
-
overrides.search_index = config2.search_index;
|
|
30663
|
-
if (config2.semantic_search !== undefined)
|
|
30664
|
-
overrides.semantic_search = config2.semantic_search;
|
|
30665
|
-
if (config2.callgraph_store !== undefined)
|
|
30666
|
-
overrides.callgraph_store = config2.callgraph_store;
|
|
30667
|
-
if (config2.callgraph_chunk_size !== undefined)
|
|
30668
|
-
overrides.callgraph_chunk_size = config2.callgraph_chunk_size;
|
|
30669
|
-
Object.assign(overrides, resolveExperimentalConfigForConfigure(config2));
|
|
30670
|
-
Object.assign(overrides, resolveLspConfigForConfigure(config2));
|
|
30671
|
-
if (config2.semantic !== undefined)
|
|
30672
|
-
overrides.semantic = config2.semantic;
|
|
30673
|
-
if (config2.inspect !== undefined)
|
|
30674
|
-
overrides.inspect = config2.inspect;
|
|
30675
|
-
if (config2.max_callgraph_files !== undefined)
|
|
30676
|
-
overrides.max_callgraph_files = config2.max_callgraph_files;
|
|
30677
|
-
return overrides;
|
|
30678
|
-
}
|
|
30679
|
-
function resolveExperimentalConfigForConfigure(config2) {
|
|
30680
|
-
const overrides = {};
|
|
30681
|
-
const bash = resolveBashConfig(config2);
|
|
30682
|
-
overrides.experimental_bash_rewrite = bash.rewrite;
|
|
30683
|
-
overrides.experimental_bash_compress = bash.compress;
|
|
30684
|
-
overrides.experimental_bash_background = bash.background;
|
|
30685
|
-
if (bash.long_running_reminder_enabled !== undefined) {
|
|
30686
|
-
overrides.bash_long_running_reminder_enabled = bash.long_running_reminder_enabled;
|
|
30687
|
-
}
|
|
30688
|
-
if (bash.long_running_reminder_interval_ms !== undefined) {
|
|
30689
|
-
overrides.bash_long_running_reminder_interval_ms = bash.long_running_reminder_interval_ms;
|
|
30690
|
-
}
|
|
30691
|
-
if (config2.experimental?.lsp_ty !== undefined) {
|
|
30692
|
-
overrides.experimental_lsp_ty = config2.experimental.lsp_ty;
|
|
30693
|
-
}
|
|
30694
|
-
return overrides;
|
|
30695
|
-
}
|
|
30696
30624
|
var CONFIG_MIGRATIONS = [
|
|
30697
30625
|
{ oldKey: "experimental_search_index", newPath: ["search_index"] },
|
|
30698
30626
|
{ oldKey: "experimental_semantic_search", newPath: ["semantic_search"] },
|
|
@@ -30802,14 +30730,14 @@ function migrateExperimentalBashBlock(rawConfig, configPath, logger) {
|
|
|
30802
30730
|
}
|
|
30803
30731
|
return movedKeys;
|
|
30804
30732
|
}
|
|
30805
|
-
function
|
|
30806
|
-
if (!
|
|
30733
|
+
function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 }) {
|
|
30734
|
+
if (!existsSync7(configPath)) {
|
|
30807
30735
|
return { migrated: false, oldKeys: [] };
|
|
30808
30736
|
}
|
|
30809
30737
|
let tmpPath = null;
|
|
30810
30738
|
let oldKeys = [];
|
|
30811
30739
|
try {
|
|
30812
|
-
const content =
|
|
30740
|
+
const content = readFileSync6(configPath, "utf-8");
|
|
30813
30741
|
const rawConfig = import_comment_json.parse(content);
|
|
30814
30742
|
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
30815
30743
|
return { migrated: false, oldKeys: [] };
|
|
@@ -30825,14 +30753,14 @@ function migrateAftConfigFile(configPath, logger = { log: log2, warn: warn2 }) {
|
|
|
30825
30753
|
`)}
|
|
30826
30754
|
${serialized}` : serialized;
|
|
30827
30755
|
tmpPath = `${configPath}.tmp.${process.pid}`;
|
|
30828
|
-
|
|
30829
|
-
|
|
30756
|
+
writeFileSync4(tmpPath, nextContent, "utf-8");
|
|
30757
|
+
renameSync5(tmpPath, configPath);
|
|
30830
30758
|
logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
|
|
30831
30759
|
return { migrated: true, oldKeys };
|
|
30832
30760
|
} catch (err) {
|
|
30833
30761
|
if (tmpPath) {
|
|
30834
30762
|
try {
|
|
30835
|
-
|
|
30763
|
+
unlinkSync5(tmpPath);
|
|
30836
30764
|
} catch {}
|
|
30837
30765
|
}
|
|
30838
30766
|
if (isWritableMigrationError(err)) {
|
|
@@ -30843,15 +30771,6 @@ ${serialized}` : serialized;
|
|
|
30843
30771
|
return { migrated: false, oldKeys: [] };
|
|
30844
30772
|
}
|
|
30845
30773
|
}
|
|
30846
|
-
function detectConfigFile(basePath) {
|
|
30847
|
-
const jsoncPath = `${basePath}.jsonc`;
|
|
30848
|
-
const jsonPath = `${basePath}.json`;
|
|
30849
|
-
if (existsSync6(jsoncPath))
|
|
30850
|
-
return { format: "jsonc", path: jsoncPath };
|
|
30851
|
-
if (existsSync6(jsonPath))
|
|
30852
|
-
return { format: "json", path: jsonPath };
|
|
30853
|
-
return { format: "none", path: jsonPath };
|
|
30854
|
-
}
|
|
30855
30774
|
var configLoadErrors = [];
|
|
30856
30775
|
function getConfigLoadErrors() {
|
|
30857
30776
|
return configLoadErrors;
|
|
@@ -30865,9 +30784,9 @@ function recordConfigParseFailure(configPath, errorMessage) {
|
|
|
30865
30784
|
}
|
|
30866
30785
|
function loadConfigFromPath(configPath) {
|
|
30867
30786
|
try {
|
|
30868
|
-
if (!
|
|
30787
|
+
if (!existsSync7(configPath))
|
|
30869
30788
|
return null;
|
|
30870
|
-
const content =
|
|
30789
|
+
const content = readFileSync6(configPath, "utf-8");
|
|
30871
30790
|
const rawConfig = import_comment_json.parse(content);
|
|
30872
30791
|
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
30873
30792
|
recordConfigParseFailure(configPath, "root must be an object");
|
|
@@ -31084,21 +31003,43 @@ function resolveBridgePoolTransportOptions(config2) {
|
|
|
31084
31003
|
hangThreshold: config2.bridge?.hang_threshold ?? DEFAULT_BRIDGE_HANG_THRESHOLD
|
|
31085
31004
|
};
|
|
31086
31005
|
}
|
|
31087
|
-
function
|
|
31088
|
-
|
|
31006
|
+
function migrateAftConfigLocations(projectDirectory, logger = { log: log2, warn: warn2 }) {
|
|
31007
|
+
const paths = resolveCortexKitConfigPaths(projectDirectory);
|
|
31008
|
+
const legacy = resolveLegacyAftConfigSources(projectDirectory);
|
|
31009
|
+
return [
|
|
31010
|
+
migrateAftConfigFile({
|
|
31011
|
+
scope: "user",
|
|
31012
|
+
targetPath: paths.userConfigPath,
|
|
31013
|
+
legacySources: legacy.user,
|
|
31014
|
+
operatingHarness: "pi",
|
|
31015
|
+
logger
|
|
31016
|
+
}),
|
|
31017
|
+
migrateAftConfigFile({
|
|
31018
|
+
scope: "project",
|
|
31019
|
+
targetPath: paths.projectConfigPath,
|
|
31020
|
+
legacySources: legacy.project,
|
|
31021
|
+
operatingHarness: "pi",
|
|
31022
|
+
logger
|
|
31023
|
+
})
|
|
31024
|
+
];
|
|
31025
|
+
}
|
|
31026
|
+
function resolveAftConfigPaths(projectDirectory) {
|
|
31027
|
+
const paths = resolveCortexKitConfigPaths(projectDirectory);
|
|
31028
|
+
migrateAftConfigFile2(paths.userConfigPath);
|
|
31029
|
+
migrateAftConfigFile2(paths.projectConfigPath);
|
|
31030
|
+
return paths;
|
|
31031
|
+
}
|
|
31032
|
+
function buildConfigTierConfigureParams(projectDirectory, processState = {}) {
|
|
31033
|
+
const paths = resolveAftConfigPaths(projectDirectory);
|
|
31034
|
+
return {
|
|
31035
|
+
...processState,
|
|
31036
|
+
cortexkit_user_config_path: paths.userConfigPath,
|
|
31037
|
+
config: readConfigTiers(paths)
|
|
31038
|
+
};
|
|
31089
31039
|
}
|
|
31090
31040
|
function loadAftConfig(projectDirectory) {
|
|
31091
31041
|
configLoadErrors = [];
|
|
31092
|
-
const
|
|
31093
|
-
migrateAftConfigFile(`${userBasePath}.jsonc`);
|
|
31094
|
-
migrateAftConfigFile(`${userBasePath}.json`);
|
|
31095
|
-
const userDetected = detectConfigFile(userBasePath);
|
|
31096
|
-
const userConfigPath = userDetected.format !== "none" ? userDetected.path : `${userBasePath}.json`;
|
|
31097
|
-
const projectBasePath = join10(projectDirectory, ".pi", "aft");
|
|
31098
|
-
migrateAftConfigFile(`${projectBasePath}.jsonc`);
|
|
31099
|
-
migrateAftConfigFile(`${projectBasePath}.json`);
|
|
31100
|
-
const projectDetected = detectConfigFile(projectBasePath);
|
|
31101
|
-
const projectConfigPath = projectDetected.format !== "none" ? projectDetected.path : `${projectBasePath}.json`;
|
|
31042
|
+
const { userConfigPath, projectConfigPath } = resolveAftConfigPaths(projectDirectory);
|
|
31102
31043
|
let config2 = loadConfigFromPath(userConfigPath) ?? {};
|
|
31103
31044
|
const projectConfig = loadConfigFromPath(projectConfigPath);
|
|
31104
31045
|
if (projectConfig) {
|
|
@@ -31123,56 +31064,56 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
31123
31064
|
import { createHash as createHash3 } from "node:crypto";
|
|
31124
31065
|
import {
|
|
31125
31066
|
createReadStream,
|
|
31126
|
-
existsSync as
|
|
31067
|
+
existsSync as existsSync9,
|
|
31127
31068
|
mkdirSync as mkdirSync7,
|
|
31128
|
-
readFileSync as
|
|
31129
|
-
renameSync as
|
|
31130
|
-
rmSync as
|
|
31131
|
-
statSync as
|
|
31132
|
-
writeFileSync as
|
|
31069
|
+
readFileSync as readFileSync9,
|
|
31070
|
+
renameSync as renameSync6,
|
|
31071
|
+
rmSync as rmSync4,
|
|
31072
|
+
statSync as statSync6,
|
|
31073
|
+
writeFileSync as writeFileSync6
|
|
31133
31074
|
} from "node:fs";
|
|
31134
|
-
import { join as
|
|
31075
|
+
import { join as join12 } from "node:path";
|
|
31135
31076
|
|
|
31136
31077
|
// src/lsp-cache.ts
|
|
31137
31078
|
import {
|
|
31138
|
-
closeSync as
|
|
31079
|
+
closeSync as closeSync5,
|
|
31139
31080
|
mkdirSync as mkdirSync6,
|
|
31140
|
-
openSync as
|
|
31141
|
-
readFileSync as
|
|
31142
|
-
statSync as
|
|
31143
|
-
unlinkSync as
|
|
31144
|
-
writeFileSync as
|
|
31081
|
+
openSync as openSync5,
|
|
31082
|
+
readFileSync as readFileSync7,
|
|
31083
|
+
statSync as statSync5,
|
|
31084
|
+
unlinkSync as unlinkSync6,
|
|
31085
|
+
writeFileSync as writeFileSync5
|
|
31145
31086
|
} from "node:fs";
|
|
31146
31087
|
import { homedir as homedir10 } from "node:os";
|
|
31147
|
-
import { join as
|
|
31088
|
+
import { join as join10 } from "node:path";
|
|
31148
31089
|
function aftCacheBase() {
|
|
31149
31090
|
const override = process.env.AFT_CACHE_DIR;
|
|
31150
31091
|
if (override && override.length > 0)
|
|
31151
31092
|
return override;
|
|
31152
31093
|
if (process.platform === "win32") {
|
|
31153
31094
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
31154
|
-
const base2 = localAppData ||
|
|
31155
|
-
return
|
|
31095
|
+
const base2 = localAppData || join10(homedir10(), "AppData", "Local");
|
|
31096
|
+
return join10(base2, "aft");
|
|
31156
31097
|
}
|
|
31157
|
-
const base = process.env.XDG_CACHE_HOME ||
|
|
31158
|
-
return
|
|
31098
|
+
const base = process.env.XDG_CACHE_HOME || join10(homedir10(), ".cache");
|
|
31099
|
+
return join10(base, "aft");
|
|
31159
31100
|
}
|
|
31160
31101
|
function lspCacheRoot() {
|
|
31161
|
-
return
|
|
31102
|
+
return join10(aftCacheBase(), "lsp-packages");
|
|
31162
31103
|
}
|
|
31163
31104
|
function lspPackageDir(npmPackage) {
|
|
31164
|
-
return
|
|
31105
|
+
return join10(lspCacheRoot(), encodeURIComponent(npmPackage));
|
|
31165
31106
|
}
|
|
31166
31107
|
function lspBinaryPath(npmPackage, binary) {
|
|
31167
|
-
return
|
|
31108
|
+
return join10(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
|
|
31168
31109
|
}
|
|
31169
31110
|
function lspBinDir(npmPackage) {
|
|
31170
|
-
return
|
|
31111
|
+
return join10(lspPackageDir(npmPackage), "node_modules", ".bin");
|
|
31171
31112
|
}
|
|
31172
31113
|
function isInstalled(npmPackage, binary) {
|
|
31173
31114
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
31174
31115
|
try {
|
|
31175
|
-
if (
|
|
31116
|
+
if (statSync5(join10(lspBinDir(npmPackage), candidate)).isFile())
|
|
31176
31117
|
return true;
|
|
31177
31118
|
} catch {}
|
|
31178
31119
|
}
|
|
@@ -31192,17 +31133,17 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
|
|
|
31192
31133
|
installedAt: new Date().toISOString(),
|
|
31193
31134
|
...sha256 ? { sha256 } : {}
|
|
31194
31135
|
};
|
|
31195
|
-
|
|
31136
|
+
writeFileSync5(join10(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
|
|
31196
31137
|
} catch (err) {
|
|
31197
31138
|
log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
|
|
31198
31139
|
}
|
|
31199
31140
|
}
|
|
31200
31141
|
function readInstalledMetaIn(installDir) {
|
|
31201
|
-
const path3 =
|
|
31142
|
+
const path3 = join10(installDir, INSTALLED_META_FILE);
|
|
31202
31143
|
try {
|
|
31203
|
-
if (!
|
|
31144
|
+
if (!statSync5(path3).isFile())
|
|
31204
31145
|
return null;
|
|
31205
|
-
const raw =
|
|
31146
|
+
const raw = readFileSync7(path3, "utf8");
|
|
31206
31147
|
const parsed = JSON.parse(raw);
|
|
31207
31148
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
31208
31149
|
return null;
|
|
@@ -31222,7 +31163,7 @@ function readInstalledMeta(packageKey) {
|
|
|
31222
31163
|
return readInstalledMetaIn(lspPackageDir(packageKey));
|
|
31223
31164
|
}
|
|
31224
31165
|
function lockPath(npmPackage) {
|
|
31225
|
-
return
|
|
31166
|
+
return join10(lspPackageDir(npmPackage), ".aft-installing");
|
|
31226
31167
|
}
|
|
31227
31168
|
var STALE_LOCK_MS2 = 30 * 60 * 1000;
|
|
31228
31169
|
function acquireInstallLock(lockKey) {
|
|
@@ -31230,13 +31171,13 @@ function acquireInstallLock(lockKey) {
|
|
|
31230
31171
|
const lock = lockPath(lockKey);
|
|
31231
31172
|
const tryClaim = () => {
|
|
31232
31173
|
try {
|
|
31233
|
-
const fd =
|
|
31174
|
+
const fd = openSync5(lock, "wx");
|
|
31234
31175
|
try {
|
|
31235
|
-
|
|
31176
|
+
writeFileSync5(fd, `${process.pid}
|
|
31236
31177
|
${new Date().toISOString()}
|
|
31237
31178
|
`);
|
|
31238
31179
|
} finally {
|
|
31239
|
-
|
|
31180
|
+
closeSync5(fd);
|
|
31240
31181
|
}
|
|
31241
31182
|
return true;
|
|
31242
31183
|
} catch (err) {
|
|
@@ -31252,12 +31193,12 @@ ${new Date().toISOString()}
|
|
|
31252
31193
|
let owningPid = null;
|
|
31253
31194
|
let lockMtimeMs = 0;
|
|
31254
31195
|
try {
|
|
31255
|
-
const raw =
|
|
31196
|
+
const raw = readFileSync7(lock, "utf8");
|
|
31256
31197
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
31257
31198
|
const parsed = Number.parseInt(firstLine, 10);
|
|
31258
31199
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
31259
31200
|
owningPid = parsed;
|
|
31260
|
-
lockMtimeMs =
|
|
31201
|
+
lockMtimeMs = statSync5(lock).mtimeMs;
|
|
31261
31202
|
} catch {
|
|
31262
31203
|
return tryClaim();
|
|
31263
31204
|
}
|
|
@@ -31270,7 +31211,7 @@ ${new Date().toISOString()}
|
|
|
31270
31211
|
}
|
|
31271
31212
|
log2(`[lsp] reclaiming install lock for ${lockKey} (owner_pid=${owningPid ?? "unknown"}, alive=${ownerAlive}, age_ms=${age})`);
|
|
31272
31213
|
try {
|
|
31273
|
-
|
|
31214
|
+
unlinkSync6(lock);
|
|
31274
31215
|
} catch {}
|
|
31275
31216
|
return tryClaim();
|
|
31276
31217
|
}
|
|
@@ -31290,7 +31231,7 @@ function releaseInstallLock(lockKey) {
|
|
|
31290
31231
|
try {
|
|
31291
31232
|
let owningPid = null;
|
|
31292
31233
|
try {
|
|
31293
|
-
const raw =
|
|
31234
|
+
const raw = readFileSync7(lock, "utf8");
|
|
31294
31235
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
31295
31236
|
const parsed = Number.parseInt(firstLine, 10);
|
|
31296
31237
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -31307,7 +31248,7 @@ function releaseInstallLock(lockKey) {
|
|
|
31307
31248
|
return;
|
|
31308
31249
|
}
|
|
31309
31250
|
try {
|
|
31310
|
-
|
|
31251
|
+
unlinkSync6(lock);
|
|
31311
31252
|
} catch (unlinkErr) {
|
|
31312
31253
|
const code = unlinkErr.code;
|
|
31313
31254
|
if (code !== "ENOENT") {
|
|
@@ -31329,9 +31270,9 @@ async function withInstallLock(lockKey, task) {
|
|
|
31329
31270
|
}
|
|
31330
31271
|
var VERSION_CHECK_FILE = ".aft-version-check";
|
|
31331
31272
|
function readVersionCheck(npmPackage) {
|
|
31332
|
-
const file2 =
|
|
31273
|
+
const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
31333
31274
|
try {
|
|
31334
|
-
const raw =
|
|
31275
|
+
const raw = readFileSync7(file2, "utf8");
|
|
31335
31276
|
const parsed = JSON.parse(raw);
|
|
31336
31277
|
if (typeof parsed.last_checked === "string") {
|
|
31337
31278
|
return {
|
|
@@ -31346,12 +31287,12 @@ function readVersionCheck(npmPackage) {
|
|
|
31346
31287
|
}
|
|
31347
31288
|
function writeVersionCheck(npmPackage, latest) {
|
|
31348
31289
|
mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
|
|
31349
|
-
const file2 =
|
|
31290
|
+
const file2 = join10(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
31350
31291
|
const record2 = {
|
|
31351
31292
|
last_checked: new Date().toISOString(),
|
|
31352
31293
|
latest_eligible: latest
|
|
31353
31294
|
};
|
|
31354
|
-
|
|
31295
|
+
writeFileSync5(file2, JSON.stringify(record2, null, 2));
|
|
31355
31296
|
}
|
|
31356
31297
|
function shouldRecheckVersion(record2, weeklyCheckIntervalMs = 7 * 24 * 60 * 60 * 1000) {
|
|
31357
31298
|
if (!record2)
|
|
@@ -31508,8 +31449,8 @@ var NPM_LSP_TABLE = [
|
|
|
31508
31449
|
];
|
|
31509
31450
|
|
|
31510
31451
|
// src/lsp-project-relevance.ts
|
|
31511
|
-
import { existsSync as
|
|
31512
|
-
import { join as
|
|
31452
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "node:fs";
|
|
31453
|
+
import { join as join11 } from "node:path";
|
|
31513
31454
|
var MAX_WALK_DIRS = 200;
|
|
31514
31455
|
var MAX_WALK_DEPTH = 4;
|
|
31515
31456
|
var NOISE_DIRS = new Set([
|
|
@@ -31526,7 +31467,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
|
|
|
31526
31467
|
if (!rootMarkers)
|
|
31527
31468
|
return false;
|
|
31528
31469
|
for (const marker of rootMarkers) {
|
|
31529
|
-
if (
|
|
31470
|
+
if (existsSync8(join11(projectRoot, marker)))
|
|
31530
31471
|
return true;
|
|
31531
31472
|
}
|
|
31532
31473
|
return false;
|
|
@@ -31550,7 +31491,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
|
|
|
31550
31491
|
}
|
|
31551
31492
|
function readPackageJson(projectRoot) {
|
|
31552
31493
|
try {
|
|
31553
|
-
const raw =
|
|
31494
|
+
const raw = readFileSync8(join11(projectRoot, "package.json"), "utf8");
|
|
31554
31495
|
const parsed = JSON.parse(raw);
|
|
31555
31496
|
if (typeof parsed !== "object" || parsed === null)
|
|
31556
31497
|
return null;
|
|
@@ -31580,7 +31521,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
|
|
|
31580
31521
|
for (const entry of entries) {
|
|
31581
31522
|
if (entry.isDirectory()) {
|
|
31582
31523
|
if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
|
|
31583
|
-
queue.push({ dir:
|
|
31524
|
+
queue.push({ dir: join11(current.dir, entry.name), depth: current.depth + 1 });
|
|
31584
31525
|
}
|
|
31585
31526
|
continue;
|
|
31586
31527
|
}
|
|
@@ -31707,9 +31648,9 @@ async function resolveTargetVersion(spec, config2, fetchImpl = fetch) {
|
|
|
31707
31648
|
}
|
|
31708
31649
|
function ensureInstallAnchor(cwd) {
|
|
31709
31650
|
try {
|
|
31710
|
-
const stub =
|
|
31711
|
-
if (!
|
|
31712
|
-
|
|
31651
|
+
const stub = join12(cwd, "package.json");
|
|
31652
|
+
if (!existsSync9(stub)) {
|
|
31653
|
+
writeFileSync6(stub, `${JSON.stringify({ name: "aft-lsp-cache", version: "0.0.0", private: true })}
|
|
31713
31654
|
`);
|
|
31714
31655
|
}
|
|
31715
31656
|
} catch (err) {
|
|
@@ -31717,18 +31658,18 @@ function ensureInstallAnchor(cwd) {
|
|
|
31717
31658
|
}
|
|
31718
31659
|
}
|
|
31719
31660
|
function runInstall(spec, version2, cwd, signal) {
|
|
31720
|
-
return new Promise((
|
|
31661
|
+
return new Promise((resolve7) => {
|
|
31721
31662
|
const target = `${spec.npm}@${version2}`;
|
|
31722
31663
|
log2(`[lsp] installing ${target} to ${cwd}`);
|
|
31723
31664
|
if (signal?.aborted) {
|
|
31724
31665
|
warn2(`[lsp] install ${target} aborted before spawn`);
|
|
31725
|
-
|
|
31666
|
+
resolve7(false);
|
|
31726
31667
|
return;
|
|
31727
31668
|
}
|
|
31728
31669
|
const npm = resolveNpm();
|
|
31729
31670
|
if (!npm) {
|
|
31730
31671
|
warn2(`[lsp] npm not found on PATH or known locations; cannot install ${target}`);
|
|
31731
|
-
|
|
31672
|
+
resolve7(false);
|
|
31732
31673
|
return;
|
|
31733
31674
|
}
|
|
31734
31675
|
ensureInstallAnchor(cwd);
|
|
@@ -31751,7 +31692,7 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
31751
31692
|
return;
|
|
31752
31693
|
settled = true;
|
|
31753
31694
|
cleanup();
|
|
31754
|
-
|
|
31695
|
+
resolve7(ok);
|
|
31755
31696
|
};
|
|
31756
31697
|
const onAbort = () => {
|
|
31757
31698
|
warn2(`[lsp] install ${target} aborted during shutdown`);
|
|
@@ -31852,7 +31793,7 @@ function cachedPackageDir(npmPackage) {
|
|
|
31852
31793
|
return lspBinDir(npmPackage).replace(/[\\/]node_modules[\\/]\.bin[\\/]?$/, "");
|
|
31853
31794
|
}
|
|
31854
31795
|
function hashInstalledBinary(spec) {
|
|
31855
|
-
return new Promise((
|
|
31796
|
+
return new Promise((resolve7, reject) => {
|
|
31856
31797
|
const candidates = process.platform === "win32" ? [
|
|
31857
31798
|
lspBinaryPath(spec.npm, spec.binary),
|
|
31858
31799
|
lspBinaryPath(spec.npm, `${spec.binary}.cmd`),
|
|
@@ -31862,7 +31803,7 @@ function hashInstalledBinary(spec) {
|
|
|
31862
31803
|
let pathToHash = null;
|
|
31863
31804
|
for (const p of candidates) {
|
|
31864
31805
|
try {
|
|
31865
|
-
if (
|
|
31806
|
+
if (statSync6(p).isFile()) {
|
|
31866
31807
|
pathToHash = p;
|
|
31867
31808
|
break;
|
|
31868
31809
|
}
|
|
@@ -31876,7 +31817,7 @@ function hashInstalledBinary(spec) {
|
|
|
31876
31817
|
const stream = createReadStream(pathToHash);
|
|
31877
31818
|
stream.on("error", reject);
|
|
31878
31819
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
31879
|
-
stream.on("end", () =>
|
|
31820
|
+
stream.on("end", () => resolve7(hash2.digest("hex")));
|
|
31880
31821
|
});
|
|
31881
31822
|
}
|
|
31882
31823
|
function installedBinaryPath(spec) {
|
|
@@ -31888,23 +31829,23 @@ function installedBinaryPath(spec) {
|
|
|
31888
31829
|
] : [lspBinaryPath(spec.npm, spec.binary)];
|
|
31889
31830
|
for (const candidate of candidates) {
|
|
31890
31831
|
try {
|
|
31891
|
-
if (
|
|
31832
|
+
if (statSync6(candidate).isFile())
|
|
31892
31833
|
return candidate;
|
|
31893
31834
|
} catch {}
|
|
31894
31835
|
}
|
|
31895
31836
|
return null;
|
|
31896
31837
|
}
|
|
31897
31838
|
function sha256OfFileSync(path3) {
|
|
31898
|
-
return createHash3("sha256").update(
|
|
31839
|
+
return createHash3("sha256").update(readFileSync9(path3)).digest("hex");
|
|
31899
31840
|
}
|
|
31900
31841
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
31901
31842
|
const packageDir = lspPackageDir(spec.npm);
|
|
31902
|
-
const dest =
|
|
31843
|
+
const dest = join12(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
|
|
31903
31844
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
31904
31845
|
try {
|
|
31905
|
-
mkdirSync7(
|
|
31906
|
-
|
|
31907
|
-
|
|
31846
|
+
mkdirSync7(join12(dest, ".."), { recursive: true });
|
|
31847
|
+
rmSync4(dest, { recursive: true, force: true });
|
|
31848
|
+
renameSync6(packageDir, dest);
|
|
31908
31849
|
} catch (err) {
|
|
31909
31850
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
|
|
31910
31851
|
}
|
|
@@ -31984,20 +31925,20 @@ import {
|
|
|
31984
31925
|
copyFileSync as copyFileSync4,
|
|
31985
31926
|
createReadStream as createReadStream2,
|
|
31986
31927
|
createWriteStream as createWriteStream3,
|
|
31987
|
-
existsSync as
|
|
31928
|
+
existsSync as existsSync10,
|
|
31988
31929
|
lstatSync as lstatSync2,
|
|
31989
31930
|
mkdirSync as mkdirSync8,
|
|
31990
31931
|
readdirSync as readdirSync4,
|
|
31991
|
-
readFileSync as
|
|
31932
|
+
readFileSync as readFileSync10,
|
|
31992
31933
|
readlinkSync as readlinkSync2,
|
|
31993
31934
|
realpathSync as realpathSync3,
|
|
31994
|
-
renameSync as
|
|
31995
|
-
rmSync as
|
|
31996
|
-
statSync as
|
|
31997
|
-
unlinkSync as
|
|
31998
|
-
writeFileSync as
|
|
31935
|
+
renameSync as renameSync7,
|
|
31936
|
+
rmSync as rmSync5,
|
|
31937
|
+
statSync as statSync7,
|
|
31938
|
+
unlinkSync as unlinkSync7,
|
|
31939
|
+
writeFileSync as writeFileSync7
|
|
31999
31940
|
} from "node:fs";
|
|
32000
|
-
import { dirname as dirname5, join as
|
|
31941
|
+
import { dirname as dirname5, join as join13, relative as relative3, resolve as resolve7 } from "node:path";
|
|
32001
31942
|
import { Readable as Readable3 } from "node:stream";
|
|
32002
31943
|
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
32003
31944
|
|
|
@@ -32087,26 +32028,26 @@ function detectHostPlatform() {
|
|
|
32087
32028
|
|
|
32088
32029
|
// src/lsp-github-install.ts
|
|
32089
32030
|
function ghCacheRoot() {
|
|
32090
|
-
return
|
|
32031
|
+
return join13(aftCacheBase(), "lsp-binaries");
|
|
32091
32032
|
}
|
|
32092
32033
|
function ghPackageDir(spec) {
|
|
32093
|
-
return
|
|
32034
|
+
return join13(ghCacheRoot(), spec.id);
|
|
32094
32035
|
}
|
|
32095
32036
|
function ghBinDir(spec) {
|
|
32096
|
-
return
|
|
32037
|
+
return join13(ghPackageDir(spec), "bin");
|
|
32097
32038
|
}
|
|
32098
32039
|
function ghExtractDir(spec) {
|
|
32099
|
-
return
|
|
32040
|
+
return join13(ghPackageDir(spec), "extracted");
|
|
32100
32041
|
}
|
|
32101
32042
|
var INSTALLED_META_FILE2 = ".aft-installed";
|
|
32102
32043
|
function ghBinaryPath(spec, platform) {
|
|
32103
32044
|
const ext = platform === "win32" ? ".exe" : "";
|
|
32104
|
-
return
|
|
32045
|
+
return join13(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
32105
32046
|
}
|
|
32106
32047
|
function isGithubInstalled(spec, platform) {
|
|
32107
32048
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
32108
32049
|
try {
|
|
32109
|
-
if (
|
|
32050
|
+
if (statSync7(join13(ghBinDir(spec), candidate)).isFile())
|
|
32110
32051
|
return true;
|
|
32111
32052
|
} catch {}
|
|
32112
32053
|
}
|
|
@@ -32119,10 +32060,10 @@ function ghBinaryCandidates(spec, platform) {
|
|
|
32119
32060
|
}
|
|
32120
32061
|
function readGithubInstalledMetaIn(installDir) {
|
|
32121
32062
|
try {
|
|
32122
|
-
const path3 =
|
|
32123
|
-
if (!
|
|
32063
|
+
const path3 = join13(installDir, INSTALLED_META_FILE2);
|
|
32064
|
+
if (!statSync7(path3).isFile())
|
|
32124
32065
|
return null;
|
|
32125
|
-
const parsed = JSON.parse(
|
|
32066
|
+
const parsed = JSON.parse(readFileSync10(path3, "utf8"));
|
|
32126
32067
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
32127
32068
|
return null;
|
|
32128
32069
|
return {
|
|
@@ -32146,7 +32087,7 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
|
|
|
32146
32087
|
binarySha256,
|
|
32147
32088
|
...archiveSha256 ? { archiveSha256 } : {}
|
|
32148
32089
|
};
|
|
32149
|
-
|
|
32090
|
+
writeFileSync7(join13(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
|
|
32150
32091
|
} catch (err) {
|
|
32151
32092
|
warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
|
|
32152
32093
|
}
|
|
@@ -32154,16 +32095,16 @@ function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveS
|
|
|
32154
32095
|
var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
|
|
32155
32096
|
var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
|
|
32156
32097
|
function sha256OfFile(path3) {
|
|
32157
|
-
return new Promise((
|
|
32098
|
+
return new Promise((resolve8, reject) => {
|
|
32158
32099
|
const hash2 = createHash4("sha256");
|
|
32159
32100
|
const stream = createReadStream2(path3);
|
|
32160
32101
|
stream.on("error", reject);
|
|
32161
32102
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
32162
|
-
stream.on("end", () =>
|
|
32103
|
+
stream.on("end", () => resolve8(hash2.digest("hex")));
|
|
32163
32104
|
});
|
|
32164
32105
|
}
|
|
32165
32106
|
function sha256OfFileSync2(path3) {
|
|
32166
|
-
return createHash4("sha256").update(
|
|
32107
|
+
return createHash4("sha256").update(readFileSync10(path3)).digest("hex");
|
|
32167
32108
|
}
|
|
32168
32109
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
|
|
32169
32110
|
const candidates = [];
|
|
@@ -32356,7 +32297,7 @@ async function downloadFile(url2, destPath, fetchImpl, assetSize, signal) {
|
|
|
32356
32297
|
await pipeline3(nodeStream, createWriteStream3(destPath), { signal: timeout.signal });
|
|
32357
32298
|
} catch (err) {
|
|
32358
32299
|
try {
|
|
32359
|
-
|
|
32300
|
+
unlinkSync7(destPath);
|
|
32360
32301
|
} catch {}
|
|
32361
32302
|
throw err;
|
|
32362
32303
|
} finally {
|
|
@@ -32395,7 +32336,7 @@ function validateExtraction(stagingRoot) {
|
|
|
32395
32336
|
throw new Error(`failed to read staging dir ${dir}: ${err}`);
|
|
32396
32337
|
}
|
|
32397
32338
|
for (const entry of entries) {
|
|
32398
|
-
const full =
|
|
32339
|
+
const full = join13(dir, entry);
|
|
32399
32340
|
let lst;
|
|
32400
32341
|
try {
|
|
32401
32342
|
lst = lstatSync2(full);
|
|
@@ -32416,7 +32357,7 @@ function validateExtraction(stagingRoot) {
|
|
|
32416
32357
|
throw new Error(`failed to realpath ${full}: ${err}`);
|
|
32417
32358
|
}
|
|
32418
32359
|
const rel = relative3(realStagingRoot, realFull);
|
|
32419
|
-
if (rel.startsWith("..") ||
|
|
32360
|
+
if (rel.startsWith("..") || resolve7(realStagingRoot, rel) !== realFull) {
|
|
32420
32361
|
throw new Error(`archive entry escapes staging root: ${full} → ${realFull} (zip-slip defense)`);
|
|
32421
32362
|
}
|
|
32422
32363
|
if (lst.isDirectory()) {
|
|
@@ -32463,7 +32404,7 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
32463
32404
|
const suffix = randomBytes(8).toString("hex");
|
|
32464
32405
|
const stagingDir = `${destDir}.staging-${suffix}`;
|
|
32465
32406
|
try {
|
|
32466
|
-
|
|
32407
|
+
rmSync5(stagingDir, { recursive: true, force: true });
|
|
32467
32408
|
} catch {}
|
|
32468
32409
|
mkdirSync8(stagingDir, { recursive: true });
|
|
32469
32410
|
try {
|
|
@@ -32471,24 +32412,24 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
32471
32412
|
runPlatformExtractor(archivePath, stagingDir, archiveType);
|
|
32472
32413
|
validateExtraction(stagingDir);
|
|
32473
32414
|
try {
|
|
32474
|
-
|
|
32415
|
+
rmSync5(destDir, { recursive: true, force: true });
|
|
32475
32416
|
} catch {}
|
|
32476
|
-
|
|
32417
|
+
renameSync7(stagingDir, destDir);
|
|
32477
32418
|
} catch (err) {
|
|
32478
32419
|
try {
|
|
32479
|
-
|
|
32420
|
+
rmSync5(stagingDir, { recursive: true, force: true });
|
|
32480
32421
|
} catch {}
|
|
32481
32422
|
throw err;
|
|
32482
32423
|
}
|
|
32483
32424
|
}
|
|
32484
32425
|
function quarantineCachedGithubInstall(spec, reason) {
|
|
32485
32426
|
const packageDir = ghPackageDir(spec);
|
|
32486
|
-
const dest =
|
|
32427
|
+
const dest = join13(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
|
|
32487
32428
|
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
32488
32429
|
try {
|
|
32489
32430
|
mkdirSync8(dirname5(dest), { recursive: true });
|
|
32490
|
-
|
|
32491
|
-
|
|
32431
|
+
rmSync5(dest, { recursive: true, force: true });
|
|
32432
|
+
renameSync7(packageDir, dest);
|
|
32492
32433
|
} catch (err) {
|
|
32493
32434
|
warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
|
|
32494
32435
|
}
|
|
@@ -32496,9 +32437,9 @@ function quarantineCachedGithubInstall(spec, reason) {
|
|
|
32496
32437
|
function validateCachedGithubInstall(spec, platform) {
|
|
32497
32438
|
const packageDir = ghPackageDir(spec);
|
|
32498
32439
|
const meta3 = readGithubInstalledMetaIn(packageDir);
|
|
32499
|
-
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) =>
|
|
32440
|
+
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join13(ghBinDir(spec), candidate)).find((candidate) => {
|
|
32500
32441
|
try {
|
|
32501
|
-
return
|
|
32442
|
+
return statSync7(candidate).isFile();
|
|
32502
32443
|
} catch {
|
|
32503
32444
|
return false;
|
|
32504
32445
|
}
|
|
@@ -32574,7 +32515,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
32574
32515
|
}
|
|
32575
32516
|
const pkgDir = ghPackageDir(spec);
|
|
32576
32517
|
const extractDir = ghExtractDir(spec);
|
|
32577
|
-
const archivePath =
|
|
32518
|
+
const archivePath = join13(pkgDir, expected.name);
|
|
32578
32519
|
log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
|
|
32579
32520
|
try {
|
|
32580
32521
|
await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
|
|
@@ -32588,7 +32529,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
32588
32529
|
} catch (err) {
|
|
32589
32530
|
error2(`[lsp] hash ${spec.id} failed: ${err}`);
|
|
32590
32531
|
try {
|
|
32591
|
-
|
|
32532
|
+
unlinkSync7(archivePath);
|
|
32592
32533
|
} catch {}
|
|
32593
32534
|
return null;
|
|
32594
32535
|
}
|
|
@@ -32599,7 +32540,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
32599
32540
|
if (previousArchiveSha256 !== archiveSha256) {
|
|
32600
32541
|
error2(`[lsp] ${spec.id} ${tag}: TOFU sha256 mismatch — refusing install. ` + `Previously installed archive sha256=${previousArchiveSha256}, downloaded sha256=${archiveSha256}. ` + `This means the published release for tag ${tag} changed. Investigate before proceeding.`);
|
|
32601
32542
|
try {
|
|
32602
|
-
|
|
32543
|
+
unlinkSync7(archivePath);
|
|
32603
32544
|
} catch {}
|
|
32604
32545
|
return null;
|
|
32605
32546
|
}
|
|
@@ -32611,11 +32552,11 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl,
|
|
|
32611
32552
|
return null;
|
|
32612
32553
|
} finally {
|
|
32613
32554
|
try {
|
|
32614
|
-
|
|
32555
|
+
unlinkSync7(archivePath);
|
|
32615
32556
|
} catch {}
|
|
32616
32557
|
}
|
|
32617
|
-
const innerBinaryPath =
|
|
32618
|
-
if (!
|
|
32558
|
+
const innerBinaryPath = join13(extractDir, spec.binaryPathInArchive(platform, arch, version2));
|
|
32559
|
+
if (!existsSync10(innerBinaryPath)) {
|
|
32619
32560
|
error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
|
|
32620
32561
|
return null;
|
|
32621
32562
|
}
|
|
@@ -32699,7 +32640,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
|
|
|
32699
32640
|
if (!host) {
|
|
32700
32641
|
for (const spec of GITHUB_LSP_TABLE) {
|
|
32701
32642
|
try {
|
|
32702
|
-
if (
|
|
32643
|
+
if (existsSync10(ghBinDir(spec))) {
|
|
32703
32644
|
cachedBinDirs.push(ghBinDir(spec));
|
|
32704
32645
|
}
|
|
32705
32646
|
} catch {}
|
|
@@ -32869,9 +32810,13 @@ function warningTitle(warning) {
|
|
|
32869
32810
|
return "LSP binary is missing";
|
|
32870
32811
|
case "config_parse_failed":
|
|
32871
32812
|
return "Config failed to parse";
|
|
32813
|
+
case "config_key_dropped":
|
|
32814
|
+
return "Config key ignored";
|
|
32872
32815
|
}
|
|
32873
32816
|
}
|
|
32874
32817
|
function formatConfigureWarning(warning) {
|
|
32818
|
+
if (warning.kind === "config_key_dropped")
|
|
32819
|
+
return `${WARNING_MARKER} ${warning.hint}`;
|
|
32875
32820
|
const details = [];
|
|
32876
32821
|
if (warning.language)
|
|
32877
32822
|
details.push(`language: ${warning.language}`);
|
|
@@ -33014,7 +32959,7 @@ function renderScreen(state, rows = state.rows, cols = state.cols) {
|
|
|
33014
32959
|
`);
|
|
33015
32960
|
}
|
|
33016
32961
|
function writeTerminal(terminal, data) {
|
|
33017
|
-
return new Promise((
|
|
32962
|
+
return new Promise((resolve8) => terminal.write(data, resolve8));
|
|
33018
32963
|
}
|
|
33019
32964
|
|
|
33020
32965
|
// src/shutdown-hooks.ts
|
|
@@ -33071,8 +33016,8 @@ function installProcessHandlers() {
|
|
|
33071
33016
|
}
|
|
33072
33017
|
signalShutdownStarted = true;
|
|
33073
33018
|
process.exitCode = SIGNAL_EXIT_CODES[sig];
|
|
33074
|
-
const timeout = new Promise((
|
|
33075
|
-
setTimeout(
|
|
33019
|
+
const timeout = new Promise((resolve8) => {
|
|
33020
|
+
setTimeout(resolve8, SIGNAL_CLEANUP_TIMEOUT_MS);
|
|
33076
33021
|
});
|
|
33077
33022
|
Promise.race([runCleanups(sig), timeout]).finally(() => {
|
|
33078
33023
|
process.exit(SIGNAL_EXIT_CODES[sig]);
|
|
@@ -33115,7 +33060,7 @@ import { Type as Type3 } from "typebox";
|
|
|
33115
33060
|
// src/tools/hoisted.ts
|
|
33116
33061
|
import { stat } from "node:fs/promises";
|
|
33117
33062
|
import { homedir as homedir11 } from "node:os";
|
|
33118
|
-
import { isAbsolute as
|
|
33063
|
+
import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve8, sep } from "node:path";
|
|
33119
33064
|
import {
|
|
33120
33065
|
renderDiff
|
|
33121
33066
|
} from "@earendil-works/pi-coding-agent";
|
|
@@ -33230,7 +33175,7 @@ function diagnosticsOnEditDefault(ctx) {
|
|
|
33230
33175
|
}
|
|
33231
33176
|
function containsPath(parent, child) {
|
|
33232
33177
|
const rel = relative4(parent, child);
|
|
33233
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
33178
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
|
|
33234
33179
|
}
|
|
33235
33180
|
function expandTilde2(path3) {
|
|
33236
33181
|
if (!path3 || !path3.startsWith("~"))
|
|
@@ -33238,13 +33183,13 @@ function expandTilde2(path3) {
|
|
|
33238
33183
|
if (path3 === "~")
|
|
33239
33184
|
return homedir11();
|
|
33240
33185
|
if (path3.startsWith(`~${sep}`) || path3.startsWith("~/")) {
|
|
33241
|
-
return
|
|
33186
|
+
return resolve8(homedir11(), path3.slice(2));
|
|
33242
33187
|
}
|
|
33243
33188
|
return path3;
|
|
33244
33189
|
}
|
|
33245
33190
|
function absoluteSearchPath(cwd, target) {
|
|
33246
33191
|
const expanded = expandTilde2(target);
|
|
33247
|
-
return
|
|
33192
|
+
return isAbsolute5(expanded) ? expanded : resolve8(cwd, expanded);
|
|
33248
33193
|
}
|
|
33249
33194
|
async function searchPathExists(cwd, target) {
|
|
33250
33195
|
try {
|
|
@@ -33296,46 +33241,16 @@ function appendSkippedSearchPaths(text, missing) {
|
|
|
33296
33241
|
|
|
33297
33242
|
${note}` : note;
|
|
33298
33243
|
}
|
|
33299
|
-
function
|
|
33300
|
-
const raw = process.env.AFT_PI_EXTERNAL_PROMPT_TIMEOUT_MS;
|
|
33301
|
-
if (raw === undefined)
|
|
33302
|
-
return 30000;
|
|
33303
|
-
const parsed = Number.parseInt(raw, 10);
|
|
33304
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : 30000;
|
|
33305
|
-
}
|
|
33306
|
-
async function assertExternalDirectoryPermission(extCtx, target, action = "modify", options = {}) {
|
|
33244
|
+
async function assertExternalDirectoryPermission(extCtx, target, options = {}) {
|
|
33307
33245
|
if (!target)
|
|
33308
33246
|
return;
|
|
33309
33247
|
const expanded = expandTilde2(target);
|
|
33310
|
-
const absoluteTarget =
|
|
33248
|
+
const absoluteTarget = isAbsolute5(expanded) ? expanded : resolve8(extCtx.cwd, expanded);
|
|
33311
33249
|
if (containsPath(extCtx.cwd, absoluteTarget))
|
|
33312
33250
|
return;
|
|
33313
33251
|
if (options.restrictToProjectRoot === false)
|
|
33314
33252
|
return;
|
|
33315
|
-
|
|
33316
|
-
if (extCtx.hasUI === false || !confirmFn) {
|
|
33317
|
-
throw new Error(`Permission denied: cannot prompt for ${action} outside the project (${absoluteTarget}).`);
|
|
33318
|
-
}
|
|
33319
|
-
const timeoutMs = externalDirectoryPromptTimeoutMs();
|
|
33320
|
-
let timer;
|
|
33321
|
-
const timeoutPromise = new Promise((resolve5) => {
|
|
33322
|
-
timer = setTimeout(() => resolve5("timeout"), timeoutMs);
|
|
33323
|
-
});
|
|
33324
|
-
try {
|
|
33325
|
-
const result = await Promise.race([
|
|
33326
|
-
confirmFn("Allow external directory access?", `AFT wants to ${action} outside the project: ${absoluteTarget}`),
|
|
33327
|
-
timeoutPromise
|
|
33328
|
-
]);
|
|
33329
|
-
if (result === true)
|
|
33330
|
-
return;
|
|
33331
|
-
if (result === "timeout") {
|
|
33332
|
-
throw new Error(`Permission denied: external directory prompt timed out after ${timeoutMs}ms.`);
|
|
33333
|
-
}
|
|
33334
|
-
throw new Error("Permission denied: external directory access was cancelled.");
|
|
33335
|
-
} finally {
|
|
33336
|
-
if (timer !== undefined)
|
|
33337
|
-
clearTimeout(timer);
|
|
33338
|
-
}
|
|
33253
|
+
throw new Error(`Blocked: '${absoluteTarget}' is outside the project root and restrict_to_project_root is ` + "enabled (AFT full isolation). Not overridable per-call; set restrict_to_project_root: false " + "in aft.jsonc to allow external paths.");
|
|
33339
33254
|
}
|
|
33340
33255
|
var ReadParams = Type2.Object({
|
|
33341
33256
|
path: Type2.String({
|
|
@@ -33384,7 +33299,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
33384
33299
|
const offset = coerceOptionalInt(params.offset, "offset", 1, Number.MAX_SAFE_INTEGER);
|
|
33385
33300
|
const limit = coerceOptionalInt(params.limit, "limit", 1, Number.MAX_SAFE_INTEGER);
|
|
33386
33301
|
const filePath = await resolvePathArg(extCtx.cwd, params.path);
|
|
33387
|
-
await assertExternalDirectoryPermission(extCtx, filePath,
|
|
33302
|
+
await assertExternalDirectoryPermission(extCtx, filePath, {
|
|
33388
33303
|
restrictToProjectRoot: surface.restrictToProjectRoot
|
|
33389
33304
|
});
|
|
33390
33305
|
const req = {
|
|
@@ -33422,7 +33337,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
33422
33337
|
parameters: WriteParams,
|
|
33423
33338
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
33424
33339
|
const filePath = await resolvePathArg(extCtx.cwd, params.filePath);
|
|
33425
|
-
await assertExternalDirectoryPermission(extCtx, filePath,
|
|
33340
|
+
await assertExternalDirectoryPermission(extCtx, filePath, {
|
|
33426
33341
|
restrictToProjectRoot: surface.restrictToProjectRoot
|
|
33427
33342
|
});
|
|
33428
33343
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
@@ -33456,7 +33371,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
33456
33371
|
parameters: EditParams,
|
|
33457
33372
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
33458
33373
|
const filePath = await resolvePathArg(extCtx.cwd, params.filePath);
|
|
33459
|
-
await assertExternalDirectoryPermission(extCtx, filePath,
|
|
33374
|
+
await assertExternalDirectoryPermission(extCtx, filePath, {
|
|
33460
33375
|
restrictToProjectRoot: surface.restrictToProjectRoot
|
|
33461
33376
|
});
|
|
33462
33377
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
@@ -33478,7 +33393,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
33478
33393
|
diagnostics: diagnosticsOnEditDefault(ctx),
|
|
33479
33394
|
include_diff_content: true
|
|
33480
33395
|
};
|
|
33481
|
-
if (params.replaceAll
|
|
33396
|
+
if (coerceBoolean(params.replaceAll))
|
|
33482
33397
|
req.replace_all = true;
|
|
33483
33398
|
const occurrence = coerceOptionalInt(params.occurrence, "occurrence", 0, Number.MAX_SAFE_INTEGER);
|
|
33484
33399
|
if (occurrence !== undefined)
|
|
@@ -33509,7 +33424,7 @@ function registerHoistedTools(pi, ctx, surface) {
|
|
|
33509
33424
|
if (params.path) {
|
|
33510
33425
|
pathSplit = await splitSearchPathArg(extCtx.cwd, params.path);
|
|
33511
33426
|
for (const target of pathSplit.paths) {
|
|
33512
|
-
await assertExternalDirectoryPermission(extCtx, absoluteSearchPath(extCtx.cwd, target),
|
|
33427
|
+
await assertExternalDirectoryPermission(extCtx, absoluteSearchPath(extCtx.cwd, target), {
|
|
33513
33428
|
restrictToProjectRoot: surface.restrictToProjectRoot
|
|
33514
33429
|
});
|
|
33515
33430
|
}
|
|
@@ -33930,7 +33845,7 @@ async function resolveAstPaths(extCtx, paths) {
|
|
|
33930
33845
|
return;
|
|
33931
33846
|
return Promise.all(paths.filter((path3) => typeof path3 === "string").map((path3) => resolvePathArg(extCtx.cwd, path3)));
|
|
33932
33847
|
}
|
|
33933
|
-
async function assertAstPathsPermission(extCtx, paths,
|
|
33848
|
+
async function assertAstPathsPermission(extCtx, paths, restrictToProjectRoot) {
|
|
33934
33849
|
if (paths === undefined || paths.length === 0)
|
|
33935
33850
|
return;
|
|
33936
33851
|
const checked = new Set;
|
|
@@ -33938,7 +33853,7 @@ async function assertAstPathsPermission(extCtx, paths, action, restrictToProject
|
|
|
33938
33853
|
if (checked.has(path3))
|
|
33939
33854
|
continue;
|
|
33940
33855
|
checked.add(path3);
|
|
33941
|
-
await assertExternalDirectoryPermission(extCtx, path3,
|
|
33856
|
+
await assertExternalDirectoryPermission(extCtx, path3, { restrictToProjectRoot });
|
|
33942
33857
|
}
|
|
33943
33858
|
}
|
|
33944
33859
|
function buildAstSearchSections(payload, theme) {
|
|
@@ -34057,7 +33972,7 @@ function registerAstTools(pi, ctx, surface) {
|
|
|
34057
33972
|
parameters: SearchParams,
|
|
34058
33973
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
34059
33974
|
const paths = await resolveAstPaths(extCtx, params.paths);
|
|
34060
|
-
await assertAstPathsPermission(extCtx, paths,
|
|
33975
|
+
await assertAstPathsPermission(extCtx, paths, ctx.config.restrict_to_project_root ?? false);
|
|
34061
33976
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
34062
33977
|
const req = {
|
|
34063
33978
|
pattern: params.pattern,
|
|
@@ -34088,7 +34003,7 @@ function registerAstTools(pi, ctx, surface) {
|
|
|
34088
34003
|
parameters: ReplaceParams,
|
|
34089
34004
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
34090
34005
|
const paths = await resolveAstPaths(extCtx, params.paths);
|
|
34091
|
-
await assertAstPathsPermission(extCtx, paths,
|
|
34006
|
+
await assertAstPathsPermission(extCtx, paths, ctx.config.restrict_to_project_root ?? false);
|
|
34092
34007
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
34093
34008
|
const req = {
|
|
34094
34009
|
pattern: params.pattern,
|
|
@@ -34099,7 +34014,7 @@ function registerAstTools(pi, ctx, surface) {
|
|
|
34099
34014
|
req.paths = paths;
|
|
34100
34015
|
if (!isEmptyParam(params.globs))
|
|
34101
34016
|
req.globs = params.globs;
|
|
34102
|
-
req.dry_run = params.dryRun
|
|
34017
|
+
req.dry_run = coerceBoolean(params.dryRun);
|
|
34103
34018
|
const response = await callBridge(bridge, "ast_replace", req, extCtx);
|
|
34104
34019
|
return textResult(response.text ?? JSON.stringify(response));
|
|
34105
34020
|
},
|
|
@@ -34215,6 +34130,9 @@ var BashWriteParams = Type4.Object({
|
|
|
34215
34130
|
description: "Either a string of verbatim bytes (e.g. 'print(1)\\n') OR an array mixing strings " + "and { key: '<name>' } objects for atomic text+key sequences. " + "Example: [ 'iHello', { key: 'esc' }, ':wq', { key: 'enter' } ]. " + "Allowed key names: enter, return, tab, space, backspace, esc, escape, up, down, " + "left, right, home, end, page-up, page-down, delete, insert, f1..f12, ctrl-a..ctrl-z."
|
|
34216
34131
|
})
|
|
34217
34132
|
});
|
|
34133
|
+
function unavailableSnapshot() {
|
|
34134
|
+
return { status: "unknown" };
|
|
34135
|
+
}
|
|
34218
34136
|
async function callBashBridge(bridge, command, params = {}, extCtx, options) {
|
|
34219
34137
|
return await callBridge(bridge, command, params, extCtx, {
|
|
34220
34138
|
transportTimeoutMs: BASH_TRANSPORT_TIMEOUT_MS,
|
|
@@ -34247,8 +34165,8 @@ function registerBashTool(pi, ctx, aftSearchRegistered = false) {
|
|
|
34247
34165
|
const spawnHook = getBashSpawnHook(pi);
|
|
34248
34166
|
const searchSteer = aftSearchRegistered ? "use `aft_search` (concepts, identifiers, regex, literals), `read`, `aft_outline`, or `aft_zoom` instead" : "use the `grep` tool, `read`, `aft_outline`, or `aft_zoom` instead";
|
|
34249
34167
|
const bashCfg = resolveBashConfig(ctx.config);
|
|
34250
|
-
const compressionSentence = bashCfg.compress ? " Output is compressed by default; pass `compressed: false` for raw output." : "";
|
|
34251
|
-
const tasksSentence = bashCfg.background ? '
|
|
34168
|
+
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`." : "";
|
|
34169
|
+
const tasksSentence = bashCfg.background ? ' Commands run in the foreground and return inline; a long-running one auto-promotes to background and delivers a completion reminder when it finishes — so for the common "I am waiting on this result" case, just run it and wait, no flags needed. 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).";
|
|
34252
34170
|
pi.registerTool({
|
|
34253
34171
|
name: "bash",
|
|
34254
34172
|
label: "bash",
|
|
@@ -34258,7 +34176,8 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34258
34176
|
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)",
|
|
34259
34177
|
promptGuidelines: [
|
|
34260
34178
|
`DO NOT use bash for code search or exploration — ${searchSteer}.`,
|
|
34261
|
-
"Set compressed: false when you need ANSI color codes in the output."
|
|
34179
|
+
"Set compressed: false when you need ANSI color codes in the output.",
|
|
34180
|
+
"Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
|
|
34262
34181
|
],
|
|
34263
34182
|
parameters: bashParamsForConfig(bashCfg.background),
|
|
34264
34183
|
async execute(_toolCallId, params, _signal, onUpdate, extCtx) {
|
|
@@ -34269,8 +34188,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34269
34188
|
const timeout = coerceOptionalInt(params.timeout, "timeout", 1, Number.MAX_SAFE_INTEGER);
|
|
34270
34189
|
const ptyRows = backgroundDisabled ? undefined : coerceOptionalInt(params.ptyRows, "ptyRows", 1, 60);
|
|
34271
34190
|
const ptyCols = backgroundDisabled ? undefined : coerceOptionalInt(params.ptyCols, "ptyCols", 1, 140);
|
|
34272
|
-
const
|
|
34273
|
-
const
|
|
34191
|
+
const compressed = coerceBoolean(params.compressed, true);
|
|
34192
|
+
const requestedPty = !backgroundDisabled && coerceBoolean(params.pty);
|
|
34193
|
+
const effectiveBackground = !backgroundDisabled && (coerceBoolean(params.background) || requestedPty);
|
|
34274
34194
|
const effectiveTimeout = effectiveBackground || backgroundDisabled ? timeout : resolveBashKillTimeout(timeout, foregroundWaitMs);
|
|
34275
34195
|
let spawnContext = {
|
|
34276
34196
|
command: params.command,
|
|
@@ -34283,9 +34203,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34283
34203
|
throw new Error(`BashSpawnHook failed: ${hookErr instanceof Error ? hookErr.message : String(hookErr)}`);
|
|
34284
34204
|
}
|
|
34285
34205
|
}
|
|
34286
|
-
const
|
|
34287
|
-
const pipeStrip = maybeStripCompressorPipe(spawnContext.command, compressionEnabled);
|
|
34288
|
-
const bridgeCommand = pipeStrip.command;
|
|
34206
|
+
const bridgeCommand = spawnContext.command;
|
|
34289
34207
|
let streamed = "";
|
|
34290
34208
|
const response = await callBashBridge(bridge, "bash", {
|
|
34291
34209
|
command: bridgeCommand,
|
|
@@ -34295,7 +34213,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34295
34213
|
description: params.description,
|
|
34296
34214
|
background: effectiveBackground,
|
|
34297
34215
|
notify_on_completion: effectiveBackground,
|
|
34298
|
-
compressed
|
|
34216
|
+
compressed,
|
|
34299
34217
|
pty: requestedPty,
|
|
34300
34218
|
pty_rows: ptyRows,
|
|
34301
34219
|
pty_cols: ptyCols
|
|
@@ -34318,7 +34236,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34318
34236
|
if (response.status === "running" && taskId) {
|
|
34319
34237
|
if (effectiveBackground) {
|
|
34320
34238
|
trackBgTask(resolveSessionId(extCtx), taskId);
|
|
34321
|
-
return bashResult(
|
|
34239
|
+
return bashResult(formatBackgroundLaunch(taskId, requestedPty), { task_id: taskId });
|
|
34322
34240
|
}
|
|
34323
34241
|
const waitTimeoutMs = backgroundDisabled ? effectiveTimeout ?? DEFAULT_HARD_TIMEOUT_MS : effectiveTimeout !== undefined ? Math.min(effectiveTimeout, foregroundWaitMs) : foregroundWaitMs;
|
|
34324
34242
|
const startedAt = Date.now();
|
|
@@ -34328,7 +34246,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34328
34246
|
throw new Error(status.message ?? "bash_status failed");
|
|
34329
34247
|
}
|
|
34330
34248
|
if (isTerminalStatus(status.status)) {
|
|
34331
|
-
return bashResult(
|
|
34249
|
+
return bashResult(withBashHints(formatForegroundResult(status), bridgeCommand, aftSearchRegistered, extCtx.cwd), {
|
|
34332
34250
|
exit_code: status.exit_code,
|
|
34333
34251
|
duration_ms: status.duration_ms,
|
|
34334
34252
|
truncated: status.output_truncated,
|
|
@@ -34346,7 +34264,9 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34346
34264
|
throw new Error(promoted.message ?? "bash_promote failed");
|
|
34347
34265
|
}
|
|
34348
34266
|
trackBgTask(resolveSessionId(extCtx), taskId);
|
|
34349
|
-
return bashResult(
|
|
34267
|
+
return bashResult(formatPromotionMessage(taskId, effectiveTimeout, foregroundWaitMs), {
|
|
34268
|
+
task_id: taskId
|
|
34269
|
+
});
|
|
34350
34270
|
}
|
|
34351
34271
|
await sleep(FOREGROUND_POLL_INTERVAL_MS);
|
|
34352
34272
|
}
|
|
@@ -34359,7 +34279,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
34359
34279
|
task_id: taskId
|
|
34360
34280
|
};
|
|
34361
34281
|
const output = response.output ?? "";
|
|
34362
|
-
return bashResult(
|
|
34282
|
+
return bashResult(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
34363
34283
|
},
|
|
34364
34284
|
renderCall(args, theme, context) {
|
|
34365
34285
|
return renderBashCall(args?.command, args?.description, theme, context);
|
|
@@ -34413,13 +34333,13 @@ function createBashWatchTool(ctx) {
|
|
|
34413
34333
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
34414
34334
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
34415
34335
|
const waitFor = parseWaitPattern(params.pattern);
|
|
34416
|
-
if (params.background
|
|
34336
|
+
if (coerceBoolean(params.background)) {
|
|
34417
34337
|
if (!waitFor) {
|
|
34418
34338
|
throw new Error("invalid_request: Use auto-reminder; bash_watch without pattern in async mode is redundant");
|
|
34419
34339
|
}
|
|
34420
34340
|
const notifyParams = {
|
|
34421
34341
|
task_id: params.task_id,
|
|
34422
|
-
once: params.once
|
|
34342
|
+
once: coerceBoolean(params.once, true)
|
|
34423
34343
|
};
|
|
34424
34344
|
if (waitFor.kind === "regex")
|
|
34425
34345
|
notifyParams.regex = waitFor.source;
|
|
@@ -34445,7 +34365,7 @@ A notification will fire when the pattern matches or the task exits.`, watchDeta
|
|
|
34445
34365
|
}
|
|
34446
34366
|
const data = await waitForBashStatus(ctx, bridge, extCtx, params.task_id, undefined, waitFor, true, Math.min(coerceOptionalInt(params.timeout_ms, "timeout_ms", 1, MAX_BASH_STATUS_WAIT_TIMEOUT_MS) ?? DEFAULT_BASH_STATUS_WAIT_TIMEOUT_MS, MAX_BASH_STATUS_WAIT_TIMEOUT_MS));
|
|
34447
34367
|
if (data.waited?.reason === "user_message") {
|
|
34448
|
-
const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, params.once
|
|
34368
|
+
const convertedText = await convertToAsyncWatchOnAbort(bridge, extCtx, params.task_id, waitFor, coerceBoolean(params.once, true));
|
|
34449
34369
|
return textResult(convertedText, { waited: data.waited });
|
|
34450
34370
|
}
|
|
34451
34371
|
const text = await formatBashStatus(extCtx, params.task_id, data, undefined);
|
|
@@ -34561,9 +34481,31 @@ async function waitForBashStatus(ctx, bridge, extCtx, taskId, outputMode, waitFo
|
|
|
34561
34481
|
if (waitForExit)
|
|
34562
34482
|
markTaskWaiting(sessionId, taskId);
|
|
34563
34483
|
let sawTerminal = false;
|
|
34484
|
+
let lastData;
|
|
34564
34485
|
try {
|
|
34565
34486
|
while (true) {
|
|
34566
|
-
|
|
34487
|
+
let data;
|
|
34488
|
+
try {
|
|
34489
|
+
data = await bashStatusSnapshot(bridge, extCtx, taskId, outputMode, bridgeOptions);
|
|
34490
|
+
} catch (err) {
|
|
34491
|
+
if (!isBridgeTransportTimeout(err))
|
|
34492
|
+
throw err;
|
|
34493
|
+
if (isSyncWatchAborted(sessionId)) {
|
|
34494
|
+
return withWaited(lastData ?? unavailableSnapshot(), {
|
|
34495
|
+
reason: "user_message",
|
|
34496
|
+
elapsed_ms: Date.now() - startedAt
|
|
34497
|
+
});
|
|
34498
|
+
}
|
|
34499
|
+
if (Date.now() >= deadline) {
|
|
34500
|
+
return withWaited(lastData ?? unavailableSnapshot(), {
|
|
34501
|
+
reason: "unavailable",
|
|
34502
|
+
elapsed_ms: Date.now() - startedAt
|
|
34503
|
+
});
|
|
34504
|
+
}
|
|
34505
|
+
await sleep(Math.min(BASH_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now())));
|
|
34506
|
+
continue;
|
|
34507
|
+
}
|
|
34508
|
+
lastData = data;
|
|
34567
34509
|
const terminal = isTerminalStatus(data.status);
|
|
34568
34510
|
if (waitFor) {
|
|
34569
34511
|
const scan = await readNewTaskOutput(extCtx, taskId, data, spillCursor);
|
|
@@ -34755,6 +34697,9 @@ function formatWaitSummary(waited, details) {
|
|
|
34755
34697
|
if (waited.reason === "timeout") {
|
|
34756
34698
|
return `Waited ${waited.elapsed_ms}ms; timeout reached without match.`;
|
|
34757
34699
|
}
|
|
34700
|
+
if (waited.reason === "unavailable") {
|
|
34701
|
+
return `Waited ${waited.elapsed_ms}ms; the bridge stayed busy and status couldn't be read. The task may still be running — check with bash_status({ taskId }).`;
|
|
34702
|
+
}
|
|
34758
34703
|
const exit = typeof details.exit_code === "number" ? `, exit ${details.exit_code}` : "";
|
|
34759
34704
|
return `Waited ${waited.elapsed_ms}ms; task exited (${details.status}${exit}).`;
|
|
34760
34705
|
}
|
|
@@ -34924,7 +34869,7 @@ function registerConflictsTool(pi, ctx) {
|
|
|
34924
34869
|
const reqParams = {};
|
|
34925
34870
|
const path3 = params?.path;
|
|
34926
34871
|
if (typeof path3 === "string" && path3.trim() !== "") {
|
|
34927
|
-
await assertExternalDirectoryPermission(extCtx, path3,
|
|
34872
|
+
await assertExternalDirectoryPermission(extCtx, path3, {
|
|
34928
34873
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
34929
34874
|
});
|
|
34930
34875
|
reqParams.path = await resolvePathArg(extCtx.cwd, path3);
|
|
@@ -35015,14 +34960,14 @@ function registerFsTools(pi, ctx, surface) {
|
|
|
35015
34960
|
if (checked.has(file2))
|
|
35016
34961
|
continue;
|
|
35017
34962
|
checked.add(file2);
|
|
35018
|
-
await assertExternalDirectoryPermission(extCtx, file2,
|
|
34963
|
+
await assertExternalDirectoryPermission(extCtx, file2, {
|
|
35019
34964
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35020
34965
|
});
|
|
35021
34966
|
}
|
|
35022
34967
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
35023
34968
|
const response = await callBridge(bridge, "delete_file", {
|
|
35024
34969
|
files,
|
|
35025
|
-
recursive: params.recursive
|
|
34970
|
+
recursive: coerceBoolean(params.recursive)
|
|
35026
34971
|
}, extCtx);
|
|
35027
34972
|
const deletedEntries = response.deleted ?? [];
|
|
35028
34973
|
const skipped = response.skipped_files ?? [];
|
|
@@ -35059,7 +35004,7 @@ function registerFsTools(pi, ctx, surface) {
|
|
|
35059
35004
|
const destination = await resolvePathArg(extCtx.cwd, params.destination);
|
|
35060
35005
|
const checked = new Set([filePath, destination]);
|
|
35061
35006
|
for (const file2 of checked) {
|
|
35062
|
-
await assertExternalDirectoryPermission(extCtx, file2,
|
|
35007
|
+
await assertExternalDirectoryPermission(extCtx, file2, {
|
|
35063
35008
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35064
35009
|
});
|
|
35065
35010
|
}
|
|
@@ -35163,7 +35108,7 @@ function registerImportTools(pi, ctx) {
|
|
|
35163
35108
|
throw new Error(`op='${params.op}' requires 'module'`);
|
|
35164
35109
|
}
|
|
35165
35110
|
const filePath = await resolvePathArg(extCtx.cwd, params.filePath);
|
|
35166
|
-
await assertExternalDirectoryPermission(extCtx, filePath,
|
|
35111
|
+
await assertExternalDirectoryPermission(extCtx, filePath, {
|
|
35167
35112
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35168
35113
|
});
|
|
35169
35114
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
@@ -35239,7 +35184,7 @@ async function resolveAndGateScope(extCtx, ctx, scope) {
|
|
|
35239
35184
|
if (checked.has(target))
|
|
35240
35185
|
continue;
|
|
35241
35186
|
checked.add(target);
|
|
35242
|
-
await assertExternalDirectoryPermission(extCtx, target,
|
|
35187
|
+
await assertExternalDirectoryPermission(extCtx, target, {
|
|
35243
35188
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35244
35189
|
});
|
|
35245
35190
|
}
|
|
@@ -35463,7 +35408,7 @@ function registerInspectTool(pi, ctx) {
|
|
|
35463
35408
|
pi.registerTool({
|
|
35464
35409
|
name: "aft_inspect",
|
|
35465
35410
|
label: "inspect",
|
|
35466
|
-
description: "Codebase health snapshot. One call returns summary stats for: TODOs, diagnostics, file/symbol metrics, dead code, unused exports, code duplicates. Pass `sections` for per-category drill-down details.\n\n" + "Categories run in tiers — Tier 1 (todos, metrics) return synchronously from cache. Tier 2 (dead_code, unused_exports, duplicates)
|
|
35411
|
+
description: "Codebase health snapshot. One call returns summary stats for: TODOs, diagnostics, file/symbol metrics, dead code, unused exports, code duplicates. Pass `sections` for per-category drill-down details.\n\n" + "Categories run in tiers — Tier 1 (todos, metrics) return synchronously from cache. Tier 2 (dead_code, unused_exports, duplicates) waits for a fresh reuse scan up to a short deadline; if a category is still scanning the response reports `complete: false` with `pending_categories: [...]` rather than a fabricated clean count. Pi may still trigger a deduped background warmup for categories that remain pending.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
|
|
35467
35412
|
|
|
35468
35413
|
` + "Treat `dead_code` as a hint, not proof: reachability is call-based, so symbols reached only via method dispatch or referenced only in type position may be false positives — verify before deleting.",
|
|
35469
35414
|
parameters: InspectParams,
|
|
@@ -35472,11 +35417,16 @@ function registerInspectTool(pi, ctx) {
|
|
|
35472
35417
|
const sections = normalizeStringOrArray(params.sections);
|
|
35473
35418
|
const scope = await resolveAndGateScope(extCtx, ctx, normalizeStringOrArray(params.scope));
|
|
35474
35419
|
const topK = validateOptionalTopK(params.topK);
|
|
35475
|
-
const response = await callBridge(bridge, "inspect", { sections, scope, topK }, extCtx
|
|
35420
|
+
const response = await callBridge(bridge, "inspect", { sections, scope, topK }, extCtx, {
|
|
35421
|
+
keepBridgeOnTimeout: true
|
|
35422
|
+
});
|
|
35476
35423
|
runPendingTier2Categories(bridge, tier2RefreshCategories(response), extCtx);
|
|
35477
35424
|
const body = response.text;
|
|
35478
35425
|
if (typeof body === "string") {
|
|
35479
|
-
const
|
|
35426
|
+
const diagnosticsSummary = diagnosticsSummaryPart(asRecord3(response.summary));
|
|
35427
|
+
const diagnosticsDetail = diagnosticsDetailSection(asRecord3(response.details));
|
|
35428
|
+
const diagnostics = [diagnosticsSummary, diagnosticsDetail].filter(Boolean).join(`
|
|
35429
|
+
`);
|
|
35480
35430
|
const text = diagnostics ? body ? `${body}
|
|
35481
35431
|
|
|
35482
35432
|
${diagnostics}` : diagnostics : body;
|
|
@@ -35540,7 +35490,7 @@ function registerNavigateTool(pi, ctx) {
|
|
|
35540
35490
|
pi.registerTool({
|
|
35541
35491
|
name: "aft_callgraph",
|
|
35542
35492
|
label: "callgraph",
|
|
35543
|
-
description: "Answer code-relationship questions from a real call graph — instead of grep + read chains. Reach for this whenever the question is about how symbols connect. All ops require both `filePath` and `symbol`. Use `callers` for call sites (before renaming/signature changes), `impact` for blast radius (what breaks if a symbol changes), `call_tree` for what a function calls, `trace_to` for how execution reaches a symbol from entry points, `trace_to_symbol` for the shortest path from one symbol to another (requires `toSymbol`; if ambiguous, the error returns candidate files — retry with `toFile`), `trace_data` to follow a value across assignments/params.",
|
|
35493
|
+
description: "Answer code-relationship questions from a real call graph — instead of grep + read chains. Reach for this whenever the question is about how symbols connect. All ops require both `filePath` and `symbol`. Use `callers` for call sites (before renaming/signature changes), `impact` for blast radius (what breaks if a symbol changes), `call_tree` for what a function calls, `trace_to` for how execution reaches a symbol from entry points, `trace_to_symbol` for the shortest path from one symbol to another (requires `toSymbol`; if ambiguous, the error returns candidate files — retry with `toFile`), `trace_data` to follow a value across assignments/params. Markers: ~ = edge resolved by name only (may point at the wrong same-named symbol); [unresolved] = callee not resolved to a definition, so the location shown is the call site. Unmarked edges are resolved exactly.",
|
|
35544
35494
|
parameters: navigateParamsSchema(),
|
|
35545
35495
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
35546
35496
|
if (isEmptyParam(params.filePath)) {
|
|
@@ -35562,7 +35512,7 @@ function registerNavigateTool(pi, ctx) {
|
|
|
35562
35512
|
if (checked.has(target))
|
|
35563
35513
|
continue;
|
|
35564
35514
|
checked.add(target);
|
|
35565
|
-
await assertExternalDirectoryPermission(extCtx, target,
|
|
35515
|
+
await assertExternalDirectoryPermission(extCtx, target, {
|
|
35566
35516
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35567
35517
|
});
|
|
35568
35518
|
}
|
|
@@ -35642,7 +35592,7 @@ async function assertReadPathPermissions(extCtx, ctx, paths) {
|
|
|
35642
35592
|
if (!target || checked.has(target))
|
|
35643
35593
|
continue;
|
|
35644
35594
|
checked.add(target);
|
|
35645
|
-
await assertExternalDirectoryPermission(extCtx, target,
|
|
35595
|
+
await assertExternalDirectoryPermission(extCtx, target, {
|
|
35646
35596
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
35647
35597
|
});
|
|
35648
35598
|
}
|
|
@@ -35769,8 +35719,8 @@ Pass a single \`target\`:
|
|
|
35769
35719
|
parameters: OutlineParams,
|
|
35770
35720
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
35771
35721
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
35772
|
-
const target = params.target;
|
|
35773
|
-
const filesMode = params.files
|
|
35722
|
+
const target = coerceTargetParam(params.target);
|
|
35723
|
+
const filesMode = coerceBoolean(params.files);
|
|
35774
35724
|
const isArray = Array.isArray(target) && target.length > 0;
|
|
35775
35725
|
if (filesMode) {
|
|
35776
35726
|
if (Array.isArray(target)) {
|
|
@@ -35868,7 +35818,7 @@ Pass a single \`target\`:
|
|
|
35868
35818
|
const hasUrl = !isEmptyParam(params.url);
|
|
35869
35819
|
const hasTargets = hasTargetsProvided(params.targets);
|
|
35870
35820
|
const hasSymbols = !isEmptyParam(params.symbols);
|
|
35871
|
-
const wantCallgraph = params.callgraph
|
|
35821
|
+
const wantCallgraph = coerceBoolean(params.callgraph);
|
|
35872
35822
|
if (hasTargets) {
|
|
35873
35823
|
if (hasFilePath || hasUrl || hasSymbols) {
|
|
35874
35824
|
throw new Error("'targets' is mutually exclusive with 'filePath', 'url', and 'symbols'");
|
|
@@ -36137,7 +36087,7 @@ function registerRefactorTool(pi, ctx) {
|
|
|
36137
36087
|
if (checked.has(target))
|
|
36138
36088
|
continue;
|
|
36139
36089
|
checked.add(target);
|
|
36140
|
-
await assertExternalDirectoryPermission(extCtx, target,
|
|
36090
|
+
await assertExternalDirectoryPermission(extCtx, target, {
|
|
36141
36091
|
restrictToProjectRoot: ctx.config.restrict_to_project_root ?? false
|
|
36142
36092
|
});
|
|
36143
36093
|
}
|
|
@@ -36290,7 +36240,7 @@ function registerSafetyTool(pi, ctx) {
|
|
|
36290
36240
|
previewReq.file = filePath;
|
|
36291
36241
|
const preview = await callBridge(bridge, "undo_preview", previewReq, extCtx);
|
|
36292
36242
|
for (const file2 of new Set(responsePaths(preview))) {
|
|
36293
|
-
await assertExternalDirectoryPermission(extCtx, file2,
|
|
36243
|
+
await assertExternalDirectoryPermission(extCtx, file2, {
|
|
36294
36244
|
restrictToProjectRoot
|
|
36295
36245
|
});
|
|
36296
36246
|
}
|
|
@@ -36303,7 +36253,7 @@ function registerSafetyTool(pi, ctx) {
|
|
|
36303
36253
|
if (checked.has(file2))
|
|
36304
36254
|
continue;
|
|
36305
36255
|
checked.add(file2);
|
|
36306
|
-
await assertExternalDirectoryPermission(extCtx, file2,
|
|
36256
|
+
await assertExternalDirectoryPermission(extCtx, file2, {
|
|
36307
36257
|
restrictToProjectRoot
|
|
36308
36258
|
});
|
|
36309
36259
|
}
|
|
@@ -36312,7 +36262,7 @@ function registerSafetyTool(pi, ctx) {
|
|
|
36312
36262
|
if (params.op === "restore" && params.name) {
|
|
36313
36263
|
const preview = await callBridge(bridge, "checkpoint_paths", { name: params.name }, extCtx);
|
|
36314
36264
|
for (const file2 of new Set(responsePaths(preview))) {
|
|
36315
|
-
await assertExternalDirectoryPermission(extCtx, file2,
|
|
36265
|
+
await assertExternalDirectoryPermission(extCtx, file2, {
|
|
36316
36266
|
restrictToProjectRoot
|
|
36317
36267
|
});
|
|
36318
36268
|
}
|
|
@@ -36390,6 +36340,10 @@ var SearchParams2 = Type13.Object({
|
|
|
36390
36340
|
Type13.Literal("auto")
|
|
36391
36341
|
], {
|
|
36392
36342
|
description: "Optional routing hint. Defaults to 'auto'."
|
|
36343
|
+
})),
|
|
36344
|
+
includeTests: Type13.Optional(Type13.Boolean({
|
|
36345
|
+
default: false,
|
|
36346
|
+
description: "Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false."
|
|
36393
36347
|
}))
|
|
36394
36348
|
});
|
|
36395
36349
|
function buildSemanticSections(args, payload, theme) {
|
|
@@ -36495,6 +36449,8 @@ function registerSemanticTool(pi, ctx) {
|
|
|
36495
36449
|
req.top_k = params.topK;
|
|
36496
36450
|
if (params.hint !== undefined)
|
|
36497
36451
|
req.hint = params.hint;
|
|
36452
|
+
if (params.includeTests !== undefined)
|
|
36453
|
+
req.include_tests = params.includeTests;
|
|
36498
36454
|
const response = await callBridge(bridge, "semantic_search", req, extCtx);
|
|
36499
36455
|
let agentText = response.text ?? "No results.";
|
|
36500
36456
|
const extra = extraAgentHonestyNote(response);
|
|
@@ -36528,7 +36484,7 @@ function buildWorkflowHints(opts) {
|
|
|
36528
36484
|
const hasBgBash = opts.bashBackgroundEnabled && hasBash && !opts.absentTools.has("bash_status");
|
|
36529
36485
|
if (hasBash && opts.bashCompressionEnabled) {
|
|
36530
36486
|
sections.push([
|
|
36531
|
-
"**Test/build output**: bash output is auto-compressed
|
|
36487
|
+
"**Test/build output**: bash output is auto-compressed for non-piped commands. Piped commands run verbatim and show the pipeline's output. For AFT's test/build summary, run the runner without filters:",
|
|
36532
36488
|
"- `bun test | grep fail` → run `bun test`",
|
|
36533
36489
|
"- `cargo test 2>&1 | tail -20` → run `cargo test`",
|
|
36534
36490
|
"- `npm run build | head -50` → run `npm run build`"
|
|
@@ -36567,11 +36523,9 @@ function buildWorkflowHints(opts) {
|
|
|
36567
36523
|
}
|
|
36568
36524
|
if (hasBgBash) {
|
|
36569
36525
|
sections.push([
|
|
36570
|
-
`**Long-running commands** (builds, installs, full test suites): \`${bashName}({
|
|
36571
|
-
"
|
|
36572
|
-
"
|
|
36573
|
-
"3. Want to react to a specific early output line → async `bash_watch` (background:true + pattern).",
|
|
36574
|
-
"Never loop `bash_status` to wait — it's a one-shot inspector, not a wait primitive."
|
|
36526
|
+
`**Long-running commands** (builds, installs, full test suites): run them in the FOREGROUND — \`${bashName}({ command })\` waits and returns the result in ONE step, and if it outlives the short wait window it auto-promotes to background and delivers a completion reminder when it finishes. Don't reach for \`background: true\` for the common "I'm waiting on this result" case — that costs an extra turn.`,
|
|
36527
|
+
"- `background: true` is ONLY for when you have OTHER useful work to do while it runs: start it, do the other work, and the completion reminder delivers the result (or spawn a subagent for the side work). Do NOT background a command and then immediately `bash_watch` it — that spends a whole extra turn waiting for something foreground returns in one.",
|
|
36528
|
+
"- `bash_watch` is for blocking on an ALREADY-backgrounded task once you've run out of parallel work (sync — the user can interrupt), or reacting to a specific early output line (async: background:true + pattern). Never loop `bash_status` to wait — it's a one-shot inspector."
|
|
36575
36529
|
].join(`
|
|
36576
36530
|
`));
|
|
36577
36531
|
sections.push(`**PTY / interactive commands**: PTY mode is for interactive REPLs and terminal apps (python, node, bash itself, vim). Start with \`${bashName}({ command: "python", pty: true, background: true })\`, read the screen with \`bash_status({ task_id, output_mode: "screen" })\`, and send input with \`bash_write({ task_id, input: "..." })\`.`);
|
|
@@ -36673,11 +36627,12 @@ var PLUGIN_VERSION = (() => {
|
|
|
36673
36627
|
return "0.0.0";
|
|
36674
36628
|
}
|
|
36675
36629
|
})();
|
|
36676
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
36630
|
+
var ANNOUNCEMENT_VERSION = "0.40.0";
|
|
36677
36631
|
var ANNOUNCEMENT_FEATURES = [
|
|
36678
|
-
"
|
|
36679
|
-
"
|
|
36680
|
-
"
|
|
36632
|
+
"Groundwork for Subconscious, the CortexKit daemon: configuration now lives in one place under ~/.config/cortexkit/ and <project>/.cortexkit/ (auto-migrated). The daemon integration is dormant — nothing changes in how you run AFT today.",
|
|
36633
|
+
"Bash output never hides a failure: piped commands run exactly as written with their real exit status, cancelled tasks report as failed, and a failing run is never compressed to a clean-looking summary.",
|
|
36634
|
+
"The top aft_search result is now the complete, ready-to-edit symbol (no re-read needed); test files are hidden from results by default.",
|
|
36635
|
+
"format_on_edit is now off by default, and bash commands default to the foreground."
|
|
36681
36636
|
];
|
|
36682
36637
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
|
|
36683
36638
|
var ALL_ONLY_TOOLS = new Set(["aft_callgraph", "aft_delete", "aft_move", "aft_refactor"]);
|
|
@@ -36686,11 +36641,25 @@ function isConfigureWarning(value) {
|
|
|
36686
36641
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
36687
36642
|
return false;
|
|
36688
36643
|
const warning = value;
|
|
36689
|
-
return (warning.kind === "formatter_not_installed" || warning.kind === "checker_not_installed" || warning.kind === "lsp_binary_missing" || warning.kind === "config_parse_failed") && typeof warning.hint === "string";
|
|
36644
|
+
return (warning.kind === "formatter_not_installed" || warning.kind === "checker_not_installed" || warning.kind === "lsp_binary_missing" || warning.kind === "config_parse_failed" || warning.kind === "config_key_dropped") && typeof warning.hint === "string";
|
|
36690
36645
|
}
|
|
36691
36646
|
function coerceConfigureWarnings(warnings) {
|
|
36692
36647
|
return warnings.filter(isConfigureWarning);
|
|
36693
36648
|
}
|
|
36649
|
+
function isDroppedConfigKey(value) {
|
|
36650
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
36651
|
+
return false;
|
|
36652
|
+
const dropped = value;
|
|
36653
|
+
return typeof dropped.key === "string" && typeof dropped.tier === "string" && typeof dropped.reason === "string";
|
|
36654
|
+
}
|
|
36655
|
+
function coerceDroppedKeyWarnings(droppedKeys) {
|
|
36656
|
+
if (!Array.isArray(droppedKeys))
|
|
36657
|
+
return [];
|
|
36658
|
+
return formatDroppedKeyWarnings(droppedKeys.filter(isDroppedConfigKey)).map((hint) => ({
|
|
36659
|
+
kind: "config_key_dropped",
|
|
36660
|
+
hint
|
|
36661
|
+
}));
|
|
36662
|
+
}
|
|
36694
36663
|
function drainPendingEagerWarnings(projectRoot) {
|
|
36695
36664
|
const pending = pendingEagerWarnings.get(projectRoot) ?? [];
|
|
36696
36665
|
pendingEagerWarnings.delete(projectRoot);
|
|
@@ -36717,7 +36686,10 @@ function bridgeDirectoryFromCallback(bridge, fallback) {
|
|
|
36717
36686
|
return typeof cwd === "string" && cwd.length > 0 ? cwd : fallback;
|
|
36718
36687
|
}
|
|
36719
36688
|
async function handleConfigureWarningsForSession(context) {
|
|
36720
|
-
const validWarnings =
|
|
36689
|
+
const validWarnings = [
|
|
36690
|
+
...coerceConfigureWarnings(context.warnings),
|
|
36691
|
+
...coerceDroppedKeyWarnings(context.configDroppedKeys)
|
|
36692
|
+
];
|
|
36721
36693
|
if (!context.sessionId) {
|
|
36722
36694
|
if (validWarnings.length === 0)
|
|
36723
36695
|
return;
|
|
@@ -36815,6 +36787,25 @@ async function src_default(pi) {
|
|
|
36815
36787
|
return;
|
|
36816
36788
|
}
|
|
36817
36789
|
await ensureStorageMigrated({ harness: "pi", binaryPath, logger: bridgeLogger });
|
|
36790
|
+
const deliverConfigMigrationWarnings = (messages) => {
|
|
36791
|
+
for (const message of messages) {
|
|
36792
|
+
const notify = pi.ui?.notify;
|
|
36793
|
+
if (typeof notify === "function") {
|
|
36794
|
+
try {
|
|
36795
|
+
notify(message, "warning");
|
|
36796
|
+
continue;
|
|
36797
|
+
} catch (err) {
|
|
36798
|
+
warn2(`[config] failed to deliver migration notification: ${err}`);
|
|
36799
|
+
}
|
|
36800
|
+
}
|
|
36801
|
+
try {
|
|
36802
|
+
process.stderr.write(`
|
|
36803
|
+
[AFT] ${message}
|
|
36804
|
+
`);
|
|
36805
|
+
} catch {}
|
|
36806
|
+
}
|
|
36807
|
+
};
|
|
36808
|
+
deliverConfigMigrationWarnings(migrateAftConfigLocations(process.cwd(), bridgeLogger).flatMap((result) => result.warnings));
|
|
36818
36809
|
const config2 = loadAftConfig(process.cwd());
|
|
36819
36810
|
enqueueConfigParseWarnings(process.cwd(), getConfigLoadErrors());
|
|
36820
36811
|
const storageDir = resolveCortexKitStorageRoot();
|
|
@@ -36825,10 +36816,9 @@ async function src_default(pi) {
|
|
|
36825
36816
|
return null;
|
|
36826
36817
|
});
|
|
36827
36818
|
}
|
|
36828
|
-
const configOverrides =
|
|
36829
|
-
|
|
36830
|
-
|
|
36831
|
-
configOverrides.storage_dir = storageDir;
|
|
36819
|
+
const configOverrides = buildConfigTierConfigureParams(process.cwd(), {
|
|
36820
|
+
storage_dir: storageDir
|
|
36821
|
+
});
|
|
36832
36822
|
try {
|
|
36833
36823
|
const lspAutoInstall = config2.lsp?.auto_install ?? true;
|
|
36834
36824
|
const lspGraceDays = config2.lsp?.grace_days ?? 7;
|
|
@@ -36896,7 +36886,7 @@ ${lines}
|
|
|
36896
36886
|
errorPrefix: "[aft-pi]",
|
|
36897
36887
|
minVersion: PLUGIN_VERSION,
|
|
36898
36888
|
onVersionMismatch: createVersionMismatchHandler(() => pool),
|
|
36899
|
-
onConfigureWarnings: ({ projectRoot, sessionId, client, warnings }) => {
|
|
36889
|
+
onConfigureWarnings: ({ projectRoot, sessionId, client, warnings, configDroppedKeys }) => {
|
|
36900
36890
|
const bridge = pool.getActiveBridgeForRoot(projectRoot);
|
|
36901
36891
|
if (!bridge)
|
|
36902
36892
|
return;
|
|
@@ -36908,6 +36898,7 @@ ${lines}
|
|
|
36908
36898
|
client,
|
|
36909
36899
|
bridge,
|
|
36910
36900
|
warnings: [...pendingWarnings, ...warnings],
|
|
36901
|
+
configDroppedKeys,
|
|
36911
36902
|
storageDir,
|
|
36912
36903
|
pluginVersion: PLUGIN_VERSION
|
|
36913
36904
|
});
|
|
@@ -36967,7 +36958,7 @@ ${lines}
|
|
|
36967
36958
|
if (onnxRuntimePromise) {
|
|
36968
36959
|
await Promise.race([
|
|
36969
36960
|
onnxRuntimePromise,
|
|
36970
|
-
new Promise((
|
|
36961
|
+
new Promise((resolve9) => setTimeout(() => resolve9(null), 60000))
|
|
36971
36962
|
]);
|
|
36972
36963
|
}
|
|
36973
36964
|
const bridge = pool.getBridge(cwd);
|