@fitlab-ai/agent-infra 0.11.3 → 0.11.5

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.
Files changed (172) hide show
  1. package/README.md +17 -8
  2. package/README.zh-CN.md +17 -8
  3. package/dist/bin/internal-cli.js +1 -6
  4. package/dist/lib/decide.js +4 -41
  5. package/dist/lib/git/branch-worktree.js +45 -0
  6. package/dist/lib/internal/cli-route-inventory.js +1 -4
  7. package/dist/lib/internal/task-activity.js +7 -40
  8. package/dist/lib/internal/task-artifact.js +1 -1
  9. package/dist/lib/internal/task-event.js +4 -37
  10. package/dist/lib/internal/task-finalization.js +48 -1
  11. package/dist/lib/internal/task-ledger.js +14 -44
  12. package/dist/lib/internal/task-lifecycle.js +1 -1
  13. package/dist/lib/internal/task-operation-registry.js +2 -4
  14. package/dist/lib/internal/task-review.js +5 -37
  15. package/dist/lib/internal/task-verify.js +3 -47
  16. package/dist/lib/internal/task-warning.js +4 -40
  17. package/dist/lib/platform/completion-backfill.js +63 -17
  18. package/dist/lib/platform/pr-summary.js +4 -23
  19. package/dist/lib/platform/verification-sync.js +12 -49
  20. package/dist/lib/sandbox/control/client.js +4 -1
  21. package/dist/lib/sandbox/control/executor.js +12 -4
  22. package/dist/lib/sandbox/control/protocol.js +2 -1
  23. package/dist/lib/sandbox/control/server.js +26 -143
  24. package/dist/lib/sandbox/removal.js +15 -8
  25. package/dist/lib/sandbox/task-cleanup.js +13 -20
  26. package/dist/lib/task/activity-intent.js +1 -2
  27. package/dist/lib/task/artifact-command.js +11 -4
  28. package/dist/lib/task/artifact-lifecycle.js +217 -85
  29. package/dist/lib/task/artifact-operations.js +37 -28
  30. package/dist/lib/task/artifact-receipts.js +4 -1
  31. package/dist/lib/task/artifact-schema.js +8 -7
  32. package/dist/lib/task/artifact-selection.js +25 -0
  33. package/dist/lib/task/capabilities.js +158 -39
  34. package/dist/lib/task/commands/status.js +9 -2
  35. package/dist/lib/task/control-authority.js +12 -168
  36. package/dist/lib/task/decision-intents.js +14 -4
  37. package/dist/lib/task/delivery.js +1 -43
  38. package/dist/lib/task/events.js +68 -73
  39. package/dist/lib/task/finalization-handoff.js +92 -0
  40. package/dist/lib/task/finalization.js +423 -154
  41. package/dist/lib/task/intermediate-cleanup.js +9 -148
  42. package/dist/lib/task/ledger-intents.js +159 -20
  43. package/dist/lib/task/lifecycle-path.js +75 -0
  44. package/dist/lib/task/lifecycle.js +60 -11
  45. package/dist/lib/task/local-artifact-finalization.js +13 -47
  46. package/dist/lib/task/orchestration.js +17 -7
  47. package/dist/lib/task/review-command.js +1 -2
  48. package/dist/lib/task/review-finalization.js +4 -18
  49. package/dist/lib/task/rework-intent.js +70 -4
  50. package/dist/lib/task/snapshot.js +6 -6
  51. package/dist/lib/task/verification-engine.js +25 -30
  52. package/dist/lib/task/verification.js +2 -13
  53. package/dist/lib/task/workflow-warning-intents.js +23 -10
  54. package/dist/lib/task/workspace-snapshot.js +7 -2
  55. package/dist/lib/task/write.js +1 -2
  56. package/dist/lifecycle-build-manifest.json +3 -3
  57. package/lib/decide.ts +5 -35
  58. package/lib/git/branch-worktree.ts +41 -0
  59. package/lib/internal/cli-route-inventory.ts +1 -3
  60. package/lib/internal/task-activity.ts +6 -34
  61. package/lib/internal/task-artifact.ts +1 -1
  62. package/lib/internal/task-event.ts +4 -37
  63. package/lib/internal/task-finalization.ts +47 -1
  64. package/lib/internal/task-ledger.ts +15 -41
  65. package/lib/internal/task-lifecycle.ts +2 -2
  66. package/lib/internal/task-operation-registry.ts +2 -4
  67. package/lib/internal/task-review.ts +5 -31
  68. package/lib/internal/task-verify.ts +3 -39
  69. package/lib/internal/task-warning.ts +3 -32
  70. package/lib/platform/completion-backfill.ts +78 -16
  71. package/lib/platform/pr-summary.ts +4 -25
  72. package/lib/platform/verification-sync.ts +13 -53
  73. package/lib/sandbox/control/client.ts +5 -1
  74. package/lib/sandbox/control/executor.ts +13 -4
  75. package/lib/sandbox/control/protocol.ts +3 -2
  76. package/lib/sandbox/control/server.ts +21 -146
  77. package/lib/sandbox/removal.ts +23 -7
  78. package/lib/sandbox/task-cleanup.ts +12 -20
  79. package/lib/task/activity-intent.ts +1 -2
  80. package/lib/task/artifact-command.ts +14 -4
  81. package/lib/task/artifact-lifecycle.ts +236 -85
  82. package/lib/task/artifact-operations.ts +59 -28
  83. package/lib/task/artifact-receipts.ts +4 -1
  84. package/lib/task/artifact-schema.ts +10 -7
  85. package/lib/task/artifact-selection.ts +53 -0
  86. package/lib/task/capabilities.ts +154 -40
  87. package/lib/task/commands/status.ts +11 -2
  88. package/lib/task/control-authority.ts +17 -189
  89. package/lib/task/decision-intents.ts +11 -4
  90. package/lib/task/delivery.ts +1 -40
  91. package/lib/task/events.ts +73 -74
  92. package/lib/task/finalization-handoff.ts +104 -0
  93. package/lib/task/finalization.ts +388 -122
  94. package/lib/task/intermediate-cleanup.ts +9 -125
  95. package/lib/task/ledger-intents.ts +157 -20
  96. package/lib/task/lifecycle-path.ts +98 -0
  97. package/lib/task/lifecycle.ts +58 -13
  98. package/lib/task/local-artifact-finalization.ts +14 -56
  99. package/lib/task/orchestration.ts +26 -8
  100. package/lib/task/review-command.ts +2 -5
  101. package/lib/task/review-finalization.ts +4 -20
  102. package/lib/task/rework-intent.ts +75 -5
  103. package/lib/task/snapshot.ts +6 -6
  104. package/lib/task/verification-engine.ts +29 -30
  105. package/lib/task/verification.ts +3 -16
  106. package/lib/task/workflow-warning-intents.ts +20 -10
  107. package/lib/task/workspace-snapshot.ts +3 -2
  108. package/lib/task/write.ts +1 -4
  109. package/package.json +1 -1
  110. package/templates/.agents/rules/review-handshake.en.md +4 -4
  111. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
  112. package/templates/.agents/skills/analyze-task/SKILL.en.md +21 -5
  113. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +21 -5
  114. package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
  115. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
  116. package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
  117. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
  118. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
  119. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
  120. package/templates/.agents/skills/code-task/reference/report-template.en.md +7 -7
  121. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +7 -7
  122. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +2 -2
  123. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +2 -2
  124. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +1 -3
  125. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +1 -3
  126. package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
  127. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
  128. package/templates/.agents/skills/complete-task/config/verify.en.json +2 -2
  129. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
  130. package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
  131. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
  132. package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
  133. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
  134. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +3 -3
  135. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +3 -3
  136. package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
  137. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
  138. package/templates/.agents/skills/review-code/reference/report-template.en.md +3 -3
  139. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +3 -3
  140. package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
  141. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
  142. package/templates/.agents/skills/review-plan/reference/report-template.en.md +3 -3
  143. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +3 -3
  144. package/templates/.agents/skills/review-pr/config/verify.en.json +3 -1
  145. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +3 -1
  146. package/templates/.agents/skills/review-pr/reference/report-template.en.md +3 -3
  147. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +3 -3
  148. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +2 -2
  149. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +2 -2
  150. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -2
  151. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -2
  152. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
  153. package/templates/.agents/templates/task.en.md +2 -2
  154. package/templates/.agents/templates/task.zh-CN.md +2 -2
  155. package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
  156. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
  157. package/templates/.agents/workflows/feature-development.en.yaml +11 -6
  158. package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
  159. package/templates/.agents/workflows/refactoring.en.yaml +11 -6
  160. package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
  161. package/dist/lib/internal/task-override.js +0 -138
  162. package/dist/lib/sandbox/control/finalization-response.js +0 -33
  163. package/dist/lib/task/artifact-recovery.js +0 -476
  164. package/dist/lib/task/artifact-repair-intent.js +0 -181
  165. package/dist/lib/task/guard-override.js +0 -31
  166. package/dist/lib/task/human-override.js +0 -1259
  167. package/lib/internal/task-override.ts +0 -144
  168. package/lib/sandbox/control/finalization-response.ts +0 -35
  169. package/lib/task/artifact-recovery.ts +0 -572
  170. package/lib/task/artifact-repair-intent.ts +0 -227
  171. package/lib/task/guard-override.ts +0 -50
  172. package/lib/task/human-override.ts +0 -1522
