ai-project-manage-cli 8.1.26 → 8.1.28
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/index.js +62 -26
- package/dist/scripts/ensure_baseline.sh +3 -0
- package/dist/scripts/ensure_feature_branch.sh +18 -0
- package/dist/scripts/push_code.sh +3 -0
- package/dist/worker-script.js +167 -61
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1436,7 +1436,7 @@ function resolveHomeRepositoryAbsolutePaths(workdirInput, entries) {
|
|
|
1436
1436
|
}
|
|
1437
1437
|
|
|
1438
1438
|
// src/utils/git.ts
|
|
1439
|
-
import { execFile } from "child_process";
|
|
1439
|
+
import { execFile, spawn } from "child_process";
|
|
1440
1440
|
import { dirname as dirname3, join as join8 } from "path";
|
|
1441
1441
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1442
1442
|
import { promisify } from "util";
|
|
@@ -1505,7 +1505,9 @@ async function execGit(cwd, args, quietOrOptions = false) {
|
|
|
1505
1505
|
const e = err;
|
|
1506
1506
|
if (e.killed || e.signal === "SIGTERM" || e.code === "ETIMEDOUT") {
|
|
1507
1507
|
throw new Error(
|
|
1508
|
-
`[apm] git ${args.join(
|
|
1508
|
+
`[apm] git ${args.join(
|
|
1509
|
+
" "
|
|
1510
|
+
)} \u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09\uFF0C\u8BF7\u68C0\u67E5\u5230\u8FDC\u7A0B\u7684\u7F51\u7EDC/SSH\uFF1B\u53EF\u7A0D\u540E\u91CD\u8BD5`
|
|
1509
1511
|
);
|
|
1510
1512
|
}
|
|
1511
1513
|
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
@@ -1528,33 +1530,67 @@ async function runGitScript(name, options) {
|
|
|
1528
1530
|
const timeoutMs = options.timeoutMs ?? GIT_NETWORK_TIMEOUT_MS;
|
|
1529
1531
|
const script = resolveGitScript(name);
|
|
1530
1532
|
const args = [script, ...options.args ?? []];
|
|
1531
|
-
|
|
1532
|
-
const
|
|
1533
|
+
return new Promise((resolve5, reject) => {
|
|
1534
|
+
const child = spawn("bash", args, {
|
|
1533
1535
|
cwd: options.cwd,
|
|
1534
1536
|
env: gitExecEnv(),
|
|
1535
|
-
|
|
1536
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
1537
|
-
timeout: timeoutMs,
|
|
1538
|
-
killSignal: "SIGTERM"
|
|
1537
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1539
1538
|
});
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1539
|
+
let stderrBuf = "";
|
|
1540
|
+
let settled = false;
|
|
1541
|
+
let timedOut = false;
|
|
1542
|
+
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
1543
|
+
timedOut = true;
|
|
1544
|
+
child.kill("SIGTERM");
|
|
1545
|
+
const forceKill = setTimeout(() => {
|
|
1546
|
+
child.kill("SIGKILL");
|
|
1547
|
+
}, 2e3);
|
|
1548
|
+
forceKill.unref();
|
|
1549
|
+
}, timeoutMs) : null;
|
|
1550
|
+
const finish = (fn) => {
|
|
1551
|
+
if (settled) return;
|
|
1552
|
+
settled = true;
|
|
1553
|
+
if (timer) clearTimeout(timer);
|
|
1554
|
+
fn();
|
|
1555
|
+
};
|
|
1556
|
+
child.stdout?.on("data", (chunk) => {
|
|
1557
|
+
process.stdout.write(chunk);
|
|
1558
|
+
});
|
|
1559
|
+
child.stderr?.on("data", (chunk) => {
|
|
1560
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
1561
|
+
stderrBuf += text;
|
|
1562
|
+
process.stderr.write(chunk);
|
|
1563
|
+
});
|
|
1564
|
+
child.on("error", (err) => {
|
|
1565
|
+
finish(() => reject(new Error(`[apm] ${name} \u542F\u52A8\u5931\u8D25: ${err.message}`)));
|
|
1566
|
+
});
|
|
1567
|
+
child.on("close", (code, signal) => {
|
|
1568
|
+
finish(() => {
|
|
1569
|
+
if (timedOut || signal === "SIGTERM" || signal === "SIGKILL") {
|
|
1570
|
+
reject(
|
|
1571
|
+
new Error(
|
|
1572
|
+
`[apm] ${name} \u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09\uFF0C\u8BF7\u770B\u4E0A\u65B9\u6700\u540E\u4E00\u6B65\u65E5\u5FD7\u5B9A\u4F4D\u5361\u70B9\uFF08\u591A\u4E3A ls-remote/fetch/push\uFF09\uFF1B\u68C0\u67E5\u5230\u8FDC\u7A0B\u7684\u7F51\u7EDC/SSH \u540E\u53EF\u7A0D\u540E\u91CD\u8BD5`
|
|
1573
|
+
)
|
|
1574
|
+
);
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1577
|
+
if (code === skipCode) {
|
|
1578
|
+
resolve5(false);
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (code === 0) {
|
|
1582
|
+
resolve5(true);
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
const detail = stderrBuf.trim();
|
|
1586
|
+
reject(
|
|
1587
|
+
new Error(
|
|
1588
|
+
`[apm] ${name} \u5931\u8D25${detail ? `: ${detail}` : code != null ? ` (exit ${code})` : ""}`
|
|
1589
|
+
)
|
|
1590
|
+
);
|
|
1591
|
+
});
|
|
1592
|
+
});
|
|
1593
|
+
});
|
|
1558
1594
|
}
|
|
1559
1595
|
async function commitWorkingTreeIfDirty(cwd, message) {
|
|
1560
1596
|
await ensureGitRepo(cwd);
|
|
@@ -6,8 +6,11 @@ set -euo pipefail
|
|
|
6
6
|
|
|
7
7
|
baseline="${1:?用法: ensure_baseline.sh <baseline-branch>}"
|
|
8
8
|
|
|
9
|
+
echo "[apm] ensure_baseline: fetch origin ${baseline} …"
|
|
9
10
|
git fetch origin "$baseline"
|
|
11
|
+
echo "[apm] ensure_baseline: ls-remote origin ${baseline} …"
|
|
10
12
|
if git ls-remote --heads origin "$baseline" | grep -q .; then
|
|
13
|
+
echo "[apm] ensure_baseline: origin/${baseline} 已确认"
|
|
11
14
|
exit 0
|
|
12
15
|
fi
|
|
13
16
|
|
|
@@ -9,9 +9,12 @@ baseline="${2:?用法: ensure_feature_branch.sh <branch> <baseline-branch>}"
|
|
|
9
9
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
10
|
|
|
11
11
|
git rev-parse --git-dir >/dev/null
|
|
12
|
+
origin_url="$(git config --get remote.origin.url 2>/dev/null || true)"
|
|
13
|
+
echo "[apm] ensure_feature_branch: branch=${branch} baseline=${baseline}${origin_url:+ origin=${origin_url}}"
|
|
12
14
|
|
|
13
15
|
# 有未提交改动时先 stash(含 untracked),再切/建分支,避免污染目标分支工作区
|
|
14
16
|
if [[ -n "$(git status --porcelain)" ]]; then
|
|
17
|
+
echo "[apm] ensure_feature_branch: stash 未提交改动 …"
|
|
15
18
|
git stash push -u -m "apm: ensure ${branch}"
|
|
16
19
|
echo "[apm] 已 stash 未提交改动,再确认分支 ${branch}"
|
|
17
20
|
fi
|
|
@@ -20,16 +23,26 @@ current="$(git rev-parse --abbrev-ref HEAD)"
|
|
|
20
23
|
if [[ "$current" == "$branch" ]]; then
|
|
21
24
|
echo "[apm] 已在分支 ${branch}"
|
|
22
25
|
else
|
|
26
|
+
echo "[apm] ensure_feature_branch: 当前 ${current} → 准备 ${branch}"
|
|
23
27
|
bash "$SCRIPT_DIR/ensure_baseline.sh" "$baseline"
|
|
24
28
|
|
|
29
|
+
echo "[apm] ensure_feature_branch: ls-remote origin ${branch} …"
|
|
25
30
|
if git ls-remote --heads origin "$branch" | grep -q .; then
|
|
31
|
+
echo "[apm] ensure_feature_branch: 远程已有 ${branch},fetch + checkout …"
|
|
26
32
|
git fetch origin "$branch"
|
|
27
33
|
git checkout -B "$branch" "origin/${branch}"
|
|
28
34
|
elif git show-ref --verify --quiet "refs/heads/${branch}"; then
|
|
35
|
+
echo "[apm] ensure_feature_branch: 本地已有 ${branch},checkout …"
|
|
29
36
|
git checkout "$branch"
|
|
30
37
|
echo "[apm] 分支 ${branch} 已存在,跳过创建"
|
|
31
38
|
else
|
|
39
|
+
# 先切到远程基线(便于 post-checkout 等 hook 装依赖),再基于 origin/<baseline> 建特性分支(不基于本地基线)
|
|
40
|
+
echo "[apm] ensure_feature_branch: 本地/远程均无 ${branch},先切基线 origin/${baseline} …"
|
|
41
|
+
echo "[apm] ensure_feature_branch: fetch origin ${baseline} …"
|
|
32
42
|
git fetch origin "$baseline"
|
|
43
|
+
echo "[apm] ensure_feature_branch: checkout -B ${baseline} origin/${baseline} …"
|
|
44
|
+
git checkout -B "$baseline" "origin/${baseline}"
|
|
45
|
+
echo "[apm] ensure_feature_branch: 基于 origin/${baseline} 创建 ${branch} …"
|
|
33
46
|
set +e
|
|
34
47
|
git checkout --no-track -b "$branch" "origin/${baseline}"
|
|
35
48
|
create_status=$?
|
|
@@ -44,14 +57,19 @@ else
|
|
|
44
57
|
else
|
|
45
58
|
exit "$create_status"
|
|
46
59
|
fi
|
|
60
|
+
else
|
|
61
|
+
echo "[apm] ensure_feature_branch: 已创建本地分支 ${branch}"
|
|
47
62
|
fi
|
|
48
63
|
fi
|
|
49
64
|
fi
|
|
50
65
|
|
|
51
66
|
# 本地已在目标分支时也要补推:上次 push 挂死/超时后常见「本地有、远端无」
|
|
67
|
+
echo "[apm] ensure_feature_branch: 再次 ls-remote 确认远程是否已有 ${branch} …"
|
|
52
68
|
if ! git ls-remote --heads origin "$branch" | grep -q .; then
|
|
53
69
|
echo "[apm] 远程尚无 ${branch},正在 push …"
|
|
54
70
|
bash "$SCRIPT_DIR/push_code.sh" "$branch"
|
|
71
|
+
else
|
|
72
|
+
echo "[apm] ensure_feature_branch: 远程已有 ${branch},跳过 push"
|
|
55
73
|
fi
|
|
56
74
|
|
|
57
75
|
echo "[apm] 已就绪分支 ${branch}"
|
|
@@ -17,5 +17,8 @@ if ! git config --get remote.origin.url >/dev/null 2>&1; then
|
|
|
17
17
|
exit 2
|
|
18
18
|
fi
|
|
19
19
|
|
|
20
|
+
origin_url="$(git config --get remote.origin.url)"
|
|
21
|
+
echo "[apm] push: git push -u origin ${branch}(${origin_url})…"
|
|
20
22
|
# 显式 origin + -u:避免裸 git push 因 upstream 与当前分支名不一致失败
|
|
21
23
|
git push -u origin "$branch"
|
|
24
|
+
echo "[apm] push: 完成 ${branch}"
|
package/dist/worker-script.js
CHANGED
|
@@ -359,7 +359,7 @@ async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
// src/utils/git.ts
|
|
362
|
-
import { execFile } from "child_process";
|
|
362
|
+
import { execFile, spawn } from "child_process";
|
|
363
363
|
import { dirname, join as join3 } from "path";
|
|
364
364
|
import { fileURLToPath } from "url";
|
|
365
365
|
import { promisify } from "util";
|
|
@@ -428,7 +428,9 @@ async function execGit(cwd, args, quietOrOptions = false) {
|
|
|
428
428
|
const e = err;
|
|
429
429
|
if (e.killed || e.signal === "SIGTERM" || e.code === "ETIMEDOUT") {
|
|
430
430
|
throw new Error(
|
|
431
|
-
`[apm] git ${args.join(
|
|
431
|
+
`[apm] git ${args.join(
|
|
432
|
+
" "
|
|
433
|
+
)} \u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09\uFF0C\u8BF7\u68C0\u67E5\u5230\u8FDC\u7A0B\u7684\u7F51\u7EDC/SSH\uFF1B\u53EF\u7A0D\u540E\u91CD\u8BD5`
|
|
432
434
|
);
|
|
433
435
|
}
|
|
434
436
|
const detail = (e.stderr ?? e.message ?? String(err)).trim();
|
|
@@ -458,33 +460,67 @@ async function runGitScript(name, options) {
|
|
|
458
460
|
const timeoutMs = options.timeoutMs ?? GIT_NETWORK_TIMEOUT_MS;
|
|
459
461
|
const script = resolveGitScript(name);
|
|
460
462
|
const args = [script, ...options.args ?? []];
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
+
return new Promise((resolve7, reject) => {
|
|
464
|
+
const child = spawn("bash", args, {
|
|
463
465
|
cwd: options.cwd,
|
|
464
466
|
env: gitExecEnv(),
|
|
465
|
-
|
|
466
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
467
|
-
timeout: timeoutMs,
|
|
468
|
-
killSignal: "SIGTERM"
|
|
467
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
469
468
|
});
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
469
|
+
let stderrBuf = "";
|
|
470
|
+
let settled = false;
|
|
471
|
+
let timedOut = false;
|
|
472
|
+
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
473
|
+
timedOut = true;
|
|
474
|
+
child.kill("SIGTERM");
|
|
475
|
+
const forceKill = setTimeout(() => {
|
|
476
|
+
child.kill("SIGKILL");
|
|
477
|
+
}, 2e3);
|
|
478
|
+
forceKill.unref();
|
|
479
|
+
}, timeoutMs) : null;
|
|
480
|
+
const finish = (fn) => {
|
|
481
|
+
if (settled) return;
|
|
482
|
+
settled = true;
|
|
483
|
+
if (timer) clearTimeout(timer);
|
|
484
|
+
fn();
|
|
485
|
+
};
|
|
486
|
+
child.stdout?.on("data", (chunk) => {
|
|
487
|
+
process.stdout.write(chunk);
|
|
488
|
+
});
|
|
489
|
+
child.stderr?.on("data", (chunk) => {
|
|
490
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
491
|
+
stderrBuf += text;
|
|
492
|
+
process.stderr.write(chunk);
|
|
493
|
+
});
|
|
494
|
+
child.on("error", (err) => {
|
|
495
|
+
finish(() => reject(new Error(`[apm] ${name} \u542F\u52A8\u5931\u8D25: ${err.message}`)));
|
|
496
|
+
});
|
|
497
|
+
child.on("close", (code, signal) => {
|
|
498
|
+
finish(() => {
|
|
499
|
+
if (timedOut || signal === "SIGTERM" || signal === "SIGKILL") {
|
|
500
|
+
reject(
|
|
501
|
+
new Error(
|
|
502
|
+
`[apm] ${name} \u8D85\u65F6\uFF08>${timeoutMs}ms\uFF09\uFF0C\u8BF7\u770B\u4E0A\u65B9\u6700\u540E\u4E00\u6B65\u65E5\u5FD7\u5B9A\u4F4D\u5361\u70B9\uFF08\u591A\u4E3A ls-remote/fetch/push\uFF09\uFF1B\u68C0\u67E5\u5230\u8FDC\u7A0B\u7684\u7F51\u7EDC/SSH \u540E\u53EF\u7A0D\u540E\u91CD\u8BD5`
|
|
503
|
+
)
|
|
504
|
+
);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (code === skipCode) {
|
|
508
|
+
resolve7(false);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (code === 0) {
|
|
512
|
+
resolve7(true);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const detail = stderrBuf.trim();
|
|
516
|
+
reject(
|
|
517
|
+
new Error(
|
|
518
|
+
`[apm] ${name} \u5931\u8D25${detail ? `: ${detail}` : code != null ? ` (exit ${code})` : ""}`
|
|
519
|
+
)
|
|
520
|
+
);
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
});
|
|
488
524
|
}
|
|
489
525
|
async function branchHasChangesAgainstBase(cwd, baseBranch, headBranch) {
|
|
490
526
|
return runGitScript("branch_has_changes.sh", {
|
|
@@ -2401,6 +2437,17 @@ async function createApmCursorAgentStore(cfg2, workspaceRef) {
|
|
|
2401
2437
|
runEvents: mirrorRunEventsForVisualization(cfg2, sqlite.runEvents)
|
|
2402
2438
|
});
|
|
2403
2439
|
}
|
|
2440
|
+
async function purgeLocalSqliteAgentData(input) {
|
|
2441
|
+
const agentId = input.agentId.trim();
|
|
2442
|
+
const workspaceRef = input.workspaceRef.trim();
|
|
2443
|
+
if (!agentId || !workspaceRef) return;
|
|
2444
|
+
const sqlite = await openSqliteLocalAgentStore(workspaceRef);
|
|
2445
|
+
const runIds = [...input.runIds ?? []];
|
|
2446
|
+
if (runIds.length > 0) {
|
|
2447
|
+
await sqlite.runEvents.delete({ filter: { runIds } });
|
|
2448
|
+
}
|
|
2449
|
+
await sqlite.checkpoints.delete({ filter: { agentIds: [agentId] } });
|
|
2450
|
+
}
|
|
2404
2451
|
|
|
2405
2452
|
// src/commands/connect/core/worker/run-steer.ts
|
|
2406
2453
|
var impl = null;
|
|
@@ -2427,6 +2474,10 @@ function deliverRunSteer(text) {
|
|
|
2427
2474
|
}
|
|
2428
2475
|
|
|
2429
2476
|
// src/commands/connect/cursor-agent.ts
|
|
2477
|
+
function isCorruptLocalAgentCheckpointError(err) {
|
|
2478
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2479
|
+
return /Corrupt local agent checkpoint/i.test(message) || /missing root blob/i.test(message);
|
|
2480
|
+
}
|
|
2430
2481
|
var noopRemoteLogSync = {
|
|
2431
2482
|
schedule(_session) {
|
|
2432
2483
|
},
|
|
@@ -2475,6 +2526,19 @@ async function obtainAgent(ctx) {
|
|
|
2475
2526
|
err instanceof Error ? err.message : err
|
|
2476
2527
|
);
|
|
2477
2528
|
ctx.onInvalidatePersistedAgentId?.();
|
|
2529
|
+
if (isCorruptLocalAgentCheckpointError(err)) {
|
|
2530
|
+
try {
|
|
2531
|
+
await purgeLocalSqliteAgentData({
|
|
2532
|
+
workspaceRef: ctx.cwd,
|
|
2533
|
+
agentId: savedAgentId
|
|
2534
|
+
});
|
|
2535
|
+
} catch (purgeErr) {
|
|
2536
|
+
console.warn(
|
|
2537
|
+
`[apm] \u6E05\u7406\u635F\u574F checkpoint \u5931\u8D25 agentId=${savedAgentId}:`,
|
|
2538
|
+
purgeErr instanceof Error ? purgeErr.message : purgeErr
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2478
2542
|
}
|
|
2479
2543
|
}
|
|
2480
2544
|
try {
|
|
@@ -2489,6 +2553,9 @@ async function obtainAgent(ctx) {
|
|
|
2489
2553
|
}
|
|
2490
2554
|
}
|
|
2491
2555
|
async function runCursorAgent(cfg2, ctx, options) {
|
|
2556
|
+
return runCursorAgentAttempt(cfg2, ctx, options, { allowCorruptRetry: true });
|
|
2557
|
+
}
|
|
2558
|
+
async function runCursorAgentAttempt(cfg2, ctx, options, attempt) {
|
|
2492
2559
|
const signal = options.signal;
|
|
2493
2560
|
if (signal?.aborted) {
|
|
2494
2561
|
throw new Error("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u4EFB\u52A1\u4E2D\u65AD");
|
|
@@ -2535,6 +2602,8 @@ async function runCursorAgent(cfg2, ctx, options) {
|
|
|
2535
2602
|
const eventSession = options.eventSession ?? new EventSession(prompt);
|
|
2536
2603
|
const syncRemoteLog = options.createRemoteLogSync ? options.createRemoteLogSync(agent.agentId) : noopRemoteLogSync;
|
|
2537
2604
|
let activeRun;
|
|
2605
|
+
let retryCorruptWithNewAgent = false;
|
|
2606
|
+
const corruptAgentId = agent.agentId?.trim() || ctx.resumeAgentId?.trim();
|
|
2538
2607
|
const abortRun = () => {
|
|
2539
2608
|
if (!activeRun?.supports("cancel")) return;
|
|
2540
2609
|
void activeRun.cancel().catch(() => void 0);
|
|
@@ -2603,58 +2672,94 @@ async function runCursorAgent(cfg2, ctx, options) {
|
|
|
2603
2672
|
resultText: result.result
|
|
2604
2673
|
});
|
|
2605
2674
|
console.error(`[apm] ${failureMessage}`);
|
|
2606
|
-
if (resumed) {
|
|
2675
|
+
if (attempt.allowCorruptRetry && resumed && isCorruptLocalAgentCheckpointError(failureMessage)) {
|
|
2676
|
+
retryCorruptWithNewAgent = true;
|
|
2607
2677
|
invalidateAgentMapping();
|
|
2678
|
+
} else {
|
|
2679
|
+
if (resumed) {
|
|
2680
|
+
invalidateAgentMapping();
|
|
2681
|
+
}
|
|
2682
|
+
throw new Error(failureMessage);
|
|
2608
2683
|
}
|
|
2609
|
-
|
|
2610
|
-
}
|
|
2611
|
-
if (result.status === "cancelled") {
|
|
2684
|
+
} else if (result.status === "cancelled") {
|
|
2612
2685
|
throw new Error(`Cursor run \u5DF2\u53D6\u6D88: ${result.id}`);
|
|
2613
|
-
}
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
)
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
);
|
|
2686
|
+
} else {
|
|
2687
|
+
console.log(`[apm] Cursor Agent \u5B8C\u6210 messageId=${ctx.messageId}`);
|
|
2688
|
+
const artifacts = await agent.listArtifacts().catch(() => []);
|
|
2689
|
+
const artifactDocuments = [];
|
|
2690
|
+
for (const artifact of artifacts) {
|
|
2691
|
+
try {
|
|
2692
|
+
const content = (await agent.downloadArtifact(artifact.path)).toString("utf8");
|
|
2693
|
+
artifactDocuments.push({ path: artifact.path, content });
|
|
2694
|
+
} catch (err) {
|
|
2695
|
+
console.warn(
|
|
2696
|
+
`[apm] \u8BFB\u53D6\u4EA7\u7269\u5931\u8D25 path=${artifact.path}:`,
|
|
2697
|
+
err instanceof Error ? err.message : err
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2628
2700
|
}
|
|
2701
|
+
return {
|
|
2702
|
+
runId: result.id,
|
|
2703
|
+
agentId: agent.agentId,
|
|
2704
|
+
status: result.status,
|
|
2705
|
+
result: result.result,
|
|
2706
|
+
durationMs: result.durationMs,
|
|
2707
|
+
usage: result.usage,
|
|
2708
|
+
modelId: result.model?.id?.trim() || ctx.model?.trim() || void 0,
|
|
2709
|
+
assistantText: eventSession.getAssistantText(),
|
|
2710
|
+
createPlan: eventSession.getCreatePlanContent(),
|
|
2711
|
+
artifacts,
|
|
2712
|
+
artifactDocuments
|
|
2713
|
+
};
|
|
2629
2714
|
}
|
|
2630
|
-
return {
|
|
2631
|
-
runId: result.id,
|
|
2632
|
-
agentId: agent.agentId,
|
|
2633
|
-
status: result.status,
|
|
2634
|
-
result: result.result,
|
|
2635
|
-
durationMs: result.durationMs,
|
|
2636
|
-
usage: result.usage,
|
|
2637
|
-
modelId: result.model?.id?.trim() || ctx.model?.trim() || void 0,
|
|
2638
|
-
assistantText: eventSession.getAssistantText(),
|
|
2639
|
-
createPlan: eventSession.getCreatePlanContent(),
|
|
2640
|
-
artifacts,
|
|
2641
|
-
artifactDocuments
|
|
2642
|
-
};
|
|
2643
2715
|
} catch (err) {
|
|
2644
|
-
if (
|
|
2716
|
+
if (retryCorruptWithNewAgent) {
|
|
2717
|
+
} else if (attempt.allowCorruptRetry && resumed && isCorruptLocalAgentCheckpointError(err)) {
|
|
2718
|
+
console.warn(
|
|
2719
|
+
`[apm] checkpoint \u635F\u574F\uFF08agentId=${corruptAgentId ?? "?"}\uFF09\uFF0C\u672C\u8F6E\u6539\u7528\u65B0 Agent`
|
|
2720
|
+
);
|
|
2721
|
+
retryCorruptWithNewAgent = true;
|
|
2722
|
+
invalidateAgentMapping();
|
|
2723
|
+
} else if (err instanceof CursorAgentError) {
|
|
2645
2724
|
if (resumed) {
|
|
2646
2725
|
invalidateAgentMapping();
|
|
2647
2726
|
}
|
|
2648
2727
|
throw new Error(
|
|
2649
2728
|
`Cursor \u542F\u52A8\u5931\u8D25: ${err.message}${err.isRetryable ? "\uFF08\u53EF\u91CD\u8BD5\uFF09" : ""}`
|
|
2650
2729
|
);
|
|
2730
|
+
} else {
|
|
2731
|
+
throw err;
|
|
2651
2732
|
}
|
|
2652
|
-
throw err;
|
|
2653
2733
|
} finally {
|
|
2654
2734
|
clearRunSteer();
|
|
2655
2735
|
signal?.removeEventListener("abort", abortRun);
|
|
2656
2736
|
await agent[Symbol.asyncDispose]();
|
|
2657
2737
|
}
|
|
2738
|
+
if (retryCorruptWithNewAgent) {
|
|
2739
|
+
if (corruptAgentId) {
|
|
2740
|
+
try {
|
|
2741
|
+
await purgeLocalSqliteAgentData({
|
|
2742
|
+
workspaceRef: workdir,
|
|
2743
|
+
agentId: corruptAgentId
|
|
2744
|
+
});
|
|
2745
|
+
} catch (purgeErr) {
|
|
2746
|
+
console.warn(
|
|
2747
|
+
`[apm] \u6E05\u7406\u635F\u574F checkpoint \u5931\u8D25 agentId=${corruptAgentId}:`,
|
|
2748
|
+
purgeErr instanceof Error ? purgeErr.message : purgeErr
|
|
2749
|
+
);
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
console.warn(
|
|
2753
|
+
`[apm] \u4E22\u5F03\u635F\u574F Agent${corruptAgentId ? ` agentId=${corruptAgentId}` : ""}\uFF0C\u65B0\u5EFA\u540E\u91CD\u8BD5 messageId=${ctx.messageId}`
|
|
2754
|
+
);
|
|
2755
|
+
return runCursorAgentAttempt(
|
|
2756
|
+
cfg2,
|
|
2757
|
+
{ ...ctx, resumeAgentId: void 0 },
|
|
2758
|
+
options,
|
|
2759
|
+
{ allowCorruptRetry: false }
|
|
2760
|
+
);
|
|
2761
|
+
}
|
|
2762
|
+
throw new Error("Cursor Agent \u672A\u8FD4\u56DE\u7ED3\u679C");
|
|
2658
2763
|
}
|
|
2659
2764
|
|
|
2660
2765
|
// src/commands/connect/webide-agent-registry.ts
|
|
@@ -4304,8 +4409,9 @@ ${assumptionAnswersText}` : msg2.content,
|
|
|
4304
4409
|
if (startAction) {
|
|
4305
4410
|
await webIdeDiscardTransitionPrepDraft(cfg2, taskId, startAction);
|
|
4306
4411
|
}
|
|
4307
|
-
if (detail.includes("\u590D\u7528 Agent") || detail.includes("resume")) {
|
|
4412
|
+
if (detail.includes("\u590D\u7528 Agent") || detail.includes("resume") || /Corrupt local agent checkpoint/i.test(detail) || /missing root blob/i.test(detail)) {
|
|
4308
4413
|
clearWebIdeAgentId(workdir, taskId);
|
|
4414
|
+
clearWebIdeDesignAgentId(workdir, taskId);
|
|
4309
4415
|
}
|
|
4310
4416
|
try {
|
|
4311
4417
|
await setError(cfg2, messageId, detail);
|