feat(web+store): needs_attention 任务显示在审核区,附失败原因
- pendingApprovals 扩展到包含 needs_attention,subquery 取最近 executor 失败 error - Task 类型增加 lastRunError 字段,mappers 映射 - 审核区(renderGates)将 needs_attention 渲染为独立橙色卡片, 展示「需人工确认」标签 + 具体失败原因 + 重新排队/取消按钮 - i18n zh/en 补充 attnLabel/attnReason/attnRequeue/attnCancel/toastRequeued Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,7 @@ export interface Task {
|
||||
assignee: 'agent' | 'human' | null;
|
||||
retryBaseline: number; // 上次手动重投时已有的失败 run 数(重置重试计数用)
|
||||
nextEligibleAt: string | null; // 持久化退避:早于此时间不被领取(重试退避,重启不丢);null=即刻可领
|
||||
lastRunError?: string | null; // needs_attention 时:最近一次失败 run 的错误信息(供审核区展示)
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export interface TaskRow {
|
||||
next_eligible_at: string | null;
|
||||
created_at: string; updated_at: string;
|
||||
source_ref: string | null;
|
||||
last_run_error?: string | null; // pendingApprovals 扩展字段(subquery)
|
||||
}
|
||||
export interface ApprovalRow {
|
||||
id: string; task_id: string; gate: string; action: string;
|
||||
@@ -75,6 +76,7 @@ export function rowToTask(r: TaskRow, approvals: ApprovalRecord[] = []): Task {
|
||||
approvals, result: r.result ? parseResult(r.result) : null,
|
||||
assignee: r.assignee as Task['assignee'], retryBaseline: r.retry_baseline ?? 0,
|
||||
nextEligibleAt: r.next_eligible_at ?? null,
|
||||
lastRunError: r.last_run_error ?? null,
|
||||
createdAt: r.created_at, updatedAt: r.updated_at,
|
||||
};
|
||||
}
|
||||
|
||||
+5
-2
@@ -825,9 +825,12 @@ export class Store {
|
||||
|
||||
/** 列出所有处于审批闸状态(plan_review/spec_review/exec_review)的任务。 */
|
||||
pendingApprovals(projectId?: string): Task[] {
|
||||
// 包含 needs_attention:让审核区展示失败任务供人工确认/重排
|
||||
// last_run_error 由子查询取最近一条 failed executor run 的 error
|
||||
const sub = `(SELECT error FROM runs WHERE task_id = t.id AND status = 'failed' AND kind = 'executor' ORDER BY ended_at DESC LIMIT 1)`;
|
||||
const sql = projectId
|
||||
? `SELECT * FROM tasks WHERE project_id = ? AND status IN ('plan_review','spec_review','exec_review') ORDER BY updated_at`
|
||||
: `SELECT * FROM tasks WHERE status IN ('plan_review','spec_review','exec_review') ORDER BY updated_at`;
|
||||
? `SELECT t.*, ${sub} AS last_run_error FROM tasks t WHERE t.project_id = ? AND t.status IN ('plan_review','spec_review','exec_review','needs_attention') ORDER BY t.updated_at`
|
||||
: `SELECT t.*, ${sub} AS last_run_error FROM tasks t WHERE t.status IN ('plan_review','spec_review','exec_review','needs_attention') ORDER BY t.updated_at`;
|
||||
const rows = (projectId
|
||||
? this.db.prepare(sql).all(projectId)
|
||||
: this.db.prepare(sql).all()) as TaskRow[];
|
||||
|
||||
Reference in New Issue
Block a user