@cortexkit/aft 0.39.1 → 0.39.3
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -107,7 +107,10 @@ var init_active_logger = __esm(() => {
|
|
|
107
107
|
// ../aft-bridge/dist/bash-hints.js
|
|
108
108
|
var init_bash_hints = () => {};
|
|
109
109
|
// ../aft-bridge/dist/command-timeouts.js
|
|
110
|
-
|
|
110
|
+
function isPassiveCommand(command) {
|
|
111
|
+
return PASSIVE_COMMANDS.has(command);
|
|
112
|
+
}
|
|
113
|
+
var LONG_RUNNING_COMMAND_TIMEOUT_MS, PASSIVE_COMMANDS, PASSIVE_COMMAND_TIMEOUT_MS = 5000;
|
|
111
114
|
var init_command_timeouts = __esm(() => {
|
|
112
115
|
LONG_RUNNING_COMMAND_TIMEOUT_MS = {
|
|
113
116
|
callers: 60000,
|
|
@@ -119,6 +122,7 @@ var init_command_timeouts = __esm(() => {
|
|
|
119
122
|
glob: 60000,
|
|
120
123
|
semantic_search: 60000
|
|
121
124
|
};
|
|
125
|
+
PASSIVE_COMMANDS = new Set(["status"]);
|
|
122
126
|
});
|
|
123
127
|
|
|
124
128
|
// ../aft-bridge/dist/status-bar.js
|
|
@@ -161,6 +165,10 @@ function bashTaskIdFrom(response) {
|
|
|
161
165
|
function tagStderrLine(line) {
|
|
162
166
|
return /^\[aft(-\w+)?\] /.test(line) ? line : `[aft] ${line}`;
|
|
163
167
|
}
|
|
168
|
+
function shouldSurfaceStderrLine(line) {
|
|
169
|
+
const normalized = line.trim();
|
|
170
|
+
return !(normalized === `Error in cpuinfo: ${BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE}` || normalized === BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE);
|
|
171
|
+
}
|
|
164
172
|
function compareSemver(a, b) {
|
|
165
173
|
const [aMain, aPre] = a.split("-", 2);
|
|
166
174
|
const [bMain, bPre] = b.split("-", 2);
|
|
@@ -226,7 +234,7 @@ function clampSemanticTimeout(configOverrides, bridgeTimeoutMs) {
|
|
|
226
234
|
}
|
|
227
235
|
};
|
|
228
236
|
}
|
|
229
|
-
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000, BRIDGE_HANG_TIMEOUT_THRESHOLD = 2, SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000, MAX_STDOUT_BUFFER, STDOUT_BUFFER_COMPACT_THRESHOLD, TERMINAL_BASH_STATUSES, BridgeReplacedDuringVersionCheck, BinaryBridge;
|
|
237
|
+
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000, BRIDGE_HANG_TIMEOUT_THRESHOLD = 2, SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000, MAX_STDOUT_BUFFER, STDOUT_BUFFER_COMPACT_THRESHOLD, TERMINAL_BASH_STATUSES, BENIGN_CPUINFO_PROC_CPUINFO_PARSE_FAILURE = "failed to parse processor information from /proc/cpuinfo", BridgeReplacedDuringVersionCheck, BinaryBridge;
|
|
230
238
|
var init_bridge = __esm(() => {
|
|
231
239
|
init_active_logger();
|
|
232
240
|
init_command_timeouts();
|
|
@@ -264,6 +272,7 @@ var init_bridge = __esm(() => {
|
|
|
264
272
|
_restartCount = 0;
|
|
265
273
|
_shuttingDown = false;
|
|
266
274
|
timeoutMs;
|
|
275
|
+
hangThreshold;
|
|
267
276
|
maxRestarts;
|
|
268
277
|
configured = false;
|
|
269
278
|
_configurePromise = null;
|
|
@@ -288,6 +297,7 @@ var init_bridge = __esm(() => {
|
|
|
288
297
|
this.binaryPath = binaryPath;
|
|
289
298
|
this.cwd = cwd;
|
|
290
299
|
this.timeoutMs = options?.timeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS;
|
|
300
|
+
this.hangThreshold = options?.hangThreshold ?? BRIDGE_HANG_TIMEOUT_THRESHOLD;
|
|
291
301
|
this.maxRestarts = options?.maxRestarts ?? 3;
|
|
292
302
|
this.configOverrides = clampSemanticTimeout(configOverrides ?? {}, this.timeoutMs);
|
|
293
303
|
this.minVersion = options?.minVersion;
|
|
@@ -405,7 +415,9 @@ var init_bridge = __esm(() => {
|
|
|
405
415
|
if (requestSessionId && options?.configureWarningClient !== undefined) {
|
|
406
416
|
this.configureWarningClients.set(requestSessionId, options.configureWarningClient);
|
|
407
417
|
}
|
|
408
|
-
const
|
|
418
|
+
const passive = isPassiveCommand(command);
|
|
419
|
+
const resolvedTimeoutMs = options?.transportTimeoutMs ?? options?.timeoutMs ?? this.timeoutMs;
|
|
420
|
+
const effectiveTimeoutMs = passive ? Math.min(resolvedTimeoutMs, PASSIVE_COMMAND_TIMEOUT_MS) : resolvedTimeoutMs;
|
|
409
421
|
const implicitTransportOptions = {
|
|
410
422
|
...options?.transportTimeoutMs !== undefined || options?.timeoutMs !== undefined ? { transportTimeoutMs: effectiveTimeoutMs } : {},
|
|
411
423
|
markConfiguredOnSuccess: false
|
|
@@ -455,7 +467,7 @@ var init_bridge = __esm(() => {
|
|
|
455
467
|
}
|
|
456
468
|
const line = `${JSON.stringify(request)}
|
|
457
469
|
`;
|
|
458
|
-
const keepBridgeOnTimeout = options?.keepBridgeOnTimeout === true;
|
|
470
|
+
const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
|
|
459
471
|
let requestSentAt = Date.now();
|
|
460
472
|
const response = await new Promise((resolve, reject) => {
|
|
461
473
|
const timer = setTimeout(() => {
|
|
@@ -477,7 +489,7 @@ var init_bridge = __esm(() => {
|
|
|
477
489
|
const childActiveSinceRequest = this.lastChildActivityAt > requestSentAt;
|
|
478
490
|
const consecutiveTimeouts = this.consecutiveRequestTimeouts + 1;
|
|
479
491
|
this.consecutiveRequestTimeouts = consecutiveTimeouts;
|
|
480
|
-
const keepWarm = childActiveSinceRequest || consecutiveTimeouts <
|
|
492
|
+
const keepWarm = childActiveSinceRequest || consecutiveTimeouts < this.hangThreshold;
|
|
481
493
|
const restartSuffix = keepWarm ? " — bridge kept warm" : " — restarting bridge";
|
|
482
494
|
const timeoutMsg = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms${restartSuffix}`;
|
|
483
495
|
if (requestSessionId) {
|
|
@@ -772,7 +784,7 @@ var init_bridge = __esm(() => {
|
|
|
772
784
|
`)) !== -1) {
|
|
773
785
|
const line = this.stderrBuffer.slice(0, newlineIdx).replace(/\r$/, "");
|
|
774
786
|
this.stderrBuffer = this.stderrBuffer.slice(newlineIdx + 1);
|
|
775
|
-
if (!line)
|
|
787
|
+
if (!line || !shouldSurfaceStderrLine(line))
|
|
776
788
|
continue;
|
|
777
789
|
const tagged = tagStderrLine(line);
|
|
778
790
|
this.logVia(tagged);
|
|
@@ -782,7 +794,7 @@ var init_bridge = __esm(() => {
|
|
|
782
794
|
flushStderrBuffer() {
|
|
783
795
|
const line = this.stderrBuffer.replace(/\r$/, "");
|
|
784
796
|
this.stderrBuffer = "";
|
|
785
|
-
if (!line)
|
|
797
|
+
if (!line || !shouldSurfaceStderrLine(line))
|
|
786
798
|
return;
|
|
787
799
|
const tagged = tagStderrLine(line);
|
|
788
800
|
this.logVia(tagged);
|
|
@@ -1008,6 +1020,9 @@ var init_bridge = __esm(() => {
|
|
|
1008
1020
|
}
|
|
1009
1021
|
};
|
|
1010
1022
|
});
|
|
1023
|
+
|
|
1024
|
+
// ../aft-bridge/dist/callgraph-format.js
|
|
1025
|
+
var init_callgraph_format = () => {};
|
|
1011
1026
|
// ../aft-bridge/dist/platform.js
|
|
1012
1027
|
var init_platform = () => {};
|
|
1013
1028
|
|
|
@@ -1304,6 +1319,7 @@ class BridgePool {
|
|
|
1304
1319
|
this.projectConfigLoader = options.projectConfigLoader;
|
|
1305
1320
|
this.bridgeOptions = {
|
|
1306
1321
|
timeoutMs: options.timeoutMs,
|
|
1322
|
+
hangThreshold: options.hangThreshold,
|
|
1307
1323
|
maxRestarts: options.maxRestarts,
|
|
1308
1324
|
minVersion: options.minVersion,
|
|
1309
1325
|
onVersionMismatch: options.onVersionMismatch,
|
|
@@ -1470,6 +1486,7 @@ var init_dist = __esm(() => {
|
|
|
1470
1486
|
init_active_logger();
|
|
1471
1487
|
init_bash_hints();
|
|
1472
1488
|
init_bridge();
|
|
1489
|
+
init_callgraph_format();
|
|
1473
1490
|
init_command_timeouts();
|
|
1474
1491
|
init_downloader();
|
|
1475
1492
|
init_migration();
|
|
@@ -12375,11 +12392,232 @@ var init_binary_cache = __esm(() => {
|
|
|
12375
12392
|
init_paths2();
|
|
12376
12393
|
});
|
|
12377
12394
|
|
|
12378
|
-
// src/lib/
|
|
12379
|
-
import {
|
|
12395
|
+
// src/lib/sanitize.ts
|
|
12396
|
+
import { realpathSync as realpathSync2 } from "node:fs";
|
|
12397
|
+
import { homedir as homedir8, userInfo } from "node:os";
|
|
12398
|
+
function escapeRegex(value) {
|
|
12399
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12400
|
+
}
|
|
12401
|
+
function safeRealpath(p2) {
|
|
12402
|
+
try {
|
|
12403
|
+
return realpathSync2(p2);
|
|
12404
|
+
} catch {
|
|
12405
|
+
return null;
|
|
12406
|
+
}
|
|
12407
|
+
}
|
|
12408
|
+
function isSensitiveKeyName(keyName) {
|
|
12409
|
+
return SENSITIVE_KEY_WORD.test(keyName) || SEGMENTED_KEY_WORD.test(keyName) || CAMEL_CASE_KEY_WORD.test(keyName);
|
|
12410
|
+
}
|
|
12411
|
+
function redactSecrets(content) {
|
|
12412
|
+
let sanitized = content;
|
|
12413
|
+
sanitized = sanitized.replace(/\b((?:Proxy-)?Authorization[^\S\r\n]*:[^\S\r\n]*(?:Bearer|Basic)[^\S\r\n]+)[A-Za-z0-9._~+/-]+=*/gi, `$1${SECRET_PLACEHOLDER}`);
|
|
12414
|
+
sanitized = sanitized.replace(/\bgithub_pat_[A-Za-z0-9_]+\b/g, SECRET_PLACEHOLDER);
|
|
12415
|
+
sanitized = sanitized.replace(/\bgh(?:p|o|s)_[A-Za-z0-9_]{16,}\b/g, SECRET_PLACEHOLDER);
|
|
12416
|
+
sanitized = sanitized.replace(/\bsk-(?:live-)?[A-Za-z0-9][A-Za-z0-9_-]{7,}\b/g, SECRET_PLACEHOLDER);
|
|
12417
|
+
sanitized = sanitized.replace(JWT_PATTERN, SECRET_PLACEHOLDER);
|
|
12418
|
+
sanitized = sanitized.replace(AWS_ACCESS_KEY_ID_PATTERN, SECRET_PLACEHOLDER);
|
|
12419
|
+
sanitized = sanitized.replace(quotedSensitiveKeyValuePattern, (match, prefix, _keyQuote, keyName, valueQuote) => isSensitiveKeyName(keyName) ? `${prefix}${valueQuote}${SECRET_PLACEHOLDER}${valueQuote}` : match);
|
|
12420
|
+
sanitized = sanitized.replace(unquotedSensitiveKeyValuePattern, (match, prefix, keyName, valueQuote) => isSensitiveKeyName(keyName) ? `${prefix}${valueQuote}${SECRET_PLACEHOLDER}${valueQuote}` : match);
|
|
12421
|
+
sanitized = sanitized.replace(bareSensitiveKeyValuePattern, (match, prefix, keyName) => isSensitiveKeyName(keyName) ? `${prefix}${SECRET_PLACEHOLDER}` : match);
|
|
12422
|
+
sanitized = sanitized.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^@\s/?#]+@/gi, `$1${URL_CREDENTIAL_PLACEHOLDER}@`);
|
|
12423
|
+
sanitized = sanitized.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "<EMAIL>");
|
|
12424
|
+
return sanitized;
|
|
12425
|
+
}
|
|
12426
|
+
function sanitizeContent(content) {
|
|
12427
|
+
const username = userInfo().username;
|
|
12428
|
+
const home = homedir8();
|
|
12429
|
+
let sanitized = redactSecrets(content);
|
|
12430
|
+
const cwd = process.cwd();
|
|
12431
|
+
for (const candidate of new Set([cwd, safeRealpath(cwd)])) {
|
|
12432
|
+
if (candidate && candidate !== "/" && candidate !== home) {
|
|
12433
|
+
sanitized = sanitized.replace(new RegExp(escapeRegex(candidate), "g"), "<PROJECT>");
|
|
12434
|
+
}
|
|
12435
|
+
}
|
|
12436
|
+
if (home) {
|
|
12437
|
+
sanitized = sanitized.replace(new RegExp(escapeRegex(home), "g"), "~");
|
|
12438
|
+
}
|
|
12439
|
+
sanitized = sanitized.replace(/\/Users\/[^/\s"']+/g, "/Users/<USER>");
|
|
12440
|
+
sanitized = sanitized.replace(/\/home\/[^/\s"']+/g, "/home/<USER>");
|
|
12441
|
+
sanitized = sanitized.replace(/([A-Za-z]:\\\\Users\\\\)[^\\\\"'\s]+/g, "$1<USER>");
|
|
12442
|
+
sanitized = sanitized.replace(/([A-Za-z]:\\Users\\)[^\\"'\s]+/g, "$1<USER>");
|
|
12443
|
+
sanitized = sanitized.replace(/([A-Za-z]:\/Users\/)[^/\s"']+/g, "$1<USER>");
|
|
12444
|
+
if (username) {
|
|
12445
|
+
sanitized = sanitized.replace(new RegExp(escapeRegex(username), "g"), "<USER>");
|
|
12446
|
+
}
|
|
12447
|
+
return sanitized;
|
|
12448
|
+
}
|
|
12449
|
+
function sanitizeValue(value) {
|
|
12450
|
+
if (typeof value === "string") {
|
|
12451
|
+
return sanitizeContent(value);
|
|
12452
|
+
}
|
|
12453
|
+
if (Array.isArray(value)) {
|
|
12454
|
+
return value.map((entry) => sanitizeValue(entry));
|
|
12455
|
+
}
|
|
12456
|
+
if (value && typeof value === "object") {
|
|
12457
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, sanitizeValue(entry)]));
|
|
12458
|
+
}
|
|
12459
|
+
return value;
|
|
12460
|
+
}
|
|
12461
|
+
var SECRET_PLACEHOLDER = "<REDACTED_SECRET>", URL_CREDENTIAL_PLACEHOLDER = "***", KEY_NAME = "[A-Za-z_][A-Za-z0-9_.-]*", SENSITIVE_KEY_WORD, SEGMENTED_KEY_WORD, CAMEL_CASE_KEY_WORD, JWT_PATTERN, AWS_ACCESS_KEY_ID_PATTERN, quotedSensitiveKeyValuePattern, unquotedSensitiveKeyValuePattern, bareSensitiveKeyValuePattern;
|
|
12462
|
+
var init_sanitize = __esm(() => {
|
|
12463
|
+
SENSITIVE_KEY_WORD = /(?:token|password|secret|api[_-]?key|passwd|pwd|credential)/i;
|
|
12464
|
+
SEGMENTED_KEY_WORD = /(?:^|[_.-])key(?:$|[_.-])/i;
|
|
12465
|
+
CAMEL_CASE_KEY_WORD = /[a-z0-9]Key(?:$|[A-Z_.-])/;
|
|
12466
|
+
JWT_PATTERN = /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g;
|
|
12467
|
+
AWS_ACCESS_KEY_ID_PATTERN = /\b(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}\b/g;
|
|
12468
|
+
quotedSensitiveKeyValuePattern = new RegExp(String.raw`((['"])(${KEY_NAME})\2[^\S\r\n]*:[^\S\r\n]*)(['"])([^'"\r\n]+)\4`, "gi");
|
|
12469
|
+
unquotedSensitiveKeyValuePattern = new RegExp(String.raw`\b((${KEY_NAME})[^\S\r\n]*[=:][^\S\r\n]*)(['"])([^'"\r\n]+)\3`, "gi");
|
|
12470
|
+
bareSensitiveKeyValuePattern = new RegExp(String.raw`\b((${KEY_NAME})[^\S\r\n]*[=:][^\S\r\n]*)([^\s,;&'"]+)`, "gi");
|
|
12471
|
+
});
|
|
12472
|
+
|
|
12473
|
+
// src/lib/bridge-tool-failures.ts
|
|
12474
|
+
import { closeSync as closeSync2, existsSync as existsSync10, openSync as openSync2, readSync as readSync2, statSync as statSync6 } from "node:fs";
|
|
12475
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
12380
12476
|
import { join as join10 } from "node:path";
|
|
12477
|
+
function resolveBridgePluginLogPath() {
|
|
12478
|
+
const isTestEnv = process.env.BUN_TEST === "1" || false;
|
|
12479
|
+
return join10(tmpdir2(), isTestEnv ? "aft-plugin-test.log" : "aft-plugin.log");
|
|
12480
|
+
}
|
|
12481
|
+
function tailLogFileBytes(path, maxBytes) {
|
|
12482
|
+
if (!existsSync10(path) || maxBytes <= 0)
|
|
12483
|
+
return "";
|
|
12484
|
+
let fd = null;
|
|
12485
|
+
try {
|
|
12486
|
+
const size = statSync6(path).size;
|
|
12487
|
+
if (size === 0)
|
|
12488
|
+
return "";
|
|
12489
|
+
const readLength = Math.min(size, maxBytes);
|
|
12490
|
+
const position = size - readLength;
|
|
12491
|
+
fd = openSync2(path, "r");
|
|
12492
|
+
const buffer = Buffer.allocUnsafe(readLength);
|
|
12493
|
+
const bytesRead = readSync2(fd, buffer, 0, readLength, position);
|
|
12494
|
+
return buffer.subarray(0, bytesRead).toString("utf-8").trim();
|
|
12495
|
+
} catch {
|
|
12496
|
+
return "";
|
|
12497
|
+
} finally {
|
|
12498
|
+
if (fd !== null) {
|
|
12499
|
+
try {
|
|
12500
|
+
closeSync2(fd);
|
|
12501
|
+
} catch {}
|
|
12502
|
+
}
|
|
12503
|
+
}
|
|
12504
|
+
}
|
|
12505
|
+
function stripSessionTags(line) {
|
|
12506
|
+
return line.replace(SESSION_TAG_PATTERN, "").replace(/\s+/g, " ").trim();
|
|
12507
|
+
}
|
|
12508
|
+
function stripPathLikeTokens(label) {
|
|
12509
|
+
let out = label;
|
|
12510
|
+
out = out.replace(/\/(?:Users|home|var|tmp|private|Volumes)\/[^\s"'`,;)]+/gi, "<path>");
|
|
12511
|
+
out = out.replace(/[A-Za-z]:\\(?:Users|Program Files)[^\\s"'`,;)]+/gi, "<path>");
|
|
12512
|
+
out = out.replace(/file:\/\/[^\s"'`,;)]+/gi, "<path>");
|
|
12513
|
+
out = out.replace(/\(id=[^)]+\)/gi, "");
|
|
12514
|
+
return out.replace(/\s+/g, " ").trim();
|
|
12515
|
+
}
|
|
12516
|
+
function classifyBridgeLogLine(line) {
|
|
12517
|
+
const timeoutMatch = line.match(/Request "([^"]+)"[\s\S]*?timed out after (\d+)ms/i);
|
|
12518
|
+
if (timeoutMatch) {
|
|
12519
|
+
return `${timeoutMatch[1]}: timed out after ${timeoutMatch[2]}ms`;
|
|
12520
|
+
}
|
|
12521
|
+
const lowerTimeout = line.match(/request "([^"]+)" timed out after (\d+)ms/i);
|
|
12522
|
+
if (lowerTimeout) {
|
|
12523
|
+
return `${lowerTimeout[1]}: timed out after ${lowerTimeout[2]}ms`;
|
|
12524
|
+
}
|
|
12525
|
+
if (/Bridge killed after timeout/i.test(line)) {
|
|
12526
|
+
return "bridge killed after timeout";
|
|
12527
|
+
}
|
|
12528
|
+
if (/bridge killed during sibling timeout/i.test(line)) {
|
|
12529
|
+
return "bridge killed during sibling timeout";
|
|
12530
|
+
}
|
|
12531
|
+
if (/restarting bridge/i.test(line)) {
|
|
12532
|
+
return "restarting bridge";
|
|
12533
|
+
}
|
|
12534
|
+
const rpcMatch = line.match(/RPC error:\s*([^\s=]+)/i);
|
|
12535
|
+
if (rpcMatch) {
|
|
12536
|
+
return `rpc: RPC error (${rpcMatch[1]})`;
|
|
12537
|
+
}
|
|
12538
|
+
if (/spawn error/i.test(line)) {
|
|
12539
|
+
return "spawn: spawn error";
|
|
12540
|
+
}
|
|
12541
|
+
if (/failed to spawn/i.test(line)) {
|
|
12542
|
+
return "spawn: failed to spawn";
|
|
12543
|
+
}
|
|
12544
|
+
if (/\bonnx/i.test(line) && /\b(?:error|failed|missing|incompatible)\b/i.test(line)) {
|
|
12545
|
+
return "onnx: onnx runtime error";
|
|
12546
|
+
}
|
|
12547
|
+
if (/\bORT_/i.test(line) && /\b(?:error|failed)\b/i.test(line)) {
|
|
12548
|
+
return "onnx: ORT error";
|
|
12549
|
+
}
|
|
12550
|
+
const codeMatch = line.match(STRUCTURED_CODE_PATTERN);
|
|
12551
|
+
if (codeMatch && /\bERROR\b/.test(line)) {
|
|
12552
|
+
return `code: ${codeMatch[1]}`;
|
|
12553
|
+
}
|
|
12554
|
+
if (/\bERROR\b/.test(line) && /\[aft-plugin\]|\[aft-bridge\]|\[aft-lsp\]|\[aft\]/i.test(line)) {
|
|
12555
|
+
return "error: ERROR log line";
|
|
12556
|
+
}
|
|
12557
|
+
return null;
|
|
12558
|
+
}
|
|
12559
|
+
function aggregateBridgeToolFailures(logText) {
|
|
12560
|
+
const counts = new Map;
|
|
12561
|
+
if (!logText.trim())
|
|
12562
|
+
return counts;
|
|
12563
|
+
for (const rawLine of logText.split(/\r?\n/)) {
|
|
12564
|
+
if (!stripSessionTags(rawLine))
|
|
12565
|
+
continue;
|
|
12566
|
+
const key = classifyBridgeLogLine(rawLine);
|
|
12567
|
+
if (!key)
|
|
12568
|
+
continue;
|
|
12569
|
+
const sanitizedKey = stripPathLikeTokens(sanitizeContent(key));
|
|
12570
|
+
if (!sanitizedKey)
|
|
12571
|
+
continue;
|
|
12572
|
+
counts.set(sanitizedKey, (counts.get(sanitizedKey) ?? 0) + 1);
|
|
12573
|
+
}
|
|
12574
|
+
return counts;
|
|
12575
|
+
}
|
|
12576
|
+
function sortFailureKeys(a, b, counts) {
|
|
12577
|
+
const countDiff = (counts.get(b) ?? 0) - (counts.get(a) ?? 0);
|
|
12578
|
+
if (countDiff !== 0)
|
|
12579
|
+
return countDiff;
|
|
12580
|
+
return a.localeCompare(b);
|
|
12581
|
+
}
|
|
12582
|
+
function formatRecentAftToolFailuresSection(counts, options) {
|
|
12583
|
+
const maxClasses = options?.maxClasses ?? MAX_TOOL_FAILURE_CLASSES;
|
|
12584
|
+
const heading = "### Recent AFT tool failures";
|
|
12585
|
+
if (counts.size === 0) {
|
|
12586
|
+
return `${heading}
|
|
12587
|
+
No recent AFT tool failures recorded.`;
|
|
12588
|
+
}
|
|
12589
|
+
const sorted = [...counts.keys()].sort((a, b) => sortFailureKeys(a, b, counts));
|
|
12590
|
+
const shown = sorted.slice(0, maxClasses);
|
|
12591
|
+
const hidden = sorted.length - shown.length;
|
|
12592
|
+
const bullets = shown.map((key) => {
|
|
12593
|
+
const count = counts.get(key) ?? 0;
|
|
12594
|
+
return `- ${key} ×${count}`;
|
|
12595
|
+
});
|
|
12596
|
+
if (hidden > 0) {
|
|
12597
|
+
bullets.push(`- +${hidden} more failure class(es) omitted`);
|
|
12598
|
+
}
|
|
12599
|
+
return [heading, ...bullets].join(`
|
|
12600
|
+
`);
|
|
12601
|
+
}
|
|
12602
|
+
function buildRecentAftToolFailuresSectionFromLog(logPath = resolveBridgePluginLogPath(), options) {
|
|
12603
|
+
const tailBytes = options?.tailBytes ?? BRIDGE_LOG_TAIL_BYTES;
|
|
12604
|
+
const tail = tailLogFileBytes(logPath, tailBytes);
|
|
12605
|
+
const counts = aggregateBridgeToolFailures(tail);
|
|
12606
|
+
return formatRecentAftToolFailuresSection(counts, options);
|
|
12607
|
+
}
|
|
12608
|
+
var BRIDGE_LOG_TAIL_BYTES, MAX_TOOL_FAILURE_CLASSES = 30, SESSION_TAG_PATTERN, STRUCTURED_CODE_PATTERN;
|
|
12609
|
+
var init_bridge_tool_failures = __esm(() => {
|
|
12610
|
+
init_sanitize();
|
|
12611
|
+
BRIDGE_LOG_TAIL_BYTES = 2 * 1024 * 1024;
|
|
12612
|
+
SESSION_TAG_PATTERN = /\[ses_[^\]\s]+\]|\[[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\]/g;
|
|
12613
|
+
STRUCTURED_CODE_PATTERN = /"code"\s*:\s*"([^"]+)"/;
|
|
12614
|
+
});
|
|
12615
|
+
|
|
12616
|
+
// src/lib/lsp-cache.ts
|
|
12617
|
+
import { existsSync as existsSync11, readdirSync as readdirSync5, rmSync as rmSync2, statSync as statSync7 } from "node:fs";
|
|
12618
|
+
import { join as join11 } from "node:path";
|
|
12381
12619
|
function inspectDir(path) {
|
|
12382
|
-
if (!
|
|
12620
|
+
if (!existsSync11(path)) {
|
|
12383
12621
|
return { entries: [], totalSize: 0 };
|
|
12384
12622
|
}
|
|
12385
12623
|
const entries = [];
|
|
@@ -12391,9 +12629,9 @@ function inspectDir(path) {
|
|
|
12391
12629
|
return { entries: [], totalSize: 0 };
|
|
12392
12630
|
}
|
|
12393
12631
|
for (const name of names) {
|
|
12394
|
-
const full =
|
|
12632
|
+
const full = join11(path, name);
|
|
12395
12633
|
try {
|
|
12396
|
-
if (!
|
|
12634
|
+
if (!statSync7(full).isDirectory())
|
|
12397
12635
|
continue;
|
|
12398
12636
|
const size = dirSize(full);
|
|
12399
12637
|
entries.push({
|
|
@@ -12449,8 +12687,8 @@ var init_lsp_cache = __esm(() => {
|
|
|
12449
12687
|
});
|
|
12450
12688
|
|
|
12451
12689
|
// src/lib/onnx.ts
|
|
12452
|
-
import { existsSync as
|
|
12453
|
-
import { basename, isAbsolute as isAbsolute2, join as
|
|
12690
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6, readlinkSync, realpathSync as realpathSync3, statSync as statSync8 } from "node:fs";
|
|
12691
|
+
import { basename, isAbsolute as isAbsolute2, join as join12, resolve as resolve4, win32 } from "node:path";
|
|
12454
12692
|
function getOnnxLibraryName() {
|
|
12455
12693
|
if (process.platform === "darwin")
|
|
12456
12694
|
return "libonnxruntime.dylib";
|
|
@@ -12513,13 +12751,13 @@ function findSystemOnnxRuntime() {
|
|
|
12513
12751
|
searchPaths.push(...pathEntriesForPlatform());
|
|
12514
12752
|
const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
|
|
12515
12753
|
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
|
|
12516
|
-
searchPaths.push(
|
|
12754
|
+
searchPaths.push(join12(programFiles, "onnxruntime", "lib"), join12(programFiles, "Microsoft ONNX Runtime", "lib"), join12(programFiles, "Microsoft Machine Learning", "lib"), join12(programFilesX86, "onnxruntime", "lib"), ...(() => {
|
|
12517
12755
|
const nugetPaths = [];
|
|
12518
12756
|
const userProfile = process.env.USERPROFILE ?? "";
|
|
12519
12757
|
if (!userProfile)
|
|
12520
12758
|
return nugetPaths;
|
|
12521
|
-
const nugetPackageDir =
|
|
12522
|
-
if (!
|
|
12759
|
+
const nugetPackageDir = join12(userProfile, ".nuget", "packages", "microsoft.ml.onnxruntime");
|
|
12760
|
+
if (!existsSync12(nugetPackageDir))
|
|
12523
12761
|
return nugetPaths;
|
|
12524
12762
|
try {
|
|
12525
12763
|
for (const entry of readdirSync6(nugetPackageDir, { withFileTypes: true })) {
|
|
@@ -12527,7 +12765,7 @@ function findSystemOnnxRuntime() {
|
|
|
12527
12765
|
continue;
|
|
12528
12766
|
if (entry.name === "__globalPackagesFolder" || entry.name.startsWith("."))
|
|
12529
12767
|
continue;
|
|
12530
|
-
nugetPaths.push(
|
|
12768
|
+
nugetPaths.push(join12(nugetPackageDir, entry.name, "runtimes", "win-x64", "native"), join12(nugetPackageDir, entry.name, "runtimes", "win-arm64", "native"));
|
|
12531
12769
|
}
|
|
12532
12770
|
} catch {}
|
|
12533
12771
|
return nugetPaths;
|
|
@@ -12557,12 +12795,12 @@ function findSystemOnnxRuntime() {
|
|
|
12557
12795
|
return unknownVersionPaths[0] ?? null;
|
|
12558
12796
|
}
|
|
12559
12797
|
function findCachedOnnxRuntime(storageDir) {
|
|
12560
|
-
const ortDir =
|
|
12798
|
+
const ortDir = join12(storageDir, "onnxruntime", ONNX_RUNTIME_VERSION);
|
|
12561
12799
|
const libName = getOnnxLibraryName();
|
|
12562
|
-
if (
|
|
12800
|
+
if (existsSync12(join12(ortDir, libName)))
|
|
12563
12801
|
return ortDir;
|
|
12564
|
-
const libSubdir =
|
|
12565
|
-
if (
|
|
12802
|
+
const libSubdir = join12(ortDir, "lib");
|
|
12803
|
+
if (existsSync12(join12(libSubdir, libName)))
|
|
12566
12804
|
return libSubdir;
|
|
12567
12805
|
return null;
|
|
12568
12806
|
}
|
|
@@ -12583,7 +12821,7 @@ function parseOrtVersionFromDirectoryPath(value) {
|
|
|
12583
12821
|
return null;
|
|
12584
12822
|
}
|
|
12585
12823
|
function detectOrtVersion(libDir) {
|
|
12586
|
-
if (!
|
|
12824
|
+
if (!existsSync12(libDir))
|
|
12587
12825
|
return null;
|
|
12588
12826
|
const libName = getOnnxLibraryName();
|
|
12589
12827
|
try {
|
|
@@ -12598,10 +12836,10 @@ function detectOrtVersion(libDir) {
|
|
|
12598
12836
|
if (version)
|
|
12599
12837
|
return version;
|
|
12600
12838
|
}
|
|
12601
|
-
const base =
|
|
12602
|
-
if (
|
|
12839
|
+
const base = join12(libDir, libName);
|
|
12840
|
+
if (existsSync12(base)) {
|
|
12603
12841
|
try {
|
|
12604
|
-
const real =
|
|
12842
|
+
const real = realpathSync3(base);
|
|
12605
12843
|
const version = parseOrtVersionFromPath(real) ?? parseOrtVersionFromDirectoryPath(real);
|
|
12606
12844
|
if (version)
|
|
12607
12845
|
return version;
|
|
@@ -12629,93 +12867,15 @@ function isOrtVersionCompatible(version) {
|
|
|
12629
12867
|
var ONNX_RUNTIME_VERSION = "1.24.4", INVALID_ORT_VERSION = "<invalid>", REQUIRED_ORT_MAJOR = 1, REQUIRED_ORT_MIN_MINOR = 20;
|
|
12630
12868
|
var init_onnx = () => {};
|
|
12631
12869
|
|
|
12632
|
-
// src/lib/sanitize.ts
|
|
12633
|
-
import { realpathSync as realpathSync3 } from "node:fs";
|
|
12634
|
-
import { homedir as homedir8, userInfo } from "node:os";
|
|
12635
|
-
function escapeRegex(value) {
|
|
12636
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12637
|
-
}
|
|
12638
|
-
function safeRealpath(p2) {
|
|
12639
|
-
try {
|
|
12640
|
-
return realpathSync3(p2);
|
|
12641
|
-
} catch {
|
|
12642
|
-
return null;
|
|
12643
|
-
}
|
|
12644
|
-
}
|
|
12645
|
-
function isSensitiveKeyName(keyName) {
|
|
12646
|
-
return SENSITIVE_KEY_WORD.test(keyName) || SEGMENTED_KEY_WORD.test(keyName) || CAMEL_CASE_KEY_WORD.test(keyName);
|
|
12647
|
-
}
|
|
12648
|
-
function redactSecrets(content) {
|
|
12649
|
-
let sanitized = content;
|
|
12650
|
-
sanitized = sanitized.replace(/\b((?:Proxy-)?Authorization[^\S\r\n]*:[^\S\r\n]*(?:Bearer|Basic)[^\S\r\n]+)[A-Za-z0-9._~+/-]+=*/gi, `$1${SECRET_PLACEHOLDER}`);
|
|
12651
|
-
sanitized = sanitized.replace(/\bgithub_pat_[A-Za-z0-9_]+\b/g, SECRET_PLACEHOLDER);
|
|
12652
|
-
sanitized = sanitized.replace(/\bgh(?:p|o|s)_[A-Za-z0-9_]{16,}\b/g, SECRET_PLACEHOLDER);
|
|
12653
|
-
sanitized = sanitized.replace(/\bsk-(?:live-)?[A-Za-z0-9][A-Za-z0-9_-]{7,}\b/g, SECRET_PLACEHOLDER);
|
|
12654
|
-
sanitized = sanitized.replace(JWT_PATTERN, SECRET_PLACEHOLDER);
|
|
12655
|
-
sanitized = sanitized.replace(AWS_ACCESS_KEY_ID_PATTERN, SECRET_PLACEHOLDER);
|
|
12656
|
-
sanitized = sanitized.replace(quotedSensitiveKeyValuePattern, (match, prefix, _keyQuote, keyName, valueQuote) => isSensitiveKeyName(keyName) ? `${prefix}${valueQuote}${SECRET_PLACEHOLDER}${valueQuote}` : match);
|
|
12657
|
-
sanitized = sanitized.replace(unquotedSensitiveKeyValuePattern, (match, prefix, keyName, valueQuote) => isSensitiveKeyName(keyName) ? `${prefix}${valueQuote}${SECRET_PLACEHOLDER}${valueQuote}` : match);
|
|
12658
|
-
sanitized = sanitized.replace(bareSensitiveKeyValuePattern, (match, prefix, keyName) => isSensitiveKeyName(keyName) ? `${prefix}${SECRET_PLACEHOLDER}` : match);
|
|
12659
|
-
sanitized = sanitized.replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^@\s/?#]+@/gi, `$1${URL_CREDENTIAL_PLACEHOLDER}@`);
|
|
12660
|
-
sanitized = sanitized.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "<EMAIL>");
|
|
12661
|
-
return sanitized;
|
|
12662
|
-
}
|
|
12663
|
-
function sanitizeContent(content) {
|
|
12664
|
-
const username = userInfo().username;
|
|
12665
|
-
const home = homedir8();
|
|
12666
|
-
let sanitized = redactSecrets(content);
|
|
12667
|
-
const cwd = process.cwd();
|
|
12668
|
-
for (const candidate of new Set([cwd, safeRealpath(cwd)])) {
|
|
12669
|
-
if (candidate && candidate !== "/" && candidate !== home) {
|
|
12670
|
-
sanitized = sanitized.replace(new RegExp(escapeRegex(candidate), "g"), "<PROJECT>");
|
|
12671
|
-
}
|
|
12672
|
-
}
|
|
12673
|
-
if (home) {
|
|
12674
|
-
sanitized = sanitized.replace(new RegExp(escapeRegex(home), "g"), "~");
|
|
12675
|
-
}
|
|
12676
|
-
sanitized = sanitized.replace(/\/Users\/[^/\s"']+/g, "/Users/<USER>");
|
|
12677
|
-
sanitized = sanitized.replace(/\/home\/[^/\s"']+/g, "/home/<USER>");
|
|
12678
|
-
sanitized = sanitized.replace(/([A-Za-z]:\\\\Users\\\\)[^\\\\"'\s]+/g, "$1<USER>");
|
|
12679
|
-
sanitized = sanitized.replace(/([A-Za-z]:\\Users\\)[^\\"'\s]+/g, "$1<USER>");
|
|
12680
|
-
sanitized = sanitized.replace(/([A-Za-z]:\/Users\/)[^/\s"']+/g, "$1<USER>");
|
|
12681
|
-
if (username) {
|
|
12682
|
-
sanitized = sanitized.replace(new RegExp(escapeRegex(username), "g"), "<USER>");
|
|
12683
|
-
}
|
|
12684
|
-
return sanitized;
|
|
12685
|
-
}
|
|
12686
|
-
function sanitizeValue(value) {
|
|
12687
|
-
if (typeof value === "string") {
|
|
12688
|
-
return sanitizeContent(value);
|
|
12689
|
-
}
|
|
12690
|
-
if (Array.isArray(value)) {
|
|
12691
|
-
return value.map((entry) => sanitizeValue(entry));
|
|
12692
|
-
}
|
|
12693
|
-
if (value && typeof value === "object") {
|
|
12694
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, sanitizeValue(entry)]));
|
|
12695
|
-
}
|
|
12696
|
-
return value;
|
|
12697
|
-
}
|
|
12698
|
-
var SECRET_PLACEHOLDER = "<REDACTED_SECRET>", URL_CREDENTIAL_PLACEHOLDER = "***", KEY_NAME = "[A-Za-z_][A-Za-z0-9_.-]*", SENSITIVE_KEY_WORD, SEGMENTED_KEY_WORD, CAMEL_CASE_KEY_WORD, JWT_PATTERN, AWS_ACCESS_KEY_ID_PATTERN, quotedSensitiveKeyValuePattern, unquotedSensitiveKeyValuePattern, bareSensitiveKeyValuePattern;
|
|
12699
|
-
var init_sanitize = __esm(() => {
|
|
12700
|
-
SENSITIVE_KEY_WORD = /(?:token|password|secret|api[_-]?key|passwd|pwd|credential)/i;
|
|
12701
|
-
SEGMENTED_KEY_WORD = /(?:^|[_.-])key(?:$|[_.-])/i;
|
|
12702
|
-
CAMEL_CASE_KEY_WORD = /[a-z0-9]Key(?:$|[A-Z_.-])/;
|
|
12703
|
-
JWT_PATTERN = /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g;
|
|
12704
|
-
AWS_ACCESS_KEY_ID_PATTERN = /\b(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}\b/g;
|
|
12705
|
-
quotedSensitiveKeyValuePattern = new RegExp(String.raw`((['"])(${KEY_NAME})\2[^\S\r\n]*:[^\S\r\n]*)(['"])([^'"\r\n]+)\4`, "gi");
|
|
12706
|
-
unquotedSensitiveKeyValuePattern = new RegExp(String.raw`\b((${KEY_NAME})[^\S\r\n]*[=:][^\S\r\n]*)(['"])([^'"\r\n]+)\3`, "gi");
|
|
12707
|
-
bareSensitiveKeyValuePattern = new RegExp(String.raw`\b((${KEY_NAME})[^\S\r\n]*[=:][^\S\r\n]*)([^\s,;&'"]+)`, "gi");
|
|
12708
|
-
});
|
|
12709
|
-
|
|
12710
12870
|
// src/lib/diagnostics.ts
|
|
12711
12871
|
import {
|
|
12712
12872
|
accessSync,
|
|
12713
|
-
closeSync as
|
|
12873
|
+
closeSync as closeSync3,
|
|
12714
12874
|
constants,
|
|
12715
|
-
existsSync as
|
|
12716
|
-
openSync as
|
|
12717
|
-
readSync as
|
|
12718
|
-
statSync as
|
|
12875
|
+
existsSync as existsSync13,
|
|
12876
|
+
openSync as openSync3,
|
|
12877
|
+
readSync as readSync3,
|
|
12878
|
+
statSync as statSync9
|
|
12719
12879
|
} from "node:fs";
|
|
12720
12880
|
async function collectDiagnostics(adapters) {
|
|
12721
12881
|
const cliVersion = getSelfVersion();
|
|
@@ -12744,7 +12904,7 @@ async function diagnoseHarness(adapter) {
|
|
|
12744
12904
|
const logPath = adapter.getLogFile();
|
|
12745
12905
|
const pluginCache = adapter.getPluginCacheInfo();
|
|
12746
12906
|
const storageAccessible = (() => {
|
|
12747
|
-
if (!
|
|
12907
|
+
if (!existsSync13(storage))
|
|
12748
12908
|
return false;
|
|
12749
12909
|
try {
|
|
12750
12910
|
accessSync(storage, constants.R_OK | constants.W_OK);
|
|
@@ -12767,14 +12927,14 @@ async function diagnoseHarness(adapter) {
|
|
|
12767
12927
|
pluginRegistered: adapter.hasPluginEntry(),
|
|
12768
12928
|
configPaths,
|
|
12769
12929
|
aftConfig: {
|
|
12770
|
-
exists:
|
|
12930
|
+
exists: existsSync13(configPaths.aftConfig),
|
|
12771
12931
|
...aftConfigRead.error ? { parseError: aftConfigRead.error } : {},
|
|
12772
12932
|
flags: aftFlags
|
|
12773
12933
|
},
|
|
12774
12934
|
pluginCache,
|
|
12775
12935
|
storageDir: {
|
|
12776
12936
|
path: storage,
|
|
12777
|
-
exists:
|
|
12937
|
+
exists: existsSync13(storage),
|
|
12778
12938
|
accessible: storageAccessible,
|
|
12779
12939
|
sizesByKey: describeStorage
|
|
12780
12940
|
},
|
|
@@ -12792,8 +12952,8 @@ async function diagnoseHarness(adapter) {
|
|
|
12792
12952
|
},
|
|
12793
12953
|
logFile: {
|
|
12794
12954
|
path: logPath,
|
|
12795
|
-
exists:
|
|
12796
|
-
sizeKb:
|
|
12955
|
+
exists: existsSync13(logPath),
|
|
12956
|
+
sizeKb: existsSync13(logPath) ? Math.round(statSync9(logPath).size / 1024) : 0
|
|
12797
12957
|
}
|
|
12798
12958
|
};
|
|
12799
12959
|
}
|
|
@@ -12987,15 +13147,15 @@ function formatDiagnosticIssuesSection(report) {
|
|
|
12987
13147
|
return lines;
|
|
12988
13148
|
}
|
|
12989
13149
|
function tailLogFile(path, lines) {
|
|
12990
|
-
if (!
|
|
13150
|
+
if (!existsSync13(path))
|
|
12991
13151
|
return "";
|
|
12992
13152
|
if (lines <= 0)
|
|
12993
13153
|
return "";
|
|
12994
13154
|
const chunkSize = 64 * 1024;
|
|
12995
13155
|
let fd = null;
|
|
12996
13156
|
try {
|
|
12997
|
-
const size =
|
|
12998
|
-
fd =
|
|
13157
|
+
const size = statSync9(path).size;
|
|
13158
|
+
fd = openSync3(path, "r");
|
|
12999
13159
|
const chunks = [];
|
|
13000
13160
|
let position = size;
|
|
13001
13161
|
let newlineCount = 0;
|
|
@@ -13003,7 +13163,7 @@ function tailLogFile(path, lines) {
|
|
|
13003
13163
|
const readLength = Math.min(chunkSize, position);
|
|
13004
13164
|
position -= readLength;
|
|
13005
13165
|
const buffer = Buffer.allocUnsafe(readLength);
|
|
13006
|
-
const bytesRead =
|
|
13166
|
+
const bytesRead = readSync3(fd, buffer, 0, readLength, position);
|
|
13007
13167
|
const chunk = bytesRead === readLength ? buffer : buffer.subarray(0, bytesRead);
|
|
13008
13168
|
chunks.unshift(chunk);
|
|
13009
13169
|
for (let i = chunk.length - 1;i >= 0; i -= 1) {
|
|
@@ -13018,7 +13178,7 @@ function tailLogFile(path, lines) {
|
|
|
13018
13178
|
} finally {
|
|
13019
13179
|
if (fd !== null) {
|
|
13020
13180
|
try {
|
|
13021
|
-
|
|
13181
|
+
closeSync3(fd);
|
|
13022
13182
|
} catch {}
|
|
13023
13183
|
}
|
|
13024
13184
|
}
|
|
@@ -13077,7 +13237,7 @@ var init_github = () => {};
|
|
|
13077
13237
|
function filterLogToSession(logText, sessionId) {
|
|
13078
13238
|
const bareId = sessionId.replace(/^ses_/, "");
|
|
13079
13239
|
const keepTokens = [`[ses_${bareId}]`, `[${bareId}]`];
|
|
13080
|
-
return logText.split(/\r?\n/).filter((line) => !
|
|
13240
|
+
return logText.split(/\r?\n/).filter((line) => !SESSION_TAG_PATTERN2.test(line) || keepTokens.some((token) => line.includes(token))).join(`
|
|
13081
13241
|
`);
|
|
13082
13242
|
}
|
|
13083
13243
|
function isErrorLogLine(line) {
|
|
@@ -13157,9 +13317,9 @@ function truncateToByteBudget(input, maxBytes) {
|
|
|
13157
13317
|
}
|
|
13158
13318
|
return buf.subarray(0, end).toString("utf8");
|
|
13159
13319
|
}
|
|
13160
|
-
var MAX_GITHUB_BODY_BYTES = 60000,
|
|
13320
|
+
var MAX_GITHUB_BODY_BYTES = 60000, SESSION_TAG_PATTERN2, ERROR_LOG_PATTERNS;
|
|
13161
13321
|
var init_issue_body = __esm(() => {
|
|
13162
|
-
|
|
13322
|
+
SESSION_TAG_PATTERN2 = /\[ses_[^\]\s]+\]|\[[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\]/;
|
|
13163
13323
|
ERROR_LOG_PATTERNS = [
|
|
13164
13324
|
/\bcrashed:/i,
|
|
13165
13325
|
/\bfailed:/i,
|
|
@@ -13173,8 +13333,8 @@ var init_issue_body = __esm(() => {
|
|
|
13173
13333
|
});
|
|
13174
13334
|
|
|
13175
13335
|
// src/lib/onnx-fix.ts
|
|
13176
|
-
import { existsSync as
|
|
13177
|
-
import { join as
|
|
13336
|
+
import { existsSync as existsSync14, rmSync as rmSync3 } from "node:fs";
|
|
13337
|
+
import { join as join13 } from "node:path";
|
|
13178
13338
|
function findOnnxFixCandidates(report) {
|
|
13179
13339
|
const candidates = [];
|
|
13180
13340
|
for (const harness of report.harnesses) {
|
|
@@ -13182,7 +13342,7 @@ function findOnnxFixCandidates(report) {
|
|
|
13182
13342
|
continue;
|
|
13183
13343
|
if (!harness.storageDir.exists)
|
|
13184
13344
|
continue;
|
|
13185
|
-
const storageOnnxDir =
|
|
13345
|
+
const storageOnnxDir = join13(harness.storageDir.path, "onnxruntime");
|
|
13186
13346
|
const systemTooOld = harness.onnxRuntime.systemPath !== null && harness.onnxRuntime.systemCompatible === false;
|
|
13187
13347
|
const cachedTooOld = harness.onnxRuntime.cachedPath !== null && harness.onnxRuntime.cachedCompatible === false;
|
|
13188
13348
|
const hasCompatibleCached = harness.onnxRuntime.cachedCompatible === true;
|
|
@@ -13191,7 +13351,7 @@ function findOnnxFixCandidates(report) {
|
|
|
13191
13351
|
harness,
|
|
13192
13352
|
reason: `cached ONNX Runtime at ${harness.onnxRuntime.cachedPath} is v${harness.onnxRuntime.cachedVersion}, but AFT requires ${harness.onnxRuntime.requirement}. Clearing forces a fresh download on next start.`,
|
|
13193
13353
|
storageOnnxDir,
|
|
13194
|
-
storageOnnxBytes:
|
|
13354
|
+
storageOnnxBytes: existsSync14(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
|
|
13195
13355
|
});
|
|
13196
13356
|
continue;
|
|
13197
13357
|
}
|
|
@@ -13200,7 +13360,7 @@ function findOnnxFixCandidates(report) {
|
|
|
13200
13360
|
harness,
|
|
13201
13361
|
reason: `system ONNX Runtime at ${harness.onnxRuntime.systemPath} is v${harness.onnxRuntime.systemVersion}, but AFT requires ${harness.onnxRuntime.requirement}, and no AFT-managed install is present. AFT v0.19.5+ skips incompatible system installs and auto-downloads v1.24 on next start; clearing any stale state here ensures a clean slate.`,
|
|
13202
13362
|
storageOnnxDir,
|
|
13203
|
-
storageOnnxBytes:
|
|
13363
|
+
storageOnnxBytes: existsSync14(storageOnnxDir) ? dirSize(storageOnnxDir) : 0
|
|
13204
13364
|
});
|
|
13205
13365
|
}
|
|
13206
13366
|
}
|
|
@@ -13230,7 +13390,7 @@ async function runOnnxFix(adapters, report, options = {}) {
|
|
|
13230
13390
|
const result = { cleared: 0, bytesReclaimed: 0, errors: [] };
|
|
13231
13391
|
const rmFn = options.rmFn ?? rmSync3;
|
|
13232
13392
|
for (const c2 of candidates) {
|
|
13233
|
-
if (!
|
|
13393
|
+
if (!existsSync14(c2.storageOnnxDir)) {
|
|
13234
13394
|
O2.success(`${c2.harness.displayName}: no cached state to clear; restart your harness to trigger a fresh ONNX download`);
|
|
13235
13395
|
continue;
|
|
13236
13396
|
}
|
|
@@ -13256,10 +13416,10 @@ var init_onnx_fix = __esm(() => {
|
|
|
13256
13416
|
});
|
|
13257
13417
|
|
|
13258
13418
|
// src/lib/sessions.ts
|
|
13259
|
-
import { existsSync as
|
|
13419
|
+
import { existsSync as existsSync15, readdirSync as readdirSync7, readFileSync as readFileSync4, statSync as statSync10 } from "node:fs";
|
|
13260
13420
|
import { createRequire as createRequire3 } from "node:module";
|
|
13261
13421
|
import { homedir as homedir9 } from "node:os";
|
|
13262
|
-
import { basename as basename2, join as
|
|
13422
|
+
import { basename as basename2, join as join14 } from "node:path";
|
|
13263
13423
|
function listRecentSessions(adapter) {
|
|
13264
13424
|
try {
|
|
13265
13425
|
if (adapter.kind === "opencode")
|
|
@@ -13288,8 +13448,8 @@ function mapOpenCodeSessionRows(rows) {
|
|
|
13288
13448
|
}).filter((session) => session !== null).sort((a, b) => b.lastActivity - a.lastActivity).slice(0, MAX_RECENT_SESSIONS);
|
|
13289
13449
|
}
|
|
13290
13450
|
function listRecentOpenCodeSessions() {
|
|
13291
|
-
const dbPath =
|
|
13292
|
-
if (!
|
|
13451
|
+
const dbPath = join14(getXdgDataHome(), "opencode", "opencode.db");
|
|
13452
|
+
if (!existsSync15(dbPath))
|
|
13293
13453
|
return [];
|
|
13294
13454
|
let db = null;
|
|
13295
13455
|
try {
|
|
@@ -13308,10 +13468,10 @@ function listRecentOpenCodeSessions() {
|
|
|
13308
13468
|
}
|
|
13309
13469
|
function getXdgDataHome() {
|
|
13310
13470
|
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
13311
|
-
return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome :
|
|
13471
|
+
return xdgDataHome && xdgDataHome.length > 0 ? xdgDataHome : join14(homedir9(), ".local", "share");
|
|
13312
13472
|
}
|
|
13313
13473
|
function listRecentPiSessions() {
|
|
13314
|
-
return listPiSessionsFromDir(
|
|
13474
|
+
return listPiSessionsFromDir(join14(getHomeDir(), ".pi", "agent", "sessions"));
|
|
13315
13475
|
}
|
|
13316
13476
|
function getHomeDir() {
|
|
13317
13477
|
const envHome = process.platform === "win32" ? process.env.USERPROFILE : process.env.HOME;
|
|
@@ -13319,11 +13479,11 @@ function getHomeDir() {
|
|
|
13319
13479
|
}
|
|
13320
13480
|
function listPiSessionsFromDir(sessionsDir) {
|
|
13321
13481
|
try {
|
|
13322
|
-
if (!
|
|
13482
|
+
if (!existsSync15(sessionsDir))
|
|
13323
13483
|
return [];
|
|
13324
13484
|
const files = collectJsonlFiles(sessionsDir).map((filePath) => {
|
|
13325
13485
|
try {
|
|
13326
|
-
const stats =
|
|
13486
|
+
const stats = statSync10(filePath);
|
|
13327
13487
|
return { filePath, mtimeMs: stats.mtimeMs };
|
|
13328
13488
|
} catch {
|
|
13329
13489
|
return null;
|
|
@@ -13357,7 +13517,7 @@ function collectJsonlFiles(root) {
|
|
|
13357
13517
|
continue;
|
|
13358
13518
|
}
|
|
13359
13519
|
for (const entry of entries) {
|
|
13360
|
-
const path =
|
|
13520
|
+
const path = join14(dir, entry.name);
|
|
13361
13521
|
if (entry.isDirectory()) {
|
|
13362
13522
|
stack.push(path);
|
|
13363
13523
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
@@ -13457,17 +13617,17 @@ __export(exports_doctor, {
|
|
|
13457
13617
|
import { execFileSync } from "node:child_process";
|
|
13458
13618
|
import {
|
|
13459
13619
|
chmodSync as chmodSync2,
|
|
13460
|
-
existsSync as
|
|
13620
|
+
existsSync as existsSync16,
|
|
13461
13621
|
mkdirSync as mkdirSync3,
|
|
13462
13622
|
mkdtempSync,
|
|
13463
13623
|
readFileSync as readFileSync5,
|
|
13464
13624
|
realpathSync as realpathSync4,
|
|
13465
13625
|
rmSync as rmSync4,
|
|
13466
|
-
statSync as
|
|
13626
|
+
statSync as statSync11,
|
|
13467
13627
|
writeFileSync as writeFileSync2
|
|
13468
13628
|
} from "node:fs";
|
|
13469
|
-
import { tmpdir as
|
|
13470
|
-
import { join as
|
|
13629
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
13630
|
+
import { join as join15 } from "node:path";
|
|
13471
13631
|
async function runDoctor(options) {
|
|
13472
13632
|
if (options.issue) {
|
|
13473
13633
|
return runIssueFlow(options.argv);
|
|
@@ -13621,7 +13781,7 @@ function clearOldBinaries() {
|
|
|
13621
13781
|
errors: [],
|
|
13622
13782
|
keptVersion: keepTag
|
|
13623
13783
|
};
|
|
13624
|
-
if (!
|
|
13784
|
+
if (!existsSync16(info.path)) {
|
|
13625
13785
|
O2.info(`Binary cache: nothing to clear at ${info.path}`);
|
|
13626
13786
|
return result;
|
|
13627
13787
|
}
|
|
@@ -13631,10 +13791,10 @@ function clearOldBinaries() {
|
|
|
13631
13791
|
return result;
|
|
13632
13792
|
}
|
|
13633
13793
|
for (const version of stale) {
|
|
13634
|
-
const dir =
|
|
13794
|
+
const dir = join15(info.path, version);
|
|
13635
13795
|
let bytes = 0;
|
|
13636
13796
|
try {
|
|
13637
|
-
bytes =
|
|
13797
|
+
bytes = statSync11(dir).isDirectory() ? dirSize(dir) : 0;
|
|
13638
13798
|
} catch {
|
|
13639
13799
|
bytes = 0;
|
|
13640
13800
|
}
|
|
@@ -13956,7 +14116,7 @@ function ensureStorageDirsForRegisteredPlugins(adapters) {
|
|
|
13956
14116
|
if (!adapter.isInstalled() || !adapter.hasPluginEntry())
|
|
13957
14117
|
continue;
|
|
13958
14118
|
const storageDir = adapter.getStorageDir();
|
|
13959
|
-
if (
|
|
14119
|
+
if (existsSync16(storageDir))
|
|
13960
14120
|
continue;
|
|
13961
14121
|
mkdirSync3(storageDir, { recursive: true });
|
|
13962
14122
|
summary.created += 1;
|
|
@@ -14059,11 +14219,11 @@ function deriveIssueTitleFromBody(body) {
|
|
|
14059
14219
|
function writeIssueReviewFile(body) {
|
|
14060
14220
|
let reviewDir = null;
|
|
14061
14221
|
try {
|
|
14062
|
-
reviewDir = mkdtempSync(
|
|
14222
|
+
reviewDir = mkdtempSync(join15(tmpdir3(), "aft-issue-"));
|
|
14063
14223
|
if (process.platform !== "win32") {
|
|
14064
14224
|
chmodSync2(reviewDir, 448);
|
|
14065
14225
|
}
|
|
14066
|
-
const outPath =
|
|
14226
|
+
const outPath = join15(reviewDir, "issue.md");
|
|
14067
14227
|
writeFileSync2(outPath, `${body}
|
|
14068
14228
|
`, { encoding: "utf8", mode: 384, flag: "wx" });
|
|
14069
14229
|
return { path: outPath, realPath: realpathSync4(outPath) };
|
|
@@ -14152,6 +14312,7 @@ ${scopedTail || "<no log output>"}
|
|
|
14152
14312
|
const recentErrorsSection = recentErrorLines.length === 0 ? "_No error-shaped log lines found in recent history._" : ["```", recentErrorLines.join(`
|
|
14153
14313
|
`), "```"].join(`
|
|
14154
14314
|
`);
|
|
14315
|
+
const toolFailuresSection = buildRecentAftToolFailuresSectionFromLog();
|
|
14155
14316
|
const rawBody = [
|
|
14156
14317
|
"## Description",
|
|
14157
14318
|
description,
|
|
@@ -14169,6 +14330,8 @@ ${scopedTail || "<no log output>"}
|
|
|
14169
14330
|
"## Recent errors (last 20, sanitized)",
|
|
14170
14331
|
recentErrorsSection,
|
|
14171
14332
|
"",
|
|
14333
|
+
toolFailuresSection,
|
|
14334
|
+
"",
|
|
14172
14335
|
"## Logs (last 200 lines per harness)",
|
|
14173
14336
|
logSections,
|
|
14174
14337
|
"_Usernames and home paths have been stripped from this report._"
|
|
@@ -14223,6 +14386,7 @@ var DOCTOR_CLEAR_TARGET_OPTIONS, DOCTOR_FORCE_CLEAR_TARGETS;
|
|
|
14223
14386
|
var init_doctor = __esm(async () => {
|
|
14224
14387
|
init_dist();
|
|
14225
14388
|
init_binary_cache();
|
|
14389
|
+
init_bridge_tool_failures();
|
|
14226
14390
|
init_fs_util();
|
|
14227
14391
|
init_github();
|
|
14228
14392
|
init_harness_select();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Newest window: tail of the bridge log by bytes (not full file). */
|
|
2
|
+
export declare const BRIDGE_LOG_TAIL_BYTES: number;
|
|
3
|
+
export declare const MAX_TOOL_FAILURE_CLASSES = 30;
|
|
4
|
+
export declare function resolveBridgePluginLogPath(): string;
|
|
5
|
+
/** Read up to `maxBytes` from the end of a log file (UTF-8). */
|
|
6
|
+
export declare function tailLogFileBytes(path: string, maxBytes: number): string;
|
|
7
|
+
export type ToolFailureKey = string;
|
|
8
|
+
/**
|
|
9
|
+
* Aggregate failure-shaped lines from bridge plugin log text into counts.
|
|
10
|
+
* Input should be a recent tail only; keys are tool/command + error class.
|
|
11
|
+
*/
|
|
12
|
+
export declare function aggregateBridgeToolFailures(logText: string): Map<ToolFailureKey, number>;
|
|
13
|
+
/**
|
|
14
|
+
* Render the `### Recent AFT tool failures` markdown section from aggregated counts.
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatRecentAftToolFailuresSection(counts: Map<ToolFailureKey, number>, options?: {
|
|
17
|
+
maxClasses?: number;
|
|
18
|
+
}): string;
|
|
19
|
+
/**
|
|
20
|
+
* Build the tool-failures section from the bridge log path (newest tail window).
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildRecentAftToolFailuresSectionFromLog(logPath?: string, options?: {
|
|
23
|
+
tailBytes?: number;
|
|
24
|
+
maxClasses?: number;
|
|
25
|
+
}): string;
|
|
26
|
+
//# sourceMappingURL=bridge-tool-failures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-tool-failures.d.ts","sourceRoot":"","sources":["../../src/lib/bridge-tool-failures.ts"],"names":[],"mappings":"AAKA,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,QAAkB,CAAC;AAErD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAO3C,wBAAgB,0BAA0B,IAAI,MAAM,CAGnD;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuBvE;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAmEpC;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAcxF;AAQD;;GAEG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,EACnC,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,MAAM,CAqBR;AAED;;GAEG;AACH,wBAAgB,wCAAwC,CACtD,OAAO,GAAE,MAAqC,EAC9C,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,MAAM,CAKR"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft",
|
|
3
|
-
"version": "0.39.
|
|
3
|
+
"version": "0.39.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Unified CLI for Agent File Tools (AFT) — setup, doctor, and diagnostics across supported agent harnesses (OpenCode, Pi)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@clack/prompts": "^1.2.0",
|
|
27
|
-
"@cortexkit/aft-bridge": "0.39.
|
|
27
|
+
"@cortexkit/aft-bridge": "0.39.3",
|
|
28
28
|
"comment-json": "^4.6.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|