@@ -11,6 +11,7 @@ import { inspectPlatformPullRequest } from "../platform/pull-requests.js";
11
11
  import { resolveMaterializedReviewedHeadRelation } from "../platform/change-request-git-evidence.js";
12
12
  import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
13
13
  import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
14
+ import { resolveBranchWorktree } from "../git/branch-worktree.js";
14
15
  import { parseTypedTaskFrontmatter } from "./frontmatter.js";
15
16
  import { LEDGER_TERMINAL, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
16
17
  import { isValidAgentInfraVersion } from "../version.js";
@@ -26,7 +27,6 @@ import { OrchestrationStateError, readRun } from "./orchestration.js";
26
27
  import { resolveDeliveryTarget } from "./delivery-target.js";
27
28
  import { readPrDeliveryFact } from "./pr-delivery-fact.js";
28
29
  import { validateLocalArtifact } from "./local-artifact-finalization.js";
29
- import { validateQualificationAudit } from "./qualification-audit.js";
30
30
  import { getArtifactSchema } from "./artifact-schema.js";
31
31
  import { inspectArtifactContract } from "./artifact-operations.js";
32
32
  import { normalizeVerificationRecord } from './gate-policy.js';
@@ -59,7 +59,6 @@ const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
59
59
  const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
60
60
  // Review disagreement ledger (see .agents/rules/review-handshake.md).
61
61
  const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
62
- const DEFAULT_MAX_HANDSHAKE_ROUNDS = 3;
63
62
  const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
64
63
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
65
64
  const scriptPath = fileURLToPath(import.meta.url);
@@ -441,21 +440,6 @@ function checkArtifact({ taskDir, config, artifactFile, skillName }) {
441
440
  return failResult("artifact", `Artifact is empty: ${path.basename(artifactPath)}`);
442
441
  }
443
442
  const content = fs.readFileSync(artifactPath, "utf8");
444
- let taskContent = "";
445
- const taskPath = path.join(taskDir, "task.md");
446
- if (fs.existsSync(taskPath)) {
447
- try {
448
- taskContent = fs.readFileSync(taskPath, "utf8");
449
- }
450
- catch (error) {
451
- return failResult("artifact", `Cannot read task qualification contract: ${error instanceof Error ? error.message : String(error)}`);
452
- }
453
- }
454
- if (taskContent && /^review-(?:analysis|plan|code)$/.test(skillName)) {
455
- const qualification = validateQualificationAudit(taskContent, content, { artifact: path.basename(artifactPath) });
456
- if (!qualification.ok)
457
- return failResult("artifact", `${path.basename(artifactPath)} has qualification audit errors: ${qualification.code}: ${qualification.message}`);
458
- }
459
443
  const schemaFamily = skillName === "analyze-task"
460
444
  ? "analysis"
461
445
  : skillName === "review-analysis"
@@ -479,9 +463,7 @@ function checkArtifact({ taskDir, config, artifactFile, skillName }) {
479
463
  }
480
464
  if (localFamily) {
481
465
  const local = validateLocalArtifact(content, {
482
- family: localFamily,
483
- ...(taskContent ? { taskContent } : {}),
484
- artifact: path.basename(artifactPath)
466
+ family: localFamily
485
467
  });
486
468
  if (!local.ok) {
487
469
  return failResult("artifact", `${path.basename(artifactPath)} has local structural errors: ${local.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`);
@@ -502,6 +484,18 @@ function checkArtifact({ taskDir, config, artifactFile, skillName }) {
502
484
  return failResult("artifact", `${path.basename(artifactPath)} is missing required pattern: ${pattern}`);
503
485
  }
504
486
  }
487
+ const stateCheckPatterns = config.state_check_patterns || [];
488
+ if (stateCheckPatterns.length > 0) {
489
+ const scanned = scanVisibleMarkdown(content);
490
+ const stateCheckHeading = scanned.headings.find((heading) => (heading.level === 2 && (heading.text === "状态核对" || heading.text === "State Check")));
491
+ const nextHeading = stateCheckHeading && scanned.headings.find((heading) => (heading.start > stateCheckHeading.start && heading.level <= 2));
492
+ const stateCheckBody = stateCheckHeading ? content.slice(stateCheckHeading.end, nextHeading?.start ?? content.length) : "";
493
+ for (const pattern of stateCheckPatterns) {
494
+ if (!new RegExp(pattern, "m").test(stateCheckBody)) {
495
+ return failResult("artifact", `${path.basename(artifactPath)} state-check section is missing required command: ${pattern}`);
496
+ }
497
+ }
498
+ }
505
499
  return passResult("artifact", `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`);
506
500
  }
507
501
  function checkDecisionDetails({ taskDir, artifactFile }) {
@@ -715,11 +709,10 @@ function checkReviewLedger({ taskDir, config, repositoryRoot }) {
715
709
  return passResult("review-ledger", "Disagreement ledger has no entries");
716
710
  }
717
711
  const stageScope = Array.isArray(config.stage_scope) ? config.stage_scope : null;
718
- const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS, repositoryRoot));
719
712
  const problems = [];
