@cortexkit/aft 0.28.1 → 0.29.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/commands/doctor.d.ts.map +1 -1
- package/dist/index.js +106 -1
- package/dist/lib/issue-body.d.ts +67 -0
- package/dist/lib/issue-body.d.ts.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAK/B,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAMvE,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,WAAW,GAAG,cAAc,CAAC;AAE9E,eAAO,MAAM,2BAA2B,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,EAapF,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,iBAAiB,EAAqB,CAAC;AAEhF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,MAAM,WAAW,CAAC;IACnC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA2GvE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAiBnE;AA4BD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,cAAc,EAAE,EAC1B,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CAgD5B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,IAAI,sBAAsB,CAsDzD;AA0HD,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF"}
|
package/dist/index.js
CHANGED
|
@@ -11131,6 +11131,98 @@ function createGitHubIssue(repo, title, body) {
|
|
|
11131
11131
|
}
|
|
11132
11132
|
var init_github = () => {};
|
|
11133
11133
|
|
|
11134
|
+
// src/lib/issue-body.ts
|
|
11135
|
+
function isErrorLogLine(line) {
|
|
11136
|
+
return ERROR_LOG_PATTERNS.some((rx) => rx.test(line));
|
|
11137
|
+
}
|
|
11138
|
+
function extractRecentErrors(sanitized, limit = 20) {
|
|
11139
|
+
const matches = [];
|
|
11140
|
+
const lines = sanitized.split(/\r?\n/);
|
|
11141
|
+
for (let i = lines.length - 1;i >= 0 && matches.length < limit; i -= 1) {
|
|
11142
|
+
if (isErrorLogLine(lines[i])) {
|
|
11143
|
+
matches.push(lines[i]);
|
|
11144
|
+
}
|
|
11145
|
+
}
|
|
11146
|
+
return matches.reverse();
|
|
11147
|
+
}
|
|
11148
|
+
function capBodyToGithubLimit(body, maxBytes = MAX_GITHUB_BODY_BYTES) {
|
|
11149
|
+
if (Buffer.byteLength(body, "utf8") <= maxBytes)
|
|
11150
|
+
return body;
|
|
11151
|
+
const heading = "## Logs (last";
|
|
11152
|
+
const headingIdx = body.indexOf(heading);
|
|
11153
|
+
if (headingIdx === -1) {
|
|
11154
|
+
const marker = `
|
|
11155
|
+
|
|
11156
|
+
[truncated for GitHub 64KB limit]
|
|
11157
|
+
`;
|
|
11158
|
+
const markerBytes2 = Buffer.byteLength(marker, "utf8");
|
|
11159
|
+
return truncateToByteBudget(body, maxBytes - markerBytes2) + marker;
|
|
11160
|
+
}
|
|
11161
|
+
const headingEol = body.indexOf(`
|
|
11162
|
+
`, headingIdx);
|
|
11163
|
+
if (headingEol === -1)
|
|
11164
|
+
return body;
|
|
11165
|
+
const nextSectionIdx = findNextTopLevelHeading(body, headingEol + 1);
|
|
11166
|
+
const logBlockStart = headingEol + 1;
|
|
11167
|
+
const logBlockEnd = nextSectionIdx === -1 ? body.length : nextSectionIdx;
|
|
11168
|
+
const head = body.slice(0, logBlockStart);
|
|
11169
|
+
const log = body.slice(logBlockStart, logBlockEnd);
|
|
11170
|
+
const tail = body.slice(logBlockEnd);
|
|
11171
|
+
const overheadBytes = Buffer.byteLength(head, "utf8") + Buffer.byteLength(tail, "utf8");
|
|
11172
|
+
const truncationMarker = `[truncated for GitHub 64KB limit — older log lines dropped]
|
|
11173
|
+
`;
|
|
11174
|
+
const markerBytes = Buffer.byteLength(truncationMarker, "utf8");
|
|
11175
|
+
const logBudget = maxBytes - overheadBytes - markerBytes;
|
|
11176
|
+
if (logBudget <= 0) {
|
|
11177
|
+
return `${head}${truncationMarker}${tail}`;
|
|
11178
|
+
}
|
|
11179
|
+
const lines = log.split(`
|
|
11180
|
+
`);
|
|
11181
|
+
let keepLines = lines;
|
|
11182
|
+
let kept = keepLines.join(`
|
|
11183
|
+
`);
|
|
11184
|
+
while (Buffer.byteLength(kept, "utf8") > logBudget && keepLines.length > 1) {
|
|
11185
|
+
const dropCount = Math.max(1, Math.floor(keepLines.length * 0.05));
|
|
11186
|
+
keepLines = keepLines.slice(dropCount);
|
|
11187
|
+
kept = keepLines.join(`
|
|
11188
|
+
`);
|
|
11189
|
+
}
|
|
11190
|
+
if (Buffer.byteLength(kept, "utf8") > logBudget) {
|
|
11191
|
+
kept = truncateToByteBudget(kept, logBudget);
|
|
11192
|
+
}
|
|
11193
|
+
return `${head}${truncationMarker}${kept}${tail}`;
|
|
11194
|
+
}
|
|
11195
|
+
function findNextTopLevelHeading(body, startIdx) {
|
|
11196
|
+
const idx = body.indexOf(`
|
|
11197
|
+
## `, startIdx);
|
|
11198
|
+
return idx === -1 ? -1 : idx + 1;
|
|
11199
|
+
}
|
|
11200
|
+
function truncateToByteBudget(input, maxBytes) {
|
|
11201
|
+
if (maxBytes <= 0)
|
|
11202
|
+
return "";
|
|
11203
|
+
const buf = Buffer.from(input, "utf8");
|
|
11204
|
+
if (buf.length <= maxBytes)
|
|
11205
|
+
return input;
|
|
11206
|
+
let end = maxBytes;
|
|
11207
|
+
while (end > 0 && (buf[end] & 192) === 128) {
|
|
11208
|
+
end -= 1;
|
|
11209
|
+
}
|
|
11210
|
+
return buf.subarray(0, end).toString("utf8");
|
|
11211
|
+
}
|
|
11212
|
+
var MAX_GITHUB_BODY_BYTES = 60000, ERROR_LOG_PATTERNS;
|
|
11213
|
+
var init_issue_body = __esm(() => {
|
|
11214
|
+
ERROR_LOG_PATTERNS = [
|
|
11215
|
+
/\bcrashed:/i,
|
|
11216
|
+
/\bfailed:/i,
|
|
11217
|
+
/\b(?:[A-Z][a-zA-Z]*)?Error:\s/,
|
|
11218
|
+
/\bpanicked at\b/,
|
|
11219
|
+
/\bEMERGENCY\b/,
|
|
11220
|
+
/\bexception\b/i,
|
|
11221
|
+
/^\s+at\s+[\w.<>$]+\s+\(/,
|
|
11222
|
+
/^\s+at\s+(?:file:|node_modules\/|[^/\s]+:\d+)/
|
|
11223
|
+
];
|
|
11224
|
+
});
|
|
11225
|
+
|
|
11134
11226
|
// src/lib/onnx-fix.ts
|
|
11135
11227
|
import { existsSync as existsSync12, rmSync as rmSync3 } from "node:fs";
|
|
11136
11228
|
import { join as join10 } from "node:path";
|
|
@@ -36393,6 +36485,15 @@ ${tail2 || "<no log output>"}
|
|
|
36393
36485
|
\`\`\`
|
|
36394
36486
|
`;
|
|
36395
36487
|
}).join(`
|
|
36488
|
+
`);
|
|
36489
|
+
const errorScanWindow = adapters.map((adapter) => {
|
|
36490
|
+
const path = adapter.getLogFile();
|
|
36491
|
+
return sanitizeContent(tailLogFile(path, 4000));
|
|
36492
|
+
}).join(`
|
|
36493
|
+
`);
|
|
36494
|
+
const recentErrorLines = extractRecentErrors(errorScanWindow, 20);
|
|
36495
|
+
const recentErrorsSection = recentErrorLines.length === 0 ? "_No error-shaped log lines found in recent history._" : ["```", recentErrorLines.join(`
|
|
36496
|
+
`), "```"].join(`
|
|
36396
36497
|
`);
|
|
36397
36498
|
const rawBody = [
|
|
36398
36499
|
"## Description",
|
|
@@ -36407,12 +36508,15 @@ ${tail2 || "<no log output>"}
|
|
|
36407
36508
|
"## Diagnostics",
|
|
36408
36509
|
renderDiagnosticsMarkdown(report),
|
|
36409
36510
|
"",
|
|
36511
|
+
"## Recent errors (last 20, sanitized)",
|
|
36512
|
+
recentErrorsSection,
|
|
36513
|
+
"",
|
|
36410
36514
|
"## Logs (last 200 lines per harness)",
|
|
36411
36515
|
logSections,
|
|
36412
36516
|
"_Usernames and home paths have been stripped from this report._"
|
|
36413
36517
|
].join(`
|
|
36414
36518
|
`);
|
|
36415
|
-
const body = sanitizeContent(rawBody);
|
|
36519
|
+
const body = capBodyToGithubLimit(sanitizeContent(rawBody));
|
|
36416
36520
|
const title = sanitizeContent(`AFT issue: ${description.slice(0, 72)}`);
|
|
36417
36521
|
const outPath = join17(process.cwd(), `aft-issue-${Date.now()}.md`);
|
|
36418
36522
|
writeFileSync4(outPath, `${body}
|
|
@@ -36443,6 +36547,7 @@ var init_doctor = __esm(() => {
|
|
|
36443
36547
|
init_fs_util();
|
|
36444
36548
|
init_github();
|
|
36445
36549
|
init_harness_select();
|
|
36550
|
+
init_issue_body();
|
|
36446
36551
|
init_lsp_cache();
|
|
36447
36552
|
init_onnx_fix();
|
|
36448
36553
|
init_prompts();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for shaping `aft doctor --issue` GitHub issue bodies within
|
|
3
|
+
* GitHub's hard ~64KB issue-body limit.
|
|
4
|
+
*
|
|
5
|
+
* Two responsibilities live here:
|
|
6
|
+
*
|
|
7
|
+
* 1. Error-line extraction — pull the most-recent ERROR-shaped lines from
|
|
8
|
+
* a sanitized log so the issue body has a dedicated `## Recent errors`
|
|
9
|
+
* section that survives even when the main log tail needs aggressive
|
|
10
|
+
* truncation.
|
|
11
|
+
*
|
|
12
|
+
* 2. GitHub byte-budget capping — when a rendered report exceeds the
|
|
13
|
+
* budget, shrink the main log block (the noise-heavy section) from
|
|
14
|
+
* the top, preserving the diagnostics / configuration / error sections
|
|
15
|
+
* that matter most.
|
|
16
|
+
*
|
|
17
|
+
* Both helpers operate on already-sanitized markdown so they're harness-
|
|
18
|
+
* agnostic — OpenCode and Pi share the same byte budget, the same
|
|
19
|
+
* truncation marker text, and the same precision/false-positive tradeoff
|
|
20
|
+
* on what counts as an "error" line.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* GitHub issue body byte budget. GitHub enforces ~64KB (65536 bytes); we
|
|
24
|
+
* leave 4KB of headroom for: GH's own URL encoding when opening the
|
|
25
|
+
* "Submit new issue" tab via `gh issue create --web`, future minor
|
|
26
|
+
* markdown growth from new sections, and a safety margin against any
|
|
27
|
+
* single-line entry crossing the cap.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MAX_GITHUB_BODY_BYTES = 60000;
|
|
30
|
+
/**
|
|
31
|
+
* Extract the most-recent error-shaped log lines from a sanitized log.
|
|
32
|
+
* Returns them in chronological order (oldest match first → newest match
|
|
33
|
+
* last) so the issue body reads naturally top-to-bottom.
|
|
34
|
+
*
|
|
35
|
+
* **Why this exists**: GitHub issue bodies have a hard ~64KB limit and a
|
|
36
|
+
* busy session's tail can easily blow past that. If the body needs
|
|
37
|
+
* truncation, the error section MUST survive because the whole point of
|
|
38
|
+
* the issue is the error. This extractor pulls them into a separate
|
|
39
|
+
* section that the body-cap is careful not to drop.
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractRecentErrors(sanitized: string, limit?: number): string[];
|
|
42
|
+
/**
|
|
43
|
+
* Apply a byte budget to a rendered issue body. If the body is already
|
|
44
|
+
* within budget, returns it unchanged. Otherwise rewrites the main
|
|
45
|
+
* fenced log block (whose heading must start with `## Logs (last`) to
|
|
46
|
+
* drop oldest log lines until the body fits, leaving a clear
|
|
47
|
+
* `[truncated for GitHub 64KB limit — older log lines dropped]` marker
|
|
48
|
+
* at the top of the kept slice.
|
|
49
|
+
*
|
|
50
|
+
* This deliberately ONLY touches the main-log section — the description,
|
|
51
|
+
* environment, diagnostics, and recent-errors sections are preserved
|
|
52
|
+
* intact because they're the most useful parts of the report. The main
|
|
53
|
+
* log is the noise-heavy one and the right thing to shrink first.
|
|
54
|
+
*
|
|
55
|
+
* AFT's main log section contains per-harness sub-sections (`#### opencode
|
|
56
|
+
* log (path)\n```...```\n#### pi log (path)\n```...```\n`). The cap walks
|
|
57
|
+
* the entire `## Logs (last ...` block as a single shrinkable region
|
|
58
|
+
* because precise per-harness allocation is fiddly and the alternative —
|
|
59
|
+
* dropping the whole log block on overflow — is strictly worse for
|
|
60
|
+
* debugging.
|
|
61
|
+
*
|
|
62
|
+
* Returns the (possibly-shrunk) body. UTF-8 byte length is the budget,
|
|
63
|
+
* matching how GitHub measures issue bodies (the issue API rejects
|
|
64
|
+
* `body` payloads above the limit).
|
|
65
|
+
*/
|
|
66
|
+
export declare function capBodyToGithubLimit(body: string, maxBytes?: number): string;
|
|
67
|
+
//# sourceMappingURL=issue-body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-body.d.ts","sourceRoot":"","sources":["../../src/lib/issue-body.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AA2C5C;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAU3E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA8B,GACvC,MAAM,CAqER"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
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",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@clack/prompts": "^1.2.0",
|
|
26
|
-
"@cortexkit/aft-bridge": "0.
|
|
26
|
+
"@cortexkit/aft-bridge": "0.29.0",
|
|
27
27
|
"comment-json": "^4.6.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|