@xdevops/issue-auto-finish 1.0.73 → 1.0.75
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/ai-runner/ModelMapping.d.ts +3 -2
- package/dist/ai-runner/ModelMapping.d.ts.map +1 -1
- package/dist/{ai-runner-U4WLO5GZ.js → ai-runner-RUE5D72W.js} +2 -2
- package/dist/{analyze-67N2EEJY.js → analyze-IZFTWCNR.js} +3 -3
- package/dist/{braindump-6NNPGVFV.js → braindump-SXLAURR4.js} +4 -4
- package/dist/{chunk-XAMJNIXE.js → chunk-66OK4LG3.js} +40 -28
- package/dist/chunk-66OK4LG3.js.map +1 -0
- package/dist/{chunk-ZPHUJTZP.js → chunk-JL6ALTPS.js} +6 -6
- package/dist/{chunk-BCOL4JRM.js → chunk-KWOM6URK.js} +16 -12
- package/dist/chunk-KWOM6URK.js.map +1 -0
- package/dist/{chunk-RFMARJ5D.js → chunk-MC7YPVJG.js} +51 -14
- package/dist/chunk-MC7YPVJG.js.map +1 -0
- package/dist/{chunk-VM5NQHEO.js → chunk-NBX5LNCU.js} +3 -3
- package/dist/{chunk-SKA53TLK.js → chunk-OOJNTGB5.js} +5 -3
- package/dist/chunk-OOJNTGB5.js.map +1 -0
- package/dist/{chunk-WR3O4ATI.js → chunk-URE5IBQE.js} +2 -2
- package/dist/{chunk-C4NES56F.js → chunk-VYNKAT4P.js} +3 -2
- package/dist/{chunk-C4NES56F.js.map → chunk-VYNKAT4P.js.map} +1 -1
- package/dist/cli/setup/env-metadata.d.ts.map +1 -1
- package/dist/cli.js +7 -7
- package/dist/{config-C6QBYWFQ.js → config-LLOHFS6J.js} +3 -3
- package/dist/config-schema.d.ts +2 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/errors/AIExecutionError.d.ts +2 -0
- package/dist/errors/AIExecutionError.d.ts.map +1 -1
- package/dist/index.js +7 -7
- package/dist/{init-J26XGSST.js → init-EQWSE5FX.js} +5 -5
- package/dist/lib.js +3 -3
- package/dist/lifecycle/ActionLifecycleManager.d.ts +2 -2
- package/dist/lifecycle/ActionLifecycleManager.d.ts.map +1 -1
- package/dist/orchestrator/PipelineOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/steps/FailureHandler.d.ts.map +1 -1
- package/dist/phases/BasePhase.d.ts +5 -0
- package/dist/phases/BasePhase.d.ts.map +1 -1
- package/dist/{restart-PD3WUJGI.js → restart-24AKNL74.js} +5 -5
- package/dist/run.js +7 -7
- package/dist/{start-2NRFI3LI.js → start-YUT6GSVS.js} +5 -5
- package/dist/tracker/IssueState.d.ts +2 -0
- package/dist/tracker/IssueState.d.ts.map +1 -1
- package/dist/tracker/IssueTracker.d.ts +1 -1
- package/dist/tracker/IssueTracker.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/web/frontend/dist/assets/{index-CtY1m1Qk.js → index-C82qOYx3.js} +40 -40
- package/src/web/frontend/dist/index.html +1 -1
- package/dist/chunk-BCOL4JRM.js.map +0 -1
- package/dist/chunk-RFMARJ5D.js.map +0 -1
- package/dist/chunk-SKA53TLK.js.map +0 -1
- package/dist/chunk-XAMJNIXE.js.map +0 -1
- /package/dist/{ai-runner-U4WLO5GZ.js.map → ai-runner-RUE5D72W.js.map} +0 -0
- /package/dist/{analyze-67N2EEJY.js.map → analyze-IZFTWCNR.js.map} +0 -0
- /package/dist/{braindump-6NNPGVFV.js.map → braindump-SXLAURR4.js.map} +0 -0
- /package/dist/{chunk-ZPHUJTZP.js.map → chunk-JL6ALTPS.js.map} +0 -0
- /package/dist/{chunk-VM5NQHEO.js.map → chunk-NBX5LNCU.js.map} +0 -0
- /package/dist/{chunk-WR3O4ATI.js.map → chunk-URE5IBQE.js.map} +0 -0
- /package/dist/{config-C6QBYWFQ.js.map → config-LLOHFS6J.js.map} +0 -0
- /package/dist/{init-J26XGSST.js.map → init-EQWSE5FX.js.map} +0 -0
- /package/dist/{restart-PD3WUJGI.js.map → restart-24AKNL74.js.map} +0 -0
- /package/dist/{start-2NRFI3LI.js.map → start-YUT6GSVS.js.map} +0 -0
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
createAIRunner,
|
|
49
49
|
getRunnerCapabilities,
|
|
50
50
|
isShuttingDown
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-66OK4LG3.js";
|
|
52
52
|
import {
|
|
53
53
|
logger,
|
|
54
54
|
runWithIssueContext
|
|
@@ -656,16 +656,17 @@ var IssueTracker = class extends BaseTracker {
|
|
|
656
656
|
logger5.info("Issue state updated", { issueIid, state });
|
|
657
657
|
eventBus.emitTyped("issue:stateChanged", { issueIid, state, record });
|
|
658
658
|
}
|
|
659
|
-
markFailed(issueIid, error, failedAtState) {
|
|
659
|
+
markFailed(issueIid, error, failedAtState, isRetryable) {
|
|
660
660
|
const record = this.collection[this.key(issueIid)];
|
|
661
661
|
if (!record) return;
|
|
662
662
|
record.state = "failed" /* Failed */;
|
|
663
663
|
record.lastError = error;
|
|
664
664
|
record.failedAtState = failedAtState;
|
|
665
|
+
record.lastErrorRetryable = isRetryable;
|
|
665
666
|
record.attempts += 1;
|
|
666
667
|
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
667
668
|
this.save();
|
|
668
|
-
logger5.warn("Issue marked as failed", { issueIid, error, failedAtState, attempts: record.attempts });
|
|
669
|
+
logger5.warn("Issue marked as failed", { issueIid, error, failedAtState, attempts: record.attempts, isRetryable });
|
|
669
670
|
eventBus.emitTyped("issue:failed", { issueIid, error, failedAtState, record });
|
|
670
671
|
}
|
|
671
672
|
isProcessing(issueIid) {
|
|
@@ -697,7 +698,7 @@ var IssueTracker = class extends BaseTracker {
|
|
|
697
698
|
getDrivableIssues(maxRetries, stalledThresholdMs) {
|
|
698
699
|
return this.getAllRecords().filter((record) => {
|
|
699
700
|
const lm = this.lifecycleFor(record);
|
|
700
|
-
if (lm.isDrivable(record.state, record.attempts, maxRetries)) return true;
|
|
701
|
+
if (lm.isDrivable(record.state, record.attempts, maxRetries, record.lastErrorRetryable)) return true;
|
|
701
702
|
if (this.isStalled(getIid(record), stalledThresholdMs)) return true;
|
|
702
703
|
return false;
|
|
703
704
|
});
|
|
@@ -1249,7 +1250,8 @@ ${t("basePhase.rulesSection", { rules: matchedRulesText })}` : basePrompt;
|
|
|
1249
1250
|
);
|
|
1250
1251
|
throw new AIExecutionError(this.phaseName, `Phase ${this.phaseName} failed: ${shortReason}`, {
|
|
1251
1252
|
output: result.output,
|
|
1252
|
-
exitCode: result.exitCode
|
|
1253
|
+
exitCode: result.exitCode,
|
|
1254
|
+
isRetryable: this.classifyRetryable(result)
|
|
1253
1255
|
});
|
|
1254
1256
|
}
|
|
1255
1257
|
this.persistSessionId(result.sessionId);
|
|
@@ -1341,6 +1343,22 @@ ${t("basePhase.rulesSection", { rules: matchedRulesText })}` : basePrompt;
|
|
|
1341
1343
|
}
|
|
1342
1344
|
return result;
|
|
1343
1345
|
}
|
|
1346
|
+
/**
|
|
1347
|
+
* 判断 AI 执行失败是否为永久性错误(不可重试)。
|
|
1348
|
+
* 模型不存在、API key 无效等配置问题重试不会成功。
|
|
1349
|
+
*/
|
|
1350
|
+
classifyRetryable(result) {
|
|
1351
|
+
const msg = (result.errorMessage ?? result.output ?? "").toLowerCase();
|
|
1352
|
+
const permanentPatterns = [
|
|
1353
|
+
/model\b.*\b(?:not found|not supported|unavailable|service info not found)/,
|
|
1354
|
+
/invalid.?api.?key/,
|
|
1355
|
+
/authentication.*(?:failed|denied|error)/,
|
|
1356
|
+
/permission.?denied/,
|
|
1357
|
+
/billing/,
|
|
1358
|
+
/quota.*exceeded/
|
|
1359
|
+
];
|
|
1360
|
+
return !permanentPatterns.some((p) => p.test(msg));
|
|
1361
|
+
}
|
|
1344
1362
|
/**
|
|
1345
1363
|
* Heuristic: a resume failure is typically an immediate process exit
|
|
1346
1364
|
* (exit code != 0, empty output) caused by an invalid/expired session ID.
|
|
@@ -1348,7 +1366,14 @@ ${t("basePhase.rulesSection", { rules: matchedRulesText })}` : basePrompt;
|
|
|
1348
1366
|
isResumeFailure(result) {
|
|
1349
1367
|
if (result.success) return false;
|
|
1350
1368
|
const msg = (result.errorMessage ?? "").toLowerCase();
|
|
1351
|
-
|
|
1369
|
+
if (msg.includes("session") || msg.includes("resume") || msg.includes("session_id")) {
|
|
1370
|
+
return true;
|
|
1371
|
+
}
|
|
1372
|
+
if (result.output.length === 0 && result.exitCode !== null && result.exitCode !== 0) {
|
|
1373
|
+
const isConfigError = msg.includes("model") || msg.includes("api key") || msg.includes("authentication");
|
|
1374
|
+
return !isConfigError;
|
|
1375
|
+
}
|
|
1376
|
+
return false;
|
|
1352
1377
|
}
|
|
1353
1378
|
persistSessionId(sessionId) {
|
|
1354
1379
|
if (sessionId) {
|
|
@@ -2250,7 +2275,7 @@ var ActionLifecycleManager = class {
|
|
|
2250
2275
|
* - running → 不可驱动(stalled 由外部叠加)
|
|
2251
2276
|
* - done/skipped → 不可驱动
|
|
2252
2277
|
*/
|
|
2253
|
-
isDrivable(state, attempts, maxRetries) {
|
|
2278
|
+
isDrivable(state, attempts, maxRetries, lastErrorRetryable) {
|
|
2254
2279
|
if (state === "phase_done" /* PhaseDone */) return true;
|
|
2255
2280
|
if (state === "phase_approved" /* PhaseApproved */) return true;
|
|
2256
2281
|
if (state === "phase_running" /* PhaseRunning */) return false;
|
|
@@ -2261,6 +2286,7 @@ var ActionLifecycleManager = class {
|
|
|
2261
2286
|
case "ready":
|
|
2262
2287
|
return true;
|
|
2263
2288
|
case "failed":
|
|
2289
|
+
if (lastErrorRetryable === false) return false;
|
|
2264
2290
|
return attempts < maxRetries;
|
|
2265
2291
|
case "waiting":
|
|
2266
2292
|
case "running":
|
|
@@ -2384,6 +2410,19 @@ var ActionLifecycleManager = class {
|
|
|
2384
2410
|
derivePhaseStatuses(currentState, currentPhase) {
|
|
2385
2411
|
const result = {};
|
|
2386
2412
|
let passedCurrent = false;
|
|
2413
|
+
if (currentState === "failed" /* Failed */ && currentPhase) {
|
|
2414
|
+
for (const phase of this.def.phases) {
|
|
2415
|
+
if (passedCurrent) {
|
|
2416
|
+
result[phase.name] = "pending";
|
|
2417
|
+
} else if (phase.name === currentPhase) {
|
|
2418
|
+
result[phase.name] = "failed";
|
|
2419
|
+
passedCurrent = true;
|
|
2420
|
+
} else {
|
|
2421
|
+
result[phase.name] = "completed";
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
return result;
|
|
2425
|
+
}
|
|
2387
2426
|
if ((currentState === "phase_running" /* PhaseRunning */ || currentState === "phase_done" /* PhaseDone */) && currentPhase) {
|
|
2388
2427
|
for (const phase of this.def.phases) {
|
|
2389
2428
|
if (passedCurrent) {
|
|
@@ -3990,13 +4029,14 @@ async function executeCompletion(ctx, deps, phaseResult, _wtGitMap) {
|
|
|
3990
4029
|
var logger18 = logger.child("FailureHandler");
|
|
3991
4030
|
async function handleFailure(err, issue, wtCtx, deps) {
|
|
3992
4031
|
const errorMsg = err.message;
|
|
3993
|
-
|
|
4032
|
+
const isRetryable = err instanceof AIExecutionError ? err.isRetryable : true;
|
|
4033
|
+
logger18.error("Issue processing failed", { iid: issue.iid, error: errorMsg, isRetryable });
|
|
3994
4034
|
metrics.incCounter("iaf_issues_failed_total");
|
|
3995
4035
|
const currentRecord = deps.tracker.get(issue.iid);
|
|
3996
4036
|
const failedAtState = currentRecord?.state || "pending" /* Pending */;
|
|
3997
4037
|
const wasReset = failedAtState === "pending" /* Pending */ && currentRecord?.attempts === 0;
|
|
3998
4038
|
if (failedAtState !== "failed" /* Failed */ && !wasReset) {
|
|
3999
|
-
deps.tracker.markFailed(issue.iid, errorMsg.slice(0, 500), failedAtState);
|
|
4039
|
+
deps.tracker.markFailed(issue.iid, errorMsg.slice(0, 500), failedAtState, isRetryable);
|
|
4000
4040
|
}
|
|
4001
4041
|
if (wasReset) {
|
|
4002
4042
|
logger18.info("Issue was reset during processing, skipping failure marking", { iid: issue.iid });
|
|
@@ -4347,7 +4387,7 @@ var PipelineOrchestrator = class {
|
|
|
4347
4387
|
} catch {
|
|
4348
4388
|
}
|
|
4349
4389
|
});
|
|
4350
|
-
this.tracker.
|
|
4390
|
+
this.tracker.updateState(issueIid, "skipped" /* Skipped */);
|
|
4351
4391
|
logger19.info("Issue cancelled", { issueIid });
|
|
4352
4392
|
}
|
|
4353
4393
|
retryFromPhase(issueIid, phase) {
|
|
@@ -4661,9 +4701,6 @@ E2E \u6D4B\u8BD5\u5C06\u5C1D\u8BD5\u4F7F\u7528 config.json \u4E2D\u7684\u9ED8\u8
|
|
|
4661
4701
|
async restartPreview(issueIid) {
|
|
4662
4702
|
const record = this.tracker.get(issueIid);
|
|
4663
4703
|
if (!record) throw new IssueNotFoundError(issueIid);
|
|
4664
|
-
if (record.state !== "completed" /* Completed */) {
|
|
4665
|
-
throw new InvalidStateError(record.state, "Issue not in completed state");
|
|
4666
|
-
}
|
|
4667
4704
|
const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);
|
|
4668
4705
|
if (!fsSync.existsSync(wtCtx.workDir)) {
|
|
4669
4706
|
throw new InvalidStateError(record.state, "Worktree no longer exists");
|
|
@@ -5082,4 +5119,4 @@ export {
|
|
|
5082
5119
|
PipelineOrchestrator,
|
|
5083
5120
|
BrainstormService
|
|
5084
5121
|
};
|
|
5085
|
-
//# sourceMappingURL=chunk-
|
|
5122
|
+
//# sourceMappingURL=chunk-MC7YPVJG.js.map
|