720
713
  let inScopeCount = 0;
721
714
  for (const row of rows) {
722
- const { id, stage, round: roundRaw, status, evidence } = row;
715
+ const { id, stage, status, evidence } = row;
723
716
  const stageScoped = stageScope ? stageScope.includes(stage) : true;
724
717
  // post-review-commit exemption rows are consumed by the post-review-commit
725
718
  // check, not enforced here.
@@ -738,13 +731,6 @@ function checkReviewLedger({ taskDir, config, repositoryRoot }) {
738
731
  if (status !== "open" && evidence === "") {
739
732
  problems.push(`${id}: status '${status}' requires evidence`);
740
733
  }
741
- const round = Number.parseInt(roundRaw, 10);
742
- if (Number.isFinite(round) &&
743
- round >= maxRounds &&
744
- !LEDGER_TERMINAL.has(status) &&
745
- status !== "needs-human-decision") {
746
- problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
747
- }
748
734
  if (!LEDGER_TERMINAL.has(status)) {
749
735
  problems.push(`${id}: unresolved (status '${status}')`);
750
736
  }
@@ -1051,7 +1037,8 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }) {
1051
1037
  let targetHead;
1052
1038
  let diffBase;
1053
1039
  try {
1054
- gitRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
1040
+ const taskRepositoryRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
1041
+ gitRoot = reviewWorktreeForTask(taskRepositoryRoot, String(task.metadata.branch || "").trim()) ?? taskRepositoryRoot;
1055
1042
  head = execFileSync("git", ["-C", gitRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
1056
1043
  const target = resolveDeliveryTarget(gitRoot, { remote: deliveryRemote, baseRef: deliveryBaseRef });
1057
1044
  if (!target.ok)
@@ -1101,6 +1088,14 @@ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }) {
1101
1088
  }
1102
1089
  return passResult("review-fact", `Review fact valid for ${path.basename(resolvedArtifact.path)} at ${baseline.slice(0, 8)}`);
1103
1090
  }
1091
+ function reviewWorktreeForTask(repositoryRoot, branch) {
1092
+ if (!branch)
1093
+ return null;
1094
+ const worktree = resolveBranchWorktree(repositoryRoot, branch);
1095
+ if (worktree)
1096
+ return worktree;
1097
+ throw new Error(`Task branch '${branch}' is not checked out in a registered worktree`);
1098
+ }
1104
1099
  function resolvePostReviewBaseline({ gitRoot, lastReviewedCommit, reviewArtifact }) {
1105
1100
  if (SHA_PATTERN.test(lastReviewedCommit) && gitCommitExists(gitRoot, lastReviewedCommit)) {
1106
1101
  return { ok: true, sha: lastReviewedCommit };
@@ -4,7 +4,6 @@ import path from 'node:path';
4
4
  import { verifyInProcess } from './verification-engine.js';
5
5
  import { parseArtifactName } from './artifact-name.js';
6
6
  import { resolveTaskRef } from './resolve-ref.js';
7
- import { allowsManualOverride } from './guard-override.js';
8
7
  const gate = (skill, expectedState, artifactFamily) => ({
9
8
  skill, expectedState, mode: 'gate', ...(artifactFamily ? { artifactFamily } : {})
10
9
  });
@@ -23,6 +22,7 @@ const VERIFICATION_CATALOG = {
23
22
  'commit.completed': gate('commit', 'active'),
24
23
  'complete-task.preflight': { skill: 'complete-task', expectedState: 'active', mode: 'checks', checks: ['required-pr-delivery'] },
25
24
  'complete-task.hard-preflight': { skill: 'complete-task', expectedState: 'active', mode: 'checks', checks: ['required-pr-delivery'] },
25
+ 'complete-task.prepared': gate('complete-task', 'active'),
26
26
  'complete-task.completed': gate('complete-task', 'completed'),
27
27
  'create-pr.completed': gate('create-pr', 'active'),
28
28
  'create-task.completed': gate('create-task', 'active'),
@@ -49,7 +49,7 @@ async function verifyTaskEvent(request, options = {}) {
49
49
  if (!resolved.ok)
50
50
  return failure(request, resolved.code, resolved.message, { taskId: resolved.taskId, skill: spec.skill, mode: spec.mode });
51
51
  const identity = { taskId: resolved.taskId, taskDir: resolved.taskDir, taskState: resolved.state, skill: spec.skill, mode: spec.mode };
52
- if (resolved.state !== spec.expectedState && !allowsManualOverride(options.manualOverride, 'task-verify', 'VERIFY_TASK_STATE_MISMATCH')) {
52
+ if (resolved.state !== spec.expectedState) {
53
53
  return failure(request, 'VERIFY_TASK_STATE_MISMATCH', `event '${request.event}' requires workspace '${spec.expectedState}', received '${resolved.state}'`, identity);
54
54
  }
55
55
  if (spec.artifactFamily) {
@@ -68,23 +68,12 @@ async function verifyTaskEvent(request, options = {}) {
68
68
  if (spec.mode === 'gate') {
69
69
  const payload = await engine({ mode: 'gate', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [], repositoryRoot: resolved.repoRoot });
70
70
  const status = payload.gate;
71
- if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
72
- invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, gate: 'pass', humanOverride: 'human-approved', originalGate: status } });
73
- return {
74
- status: 'pass', changed: false, event: request.event, requestRef: request.taskRef,
75
- ...identity, artifact: request.artifact ?? null, invocations, error: null
76
- };
77
- }
78
71
  invocations.push({ status, exitCode: { pass: 0, fail: 1, blocked: 2 }[status], payload });
79
72
  }
80
73
  else {
81
74
  for (const check of spec.checks ?? []) {
82
75
  const payload = await engine({ mode: 'checks', skillName: spec.skill, taskDir: resolved.taskDir, artifactFile: request.artifact, checks: [check], repositoryRoot: resolved.repoRoot });
83
76
  const status = (payload.effectiveStatus ?? payload.status);
84
- if (status !== 'pass' && allowsManualOverride(options.manualOverride, 'verification-engine', status === 'blocked' ? 'CHECK_BLOCKED' : 'CHECK_FAILED')) {
85
- invocations.push({ status: 'pass', exitCode: 0, payload: { ...payload, status: 'pass', humanOverride: 'human-approved', originalStatus: status } });
86
- break;
87
- }
88
77
  invocations.push({ status, exitCode: { pass: 0, fail: 1, blocked: 2 }[status], payload });
89
78
  if (status !== 'pass')
90
79
  break;
@@ -1,8 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import { resolveTaskRef } from './resolve-ref.js';
3
+ import { parseTaskFrontmatter } from './frontmatter.js';
3
4
  import { WORKFLOW_WARNING_COLUMNS, WORKFLOW_WARNING_HEADINGS, WORKFLOW_WARNING_SEVERITIES, WORKFLOW_WARNING_STATUSES, parseWorkflowWarnings } from './workflow-warnings.js';
4
5
  import { captureTaskWriteMetadata, writeTask } from './write.js';
5
- import { allowsManualOverride } from './guard-override.js';
6
6
  import { retryHintForWarning } from './operation-outcome.js';
7
7
  function failed(intent, code, message, taskId = null, entityId = null) {
8
8
  return { status: 'failed', changed: false, intent: intent.kind, taskId, entityId, before: null, after: null, warnings: [], operations: [], error: { code, message } };
@@ -43,8 +43,7 @@ function applyWorkflowWarningIntent(intent, options = {}) {
43
43
  const resolved = resolveTaskRef(intent.taskRef, { repoRoot: options.repoRoot });
44
44
  if (!resolved.ok)
45
45
  return failed(intent, resolved.code, resolved.message, resolved.taskId);
46
- const stateOverride = allowsManualOverride(options.manualOverride, 'workflow-warning', 'TASK_STATE_MISMATCH');
47
- if (resolved.state !== 'active' && !stateOverride)
46
+ if (resolved.state !== 'active')
48
47
  return failed(intent, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
49
48
  let content;
50
49
  let rows;
@@ -101,7 +100,7 @@ function applyWorkflowWarningIntent(intent, options = {}) {
101
100
  after = { ...before, status: intent.status, resolvedAt: metadata.timestamp, resolution };
102
101
  }
103
102
  const writeResult = writeTask({
104
- taskRef: intent.taskRef, expectedState: stateOverride ? resolved.state : 'active', mutations: [...sectionMutation(content), rowMutation(after)], dryRun: intent.dryRun
103
+ taskRef: intent.taskRef, expectedState: 'active', mutations: [...sectionMutation(content), rowMutation(after)], dryRun: intent.dryRun
105
104
  }, {
106
105
  ...options,
107
106
  taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state },
@@ -118,8 +117,18 @@ function projectFinalizationWarning(taskRef, warning, options = {}) {
118
117
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
119
118
  if (!resolved.ok)
120
119
  return { status: 'failed', changed: false, error: { code: resolved.code, message: resolved.message } };
121
- if (resolved.state !== 'completed')
122
- return { status: 'failed', changed: false, error: { code: 'TASK_STATE_MISMATCH', message: `task ${resolved.taskId} is ${resolved.state}, expected completed` } };
120
+ let prepared = resolved.state === 'completed';
121
+ if (!prepared && resolved.state === 'active') {
122
+ try {
123
+ prepared = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8')).status === 'completed';
124
+ }
125
+ catch {
126
+ prepared = false;
127
+ }
128
+ }
129
+ if (!prepared) {
130
+ return { status: 'failed', changed: false, error: { code: 'TASK_STATE_MISMATCH', message: `task ${resolved.taskId} is ${resolved.state}, expected a prepared or completed task` } };
131
+ }
123
132
  let content;
124
133
  let rows;
125
134
  try {
@@ -139,23 +148,27 @@ function projectFinalizationWarning(taskRef, warning, options = {}) {
139
148
  message: warning.message,
140
149
  action: retryHintForWarning(warning),
141
150
  resolvedAt: warning.resolvedAt || (warning.status === 'resolved' ? metadata.timestamp : ''),
142
- resolution: warning.status === 'resolved' ? 'Resolved by a successful finalization retry' : ''
151
+ resolution: warning.status === 'resolved'
152
+ ? options.resolution === 'superseded' ? 'Superseded by a later verification observation' : 'Resolved by a successful finalization retry'
153
+ : ''
143
154
  }
144
155
  : {
145
156
  id: nextWarningId(rows), time: metadata.timestamp, step: warning.step,
146
157
  severity: warning.severity, code: warning.code, status: warning.status,
147
158
  target: warning.target, message: warning.message, action: retryHintForWarning(warning),
148
- resolvedAt: warning.resolvedAt || '', resolution: warning.status === 'resolved' ? 'Resolved by a successful finalization retry' : ''
159
+ resolvedAt: warning.resolvedAt || '', resolution: warning.status === 'resolved'
160
+ ? options.resolution === 'superseded' ? 'Superseded by a later verification observation' : 'Resolved by a successful finalization retry'
161
+ : ''
149
162
  };
150
163
  if (existing && JSON.stringify(existing) === JSON.stringify(after))
151
164
  return { status: 'no-op', changed: false, error: null };
152
165
  const written = writeTask({
153
166
  taskRef: resolved.taskId,
154
- expectedState: 'completed',
167
+ expectedState: resolved.state,
155
168
  mutations: [...sectionMutation(content), rowMutation(after)]
156
169
  }, {
157
170
  ...options,
158
- taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: 'completed' },
171
+ taskLocation: { repoRoot: resolved.repoRoot, taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, state: resolved.state },
159
172
  metadataProvider: () => metadata
160
173
  });
161
174
  if (written.status === 'failed')
@@ -15,7 +15,12 @@ function captureWorktreeTree(repoRoot, forcedPath) {
15
15
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-infra-orchestration-index-'));
16
16
  const indexFile = path.join(tempDir, 'index');
17
17
  try {
18
- git(repoRoot, indexFile, ['read-tree', 'HEAD']);
18
+ try {
19
+ git(repoRoot, indexFile, ['read-tree', 'HEAD']);
20
+ }
21
+ catch {
22
+ git(repoRoot, indexFile, ['read-tree', '--empty']);
23
+ }
19
24
  git(repoRoot, indexFile, ['add', '-A', '--', ':/']);
20
25
  if (forcedPath && fs.existsSync(path.join(repoRoot, forcedPath))) {
21
26
  git(repoRoot, indexFile, ['add', '-f', '--', forcedPath]);
@@ -111,5 +116,5 @@ function diffWorkspaceSnapshots(repoRoot, before, after) {
111
116
  }
112
117
  return [...changed].sort();
113
118
  }
114
- export { captureRepositorySnapshot, captureWorkspaceSnapshot, diffWorkspaceSnapshots };
119
+ export { captureRepositorySnapshot, captureWorkspaceSnapshot, captureWorktreeTree, diffWorkspaceSnapshots };
115
120
  //# sourceMappingURL=workspace-snapshot.js.map
@@ -3,7 +3,6 @@ import path from 'node:path';
3
3
  import { isValidAgentInfraVersion, VERSION } from '../version.js';
4
4
  import { parseTypedTaskFrontmatter, updateTaskFrontmatter } from './frontmatter.js';
5
5
  import { resolveTaskRef } from './resolve-ref.js';
6
- import { allowsManualOverride } from './guard-override.js';
7
6
  import { mutateTableRow, upsertSection } from './sections.js';
8
7
  import { validateCurrentTaskContract } from './current-contract.js';
9
8
  import { invalidationBlocks, parseInvalidationDocument } from './invalidation.js';
@@ -73,7 +72,7 @@ function writeTask(request, options = {}) {
73
72
  taskMdPath: resolved.taskMdPath,
74
73
  actualState: resolved.state
75
74
  };
76
- if (resolved.state !== request.expectedState && !allowsManualOverride(options.manualOverride, 'task.write', 'TASK_STATE_MISMATCH')) {
75
+ if (resolved.state !== request.expectedState) {
77
76
  return failure(request, identity, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected ${request.expectedState}`);
78
77
  }
79
78
  const io = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "protocolVersion": 3,
3
- "packageVersion": "0.11.3",
4
- "sourceInputHash": "99efbc575d475879773bf1676cc2de5ea628b9c193f69a9812a723313ba5ae7f",
5
- "internalExecutableBuildHash": "6912a66863d013c476699b88cc1d4154082971164cbae3f98ea79dda39a46e7a"
3
+ "packageVersion": "0.11.5",
4
+ "sourceInputHash": "2f29b7f1f134733c3bc1bb7c92ea6c11e57462ed51a5a96b0198b8824a3f455d",
5
+ "internalExecutableBuildHash": "cb9d00aa3fa974cf936a8aad310e1fa5f28842351f52a53fed43345fe9c46439"
6
6
  }
package/lib/decide.ts CHANGED
@@ -2,7 +2,6 @@ import { VERSION } from './version.ts';
2
2
  import { parseTaskScope } from './task/command-options.ts';
3
3
  import { applyHumanDecision } from './task/decision-intents.ts';
4
4
  import { canonicalTimestamp } from './task/write.ts';
5
- import { consumeHumanOverride, failureId } from './task/human-override.ts';
6
5
  import { resolveTaskContext } from './task/resolve-ref.ts';
7
6
  import { TaskExecutionLockError, withTaskExecutionLock } from './task/task-execution-lock.ts';
8
7
 
@@ -12,12 +11,9 @@ type DecideOptions = {
12
11
  version?: string;
13
12
  };
14
13
 
15
- function parseDecisionParts(parts: string[]): { decision: string; needsImplementation: boolean | undefined; overrideTicket?: string; overrideTarget?: string; overrideScope?: string } {
14
+ function parseDecisionParts(parts: string[]): { decision: string; needsImplementation: boolean | undefined } {
16
15
  const decision: string[] = [];
17
16
  let needsImplementation: boolean | undefined;
18
- let overrideTicket: string | undefined;
19
- let overrideTarget: string | undefined;
20
- let overrideScope: string | undefined;
21
17
  for (let index = 0; index < parts.length; index += 1) {
22
18
  const part = parts[index];
23
19
  if (part === '--needs-implementation') {
@@ -27,18 +23,14 @@ function parseDecisionParts(parts: string[]): { decision: string; needsImplement
27
23
  throw new Error("--needs-implementation must be 'true' or 'false'");
28
24
  }
29
25
  needsImplementation = value === 'true';
30
- } else if (part === '--override-ticket' || part === '--override-target' || part === '--override-scope') {
31
- const value = parts[++index];
32
- if (!value) throw new Error(`${part} requires a value`);
33
- if (part === '--override-ticket') overrideTicket = value;
34
- else if (part === '--override-target') overrideTarget = value;
35
- else overrideScope = value;
26
+ } else if (part?.startsWith('--')) {
27
+ throw new Error(`unknown option '${part}'`);
36
28
  } else {
37
29
  decision.push(parts[index]!);
38
30
  }
39
31
  }
40
32
  if (decision.length === 0) throw new Error('decision content is required');
41
- return { decision: decision.join(' '), needsImplementation, overrideTicket, overrideTarget, overrideScope };
33
+ return { decision: decision.join(' '), needsImplementation };
42
34
  }
43
35
 
44
36
  export async function decide(args: string[], options: DecideOptions = {}): Promise<number> {
@@ -79,29 +71,7 @@ export async function decide(args: string[], options: DecideOptions = {}): Promi
79
71
  metadataProvider: () => ({ timestamp: now, agentInfraVersion: options.version ?? VERSION })
80
72
  };
81
73
  let result;
82
- const execute = async () => {
83
- let current = applyHumanDecision(request, writeOptions);
84
- if (current.status !== 'failed' || !parsedDecision.overrideTicket) return current;
85
- if (!parsedDecision.overrideTarget || !parsedDecision.overrideScope) throw new Error('override ticket requires --override-target and --override-scope');
86
- const consumed = await consumeHumanOverride({
87
- taskRef: resolved.taskId,
88
- ticketId: parsedDecision.overrideTicket,
89
- failureId: failureId('decision-intent', current.error?.code ?? 'TASK_STATE_MISMATCH'),
90
- target: parsedDecision.overrideTarget,
91
- scope: parsedDecision.overrideScope
92
- }, {
93
- ...writeOptions,
94
- effectExecutor: (capability) => {
95
- const retried = applyHumanDecision(request, { ...writeOptions, manualOverride: capability });
96
- current = retried;
97
- return retried.status === 'failed' || retried.status === 'planned'
98
- ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no decision effect was committed' : `${retried.error?.code ?? 'DECISION_FAILED'}: ${retried.error?.message ?? 'manual decision effect failed'}` }
99
- : null;
100
- }
101
- });
102
- if (consumed.status === 'failed') throw new Error(consumed.error.message);
103
- return current;
104
- };
74
+ const execute = async () => applyHumanDecision(request, writeOptions);
105
75
  result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-decision', execute);
106
76
  if (result.error) throw new Error(result.error.message);
107
77
  return 0;
@@ -0,0 +1,41 @@
1
+ import { execFileSync } from 'node:child_process';
2
+
3
+ function gitText(repositoryRoot: string, args: string[]): string | null {
4
+ try {
5
+ return execFileSync('git', ['-C', repositoryRoot, ...args], {
6
+ encoding: 'utf8',
7
+ stdio: ['ignore', 'pipe', 'pipe']
8
+ }).trim();
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+
14
+ function verifiedWorktreeRoot(candidate: string, expectedBranch: string, expectedCommonDirectory: string): string | null {
15
+ const commonDirectory = gitText(candidate, ['rev-parse', '--path-format=absolute', '--git-common-dir']);
16
+ if (commonDirectory !== expectedCommonDirectory) return null;
17
+ const root = gitText(candidate, ['rev-parse', '--show-toplevel']);
18
+ if (!root) return null;
19
+ const branch = gitText(root, ['symbolic-ref', '--short', 'HEAD']);
20
+ return branch === expectedBranch ? root : null;
21
+ }
22
+
23
+ export function resolveBranchWorktree(repositoryRoot: string, expectedBranch: string): string | null {
24
+ const commonDirectory = gitText(repositoryRoot, ['rev-parse', '--path-format=absolute', '--git-common-dir']);
25
+ if (!commonDirectory) return null;
26
+ const currentRoot = verifiedWorktreeRoot(repositoryRoot, expectedBranch, commonDirectory);
27
+ if (currentRoot) return currentRoot;
28
+
29
+ const records = gitText(repositoryRoot, ['worktree', 'list', '--porcelain']);
30
+ if (!records) return null;
31
+ const expectedRef = `refs/heads/${expectedBranch}`;
32
+ for (const record of records.split(/\r?\n\r?\n/)) {
33
+ const candidate = /^worktree (.+)$/m.exec(record)?.[1];
34
+ const branch = /^branch (.+)$/m.exec(record)?.[1];
35
+ if (candidate && branch === expectedRef) {
36
+ const verifiedRoot = verifiedWorktreeRoot(candidate, expectedBranch, commonDirectory);
37
+ if (verifiedRoot) return verifiedRoot;
38
+ }
39
+ }
40
+ return null;
41
+ }
@@ -53,7 +53,7 @@ export const INTERNAL_HANDLER_ROUTE_SELECTORS = Object.freeze({
53
53
  'pr-review-grade': ['decide', 'resolve-host', 'verify-artifact'],
54
54
  'platform-checks': ['inspect', 'watch', 'resolve-run', 'logs'],
55
55
  'task-context': ['resolve'],
56
- 'task-ledger': ['decision-next-id', 'stage-status', 'finding-upsert', 'finding-respond', 'finding-review', 'decision-upsert', 'rework-intent-upsert'],
56
+ 'task-ledger': ['decision-next-id', 'stage-status', 'finding-upsert', 'finding-respond', 'finding-review', 'decision-upsert', 'rework-intent-upsert', 'rework-intent-rebuild'],
57
57
  'task-warning': ['list', 'add', 'set-status'],
58
58
  'task-activity': ['pr-review-inspect', 'pr-review-start', 'pr-review-complete', 'pr-review-terminate'],
59
59
  'task-artifact': ['inspect', 'init', 'preflight', 'finalize-local'],
@@ -61,7 +61,6 @@ export const INTERNAL_HANDLER_ROUTE_SELECTORS = Object.freeze({
61
61
  'task-review': ['preflight', 'finalize-summary'],
62
62
  'task-event': ['event'],
63
63
  'task-invalidation': ['reconcile'],
64
- 'task-override': ['diagnose', 'issue', 'consume'],
65
64
  'task-lifecycle': ['intent'],
66
65
  'task-finalization': ['complete'],
67
66
  'task-short-id': ['list', 'list-verify', 'alloc', 'release', 'resolve'],
@@ -98,7 +97,6 @@ export function internalRouteSelector(command: string, args: readonly string[]):
98
97
  if (command === 'task-orchestration') return args[1] === 'status' ? 'status' : args[1] ? 'progress' : '';
99
98
  if (command === 'task-review') return args[1] ?? '';
100
99
  if (command === 'task-invalidation') return args[1] ?? '';
101
- if (command === 'task-override') return args[1] ?? '';
102
100
  if (command === 'task-artifact') return args[1] ?? '';
103
101
  if (command === 'platform-pr-review' && first(args) === 'publish') {
104
102
  const scope = optionValue(args, '--scope') ?? '';
@@ -6,7 +6,6 @@ import type {
6
6
  PrReviewActivityIntent,
7
7
  PrReviewInspectIntent
8
8
  } from '../task/activity-intent.ts';
9
- import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.ts';
10
9
  import { resolveTaskRef } from '../task/resolve-ref.ts';
11
10
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
12
11
  import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
@@ -28,14 +27,13 @@ const FLAGS: Record<string, string> = {
28
27
  '--minor': 'minor',
29
28
  '--outcome': 'outcome',
30
29
  '--reason': 'reason'
31
- , '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
32
30
  };
33
31
  const COMMON = ['agent', 'artifact', 'head'] as const;
34
32
  const ALLOWED: Record<string, ReadonlySet<string>> = {
35
33
  'pr-review-inspect': new Set(['kind', 'taskRef']),
36
- 'pr-review-start': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'dryRun', 'overrideTicket', 'overrideTarget', 'overrideScope']),
37
- 'pr-review-complete': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'verdict', 'blockers', 'major', 'minor', 'dryRun', 'overrideTicket', 'overrideTarget', 'overrideScope']),
38
- 'pr-review-terminate': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'outcome', 'reason', 'dryRun', 'overrideTicket', 'overrideTarget', 'overrideScope'])
34
+ 'pr-review-start': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'dryRun']),
35
+ 'pr-review-complete': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'verdict', 'blockers', 'major', 'minor', 'dryRun']),
36
+ 'pr-review-terminate': new Set(['kind', 'taskRef', 'agent', 'artifact', 'head', 'outcome', 'reason', 'dryRun'])
39
37
  };
40
38
 
41
39
  function usageFailure(message: string): void {
@@ -95,45 +93,19 @@ async function taskActivity(args: string[] = []): Promise<void> {
95
93
  for (const key of operationRequired) {
96
94
  if (values[key] === undefined) { usageFailure(`${kind} requires '${key}'`); return; }
97
95
  }
98
- const dryRunConflict = overrideDryRunConflict(values);
99
- if (dryRunConflict) { usageFailure(dryRunConflict.message); return; }
100
96
  const resolved = resolveTaskRef(taskRef);
101
97
  if (!resolved.ok) { usageFailure(resolved.message); return; }
102
98
  let result;
103
- let humanOverride: unknown = null;
104
99
  try {
105
- result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-activity.${kind}`, async () => {
106
- let current = applyPrReviewActivityIntent(values as PrReviewActivityIntent, { lockAlreadyHeld: true });
107
- if (current.status !== 'failed' || !values.overrideTicket) return current;
108
- if (!values.overrideTarget || !values.overrideScope) { usageFailure('override ticket requires target and scope'); return current; }
109
- const consumed = await consumeHumanOverride({
110
- taskRef, ticketId: String(values.overrideTicket),
111
- failureId: failureId('activity-intent', current.error?.code ?? 'TASK_STATE_MISMATCH'),
112
- target: String(values.overrideTarget), scope: String(values.overrideScope)
113
- }, {
114
- effectExecutor: (capability) => {
115
- const retried = applyPrReviewActivityIntent(values as PrReviewActivityIntent, { lockAlreadyHeld: true, manualOverride: capability });
116
- current = retried;
117
- return retried.status === 'failed' || retried.status === 'planned'
118
- ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no activity effect was committed' : `${retried.error?.code ?? 'ACTIVITY_FAILED'}: ${retried.error?.message ?? 'manual activity effect failed'}` }
119
- : null;
120
- }
121
- });
122
- humanOverride = consumed;
123
- return current;
124
- });
100
+ result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-activity.${kind}`, async () => applyPrReviewActivityIntent(values as PrReviewActivityIntent, { lockAlreadyHeld: true }));
125
101
  } catch (error) {
126
102
  if (!(error instanceof TaskExecutionLockError)) throw error;
127
103
  process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: error.code, message: error.message } })}\n`);
128
104
  process.exitCode = 1;
129
105
  return;
130
106
  }
131
- process.stdout.write(`${JSON.stringify(humanOverride ? { ...result, humanOverride } : result)}\n`);
132
- const overrideFailed = Boolean(
133
- humanOverride && typeof humanOverride === 'object' &&
134
- (humanOverride as { status?: unknown }).status === 'failed'
135
- );
136
- if (result.status === 'failed' || overrideFailed) process.exitCode = 1;
107
+ process.stdout.write(`${JSON.stringify(result)}\n`);
108
+ if (result.status === 'failed') process.exitCode = 1;
137
109
  }
138
110
 
139
111
  export { taskActivity };
@@ -1,7 +1,7 @@
1
1
  import { parseArtifactCommand, executeArtifactCommand } from '../task/artifact-command.ts';
2
2
  import { ensureInternalHandlerRoute } from './cli-route-inventory.ts';
3
3
 
4
- const USAGE = `Usage: agent-infra-internal task-artifact <N | TASK-id> inspect --family <family>\n agent-infra-internal task-artifact <N | TASK-id> init --family <family> --artifact <artifact> [--locale <zh-CN|en>]\n agent-infra-internal task-artifact <N | TASK-id> preflight|finalize-local --family <analysis|plan|code> --artifact <artifact>\n\nInspect, initialize, preflight, or finalize a workflow artifact without changing task state.\n`;
4
+ const USAGE = `Usage: agent-infra-internal task-artifact <N | TASK-id> inspect --family <family> [--source-finding <id> --source-artifact <name> --source-sha256 <digest>]\n agent-infra-internal task-artifact <N | TASK-id> init --family <family> --artifact <artifact> [--locale <zh-CN|en>]\n agent-infra-internal task-artifact <N | TASK-id> preflight|finalize-local --family <analysis|plan|code> --artifact <artifact>\n\nInspect, initialize, preflight, or finalize workflow artifact facts.\n`;
5
5
 
6
6
 
7
7
  function taskArtifact(args: string[] = []): void {
@@ -1,7 +1,6 @@
1
1
  import { normalizeAgentToken, AGENT_USAGE_HINT } from '../agent-clients/tokens.ts';
2
2
  import { applyTaskEvent, eventCatalog } from '../task/events.ts';
3
3
  import type { TaskEventRequest, Verdict } from '../task/events.ts';
4
- import { consumeHumanOverride, failureId, overrideDryRunConflict } from '../task/human-override.ts';
5
4
  import { resolveTaskRef } from '../task/resolve-ref.ts';
6
5
  import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.ts';
7
6
  import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.ts';
@@ -21,8 +20,7 @@ const FLAGS: Record<string, keyof TaskEventRequest> = {
21
20
  '--verdict': 'verdict', '--blockers': 'blockers', '--major': 'major',
22
21
  '--minor': 'minor', '--manual-validation': 'manualValidation', '--files-modified': 'filesModified',
23
22
  '--tests-passed': 'testsPassed', '--summary-result': 'summaryResult',
24
- '--transaction-id': 'transactionId', '--receipt-digest': 'receiptDigest', '--pr-head-sha': 'prHeadSha',
25
- '--override-ticket': 'overrideTicket', '--override-target': 'overrideTarget', '--override-scope': 'overrideScope'
23
+ '--transaction-id': 'transactionId', '--receipt-digest': 'receiptDigest', '--pr-head-sha': 'prHeadSha'
26
24
  };
27
25
  const NUMERIC = new Set(['round', 'question', 'blockers', 'major', 'minor', 'manualValidation', 'filesModified', 'testsPassed']);
28
26
 
@@ -59,8 +57,6 @@ export function parseTaskEventRequest(args: readonly string[]): TaskEventRequest
59
57
  const agent = normalizeAgentToken(String(request.agent ?? ''));
60
58
  if (!agent) throw new Error(`invalid --agent '${request.agent}': ${AGENT_USAGE_HINT}`);
61
59
  request.agent = agent;
62
- const dryRunConflict = overrideDryRunConflict(request as unknown as Record<string, unknown>);
63
- if (dryRunConflict) throw new Error(dryRunConflict.message);
64
60
  return request;
65
61
  }
66
62
 
@@ -78,45 +74,16 @@ async function taskEvent(args: string[] = []): Promise<void> {
78
74
  return;
79
75
  }
80
76
  let result;
81
- let humanOverride: unknown = null;
82
77
  try {
83
- result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-event.${request.event}`, async () => {
84
- let current = applyTaskEvent(request, { lockAlreadyHeld: true });
85
- const values = request as Record<string, unknown>;
86
- if (current.status !== 'failed' || !values.overrideTicket) return current;
87
- if (!values.overrideTarget || !values.overrideScope) {
88
- return { ...current, humanOverride: { status: 'failed', error: { code: 'OVERRIDE_PAYLOAD_INVALID', message: 'override ticket requires target and scope' } } } as typeof current & { humanOverride: unknown };
89
- }
90
- const consumed = await consumeHumanOverride({
91
- taskRef: request.taskRef,
92
- ticketId: String(values.overrideTicket),
93
- failureId: failureId('task-event', current.error?.code ?? 'EVENT_TRANSITION_INVALID'),
94
- target: String(values.overrideTarget),
95
- scope: String(values.overrideScope)
96
- }, {
97
- effectExecutor: (capability) => {
98
- const retried = applyTaskEvent(request, { lockAlreadyHeld: true, manualOverride: capability });
99
- current = retried;
100
- return retried.status === 'failed' || retried.status === 'planned'
101
- ? { code: 'OVERRIDE_EFFECT_FAILED', message: retried.status === 'planned' ? 'producer returned planned; no task event was committed' : `${retried.error?.code ?? 'EVENT_FAILED'}: ${retried.error?.message ?? 'manual task event effect failed'}` }
102
- : null;
103
- }
104
- });
105
- humanOverride = consumed;
106
- return current;
107
- });
78
+ result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `task-event.${request.event}`, async () => applyTaskEvent(request, { lockAlreadyHeld: true }));
108
79
  } catch (error) {
109
80
  if (!(error instanceof TaskExecutionLockError)) throw error;
110
81
  process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: error.code, message: error.message } })}\n`);
111
82
  process.exitCode = 1;
112
83
  return;
113
84
  }
114
- process.stdout.write(`${JSON.stringify(humanOverride ? { ...result, humanOverride } : result)}\n`);
115
- const overrideFailed = Boolean(
116
- humanOverride && typeof humanOverride === 'object' &&
117
- (humanOverride as { status?: unknown }).status === 'failed'
118
- );
119
- if (result.status === 'failed' || overrideFailed) process.exitCode = 1;
85
+ process.stdout.write(`${JSON.stringify(result)}\n`);
86
+ if (result.status === 'failed') process.exitCode = 1;
120
87
  }
121
88
 
122
89
  export { taskEvent };