@fitlab-ai/agent-infra 0.12.0 → 0.12.2

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 (331) hide show
  1. package/README.md +0 -2
  2. package/README.zh-CN.md +0 -2
  3. package/dist/bin/internal-cli.js +2 -17
  4. package/dist/lib/agent-clients/adapter.js +0 -13
  5. package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
  6. package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
  7. package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
  8. package/dist/lib/agent-clients/adapters/codex.js +0 -52
  9. package/dist/lib/agent-clients/adapters/opencode.js +0 -5
  10. package/dist/lib/agent-clients/adapters/traecli.js +0 -5
  11. package/dist/lib/agent-clients/config.js +19 -54
  12. package/dist/lib/agent-clients/registry.js +1 -12
  13. package/dist/lib/agent-clients/schema.js +0 -18
  14. package/dist/lib/agent-clients/tokens.js +1 -2
  15. package/dist/lib/agent-clients/types.js +0 -1
  16. package/dist/lib/decide.js +2 -0
  17. package/dist/lib/git/worktree-identity.js +1 -9
  18. package/dist/lib/internal/agent-client.js +2 -62
  19. package/dist/lib/internal/cli-route-inventory.js +1 -5
  20. package/dist/lib/internal/manual-validation.js +29 -27
  21. package/dist/lib/internal/platform-comment.js +56 -7
  22. package/dist/lib/internal/task-create.js +1 -1
  23. package/dist/lib/internal/task-event.js +1 -8
  24. package/dist/lib/internal/task-finalization.js +0 -1
  25. package/dist/lib/internal/task-lifecycle.js +2 -2
  26. package/dist/lib/internal/task-operation-registry.js +4 -20
  27. package/dist/lib/internal/task-review.js +4 -4
  28. package/dist/lib/platform/comment-safety.js +1 -7
  29. package/dist/lib/platform/in-label-sync.js +1 -14
  30. package/dist/lib/platform/issue-comments.js +373 -282
  31. package/dist/lib/platform/issue-summary-content.js +112 -0
  32. package/dist/lib/platform/issues.js +1 -1
  33. package/dist/lib/platform/operation-coordinator.js +4 -2
  34. package/dist/lib/platform/pr-change-report.js +176 -30
  35. package/dist/lib/platform/pr-checks.js +2 -8
  36. package/dist/lib/platform/pr-summary-content.js +54 -0
  37. package/dist/lib/platform/pr-summary.js +318 -284
  38. package/dist/lib/platform/provider-validation.js +0 -20
  39. package/dist/lib/platform/pull-requests.js +73 -84
  40. package/dist/lib/platform/releases.js +1 -43
  41. package/dist/lib/platform/summary-content-pipeline.js +18 -0
  42. package/dist/lib/platform/verification-required.js +0 -2
  43. package/dist/lib/platform/verification-sync.js +1 -79
  44. package/dist/lib/process-data/normalize.js +1 -185
  45. package/dist/lib/process-data/privacy.js +1 -16
  46. package/dist/lib/process-data/sources.js +2 -279
  47. package/dist/lib/render.js +0 -12
  48. package/dist/lib/run/index.js +15 -10
  49. package/dist/lib/run/skills.js +0 -3
  50. package/dist/lib/sandbox/commands/create.js +40 -53
  51. package/dist/lib/sandbox/commands/list-running.js +0 -18
  52. package/dist/lib/sandbox/commands/start.js +7 -8
  53. package/dist/lib/sandbox/constants.js +0 -6
  54. package/dist/lib/sandbox/control/client.js +0 -1
  55. package/dist/lib/sandbox/control/container-identity.js +1 -16
  56. package/dist/lib/sandbox/control/executor.js +0 -4
  57. package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
  58. package/dist/lib/sandbox/control/lifecycle.js +21 -37
  59. package/dist/lib/sandbox/control/native-file-lock.js +0 -3
  60. package/dist/lib/sandbox/control/server.js +18 -38
  61. package/dist/lib/sandbox/control/state.js +1 -9
  62. package/dist/lib/sandbox/dockerfile.js +0 -6
  63. package/dist/lib/sandbox/engine.js +0 -14
  64. package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
  65. package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
  66. package/dist/lib/sandbox/recovery.js +24 -26
  67. package/dist/lib/sandbox/removal.js +67 -518
  68. package/dist/lib/sandbox/task-resolver.js +0 -41
  69. package/dist/lib/sandbox/tools.js +1 -4
  70. package/dist/lib/sandbox/workspace-view.js +1 -2
  71. package/dist/lib/server/display.js +0 -6
  72. package/dist/lib/task/activity-intent.js +45 -40
  73. package/dist/lib/task/activity-log.js +9 -16
  74. package/dist/lib/task/artifact-command.js +1 -1
  75. package/dist/lib/task/artifact-lifecycle.js +61 -63
  76. package/dist/lib/task/artifact-name.js +0 -6
  77. package/dist/lib/task/artifact-operations.js +3 -3
  78. package/dist/lib/task/capabilities.js +4 -5
  79. package/dist/lib/task/commands/log.js +0 -6
  80. package/dist/lib/task/commands/status.js +17 -60
  81. package/dist/lib/task/commit-operation.js +28 -39
  82. package/dist/lib/task/completion-facts.js +56 -43
  83. package/dist/lib/task/control-authority.js +23 -256
  84. package/dist/lib/task/control-recovery.js +3 -5
  85. package/dist/lib/task/create.js +2 -4
  86. package/dist/lib/task/decision-intents.js +8 -9
  87. package/dist/lib/task/delivery-target.js +1 -40
  88. package/dist/lib/task/events.js +84 -107
  89. package/dist/lib/task/finalization.js +60 -15
  90. package/dist/lib/task/ledger-intents.js +1 -1
  91. package/dist/lib/task/lifecycle-execution.js +38 -33
  92. package/dist/lib/task/lifecycle.js +49 -41
  93. package/dist/lib/task/local-artifact-finalization.js +1 -4
  94. package/dist/lib/task/manual-validation-evidence.js +1 -37
  95. package/dist/lib/task/platform-operation-recovery.js +151 -108
  96. package/dist/lib/task/pr-delivery-fact.js +2 -5
  97. package/dist/lib/task/qualification-confirmation.js +5 -7
  98. package/dist/lib/task/resolve-ref.js +1 -25
  99. package/dist/lib/task/review-command.js +2 -2
  100. package/dist/lib/task/review-finalization.js +1 -21
  101. package/dist/lib/task/review-fingerprint.js +0 -4
  102. package/dist/lib/task/secure-fs.js +0 -56
  103. package/dist/lib/task/short-id.js +1 -39
  104. package/dist/lib/task/skill-scope.js +0 -1
  105. package/dist/lib/task/verification-engine.js +58 -282
  106. package/dist/lib/task/verification.js +6 -3
  107. package/dist/lib/task/write.js +11 -1
  108. package/lib/agent-clients/adapter.ts +0 -76
  109. package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
  110. package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
  111. package/lib/agent-clients/adapters/claude-code.ts +0 -9
  112. package/lib/agent-clients/adapters/codex.ts +0 -56
  113. package/lib/agent-clients/adapters/opencode.ts +0 -5
  114. package/lib/agent-clients/adapters/traecli.ts +0 -5
  115. package/lib/agent-clients/config.ts +20 -61
  116. package/lib/agent-clients/registry.ts +1 -34
  117. package/lib/agent-clients/schema.ts +0 -18
  118. package/lib/agent-clients/tokens.ts +1 -2
  119. package/lib/agent-clients/types.ts +0 -15
  120. package/lib/decide.ts +1 -0
  121. package/lib/git/worktree-identity.ts +0 -10
  122. package/lib/internal/agent-client.ts +2 -70
  123. package/lib/internal/cli-route-inventory.ts +1 -4
  124. package/lib/internal/manual-validation.ts +28 -27
  125. package/lib/internal/platform-comment.ts +46 -4
  126. package/lib/internal/task-create.ts +0 -1
  127. package/lib/internal/task-event.ts +1 -5
  128. package/lib/internal/task-finalization.ts +0 -1
  129. package/lib/internal/task-lifecycle.ts +3 -5
  130. package/lib/internal/task-operation-registry.ts +3 -19
  131. package/lib/internal/task-review.ts +4 -4
  132. package/lib/platform/comment-safety.ts +0 -10
  133. package/lib/platform/github-provider.ts +0 -2
  134. package/lib/platform/in-label-sync.ts +0 -16
  135. package/lib/platform/issue-comments.ts +478 -301
  136. package/lib/platform/issue-summary-content.ts +132 -0
  137. package/lib/platform/issues.ts +0 -2
  138. package/lib/platform/operation-coordinator.ts +4 -2
  139. package/lib/platform/pr-change-report.ts +165 -25
  140. package/lib/platform/pr-checks.ts +1 -10
  141. package/lib/platform/pr-review.ts +1 -1
  142. package/lib/platform/pr-summary-content.ts +60 -0
  143. package/lib/platform/pr-summary.ts +364 -257
  144. package/lib/platform/provider-bridge.ts +0 -1
  145. package/lib/platform/provider-loader.ts +1 -5
  146. package/lib/platform/provider-validation.ts +1 -49
  147. package/lib/platform/pull-requests.ts +64 -99
  148. package/lib/platform/releases.ts +1 -40
  149. package/lib/platform/summary-content-pipeline.ts +23 -0
  150. package/lib/platform/verification-required.ts +0 -2
  151. package/lib/platform/verification-sync.ts +0 -94
  152. package/lib/process-data/normalize.ts +1 -186
  153. package/lib/process-data/privacy.ts +2 -19
  154. package/lib/process-data/sources.ts +3 -283
  155. package/lib/render.ts +0 -15
  156. package/lib/run/index.ts +13 -7
  157. package/lib/run/skills.ts +0 -4
  158. package/lib/sandbox/commands/create.ts +37 -74
  159. package/lib/sandbox/commands/list-running.ts +0 -19
  160. package/lib/sandbox/commands/start.ts +7 -10
  161. package/lib/sandbox/constants.ts +0 -8
  162. package/lib/sandbox/control/client.ts +0 -1
  163. package/lib/sandbox/control/container-identity.ts +1 -16
  164. package/lib/sandbox/control/executor.ts +1 -5
  165. package/lib/sandbox/control/identity-sentinel.ts +0 -8
  166. package/lib/sandbox/control/lifecycle.ts +18 -51
  167. package/lib/sandbox/control/native-file-lock.ts +0 -8
  168. package/lib/sandbox/control/protocol.ts +0 -2
  169. package/lib/sandbox/control/server.ts +13 -39
  170. package/lib/sandbox/control/state.ts +1 -10
  171. package/lib/sandbox/dockerfile.ts +0 -11
  172. package/lib/sandbox/engine.ts +0 -17
  173. package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
  174. package/lib/sandbox/engines/wsl2-paths.ts +0 -4
  175. package/lib/sandbox/recovery.ts +24 -26
  176. package/lib/sandbox/removal.ts +58 -687
  177. package/lib/sandbox/shell.ts +1 -1
  178. package/lib/sandbox/task-resolver.ts +0 -48
  179. package/lib/sandbox/tools.ts +1 -5
  180. package/lib/sandbox/workspace-view.ts +2 -4
  181. package/lib/server/display.ts +0 -14
  182. package/lib/server/process-control.ts +1 -1
  183. package/lib/task/activity-intent.ts +36 -44
  184. package/lib/task/activity-log.ts +9 -22
  185. package/lib/task/artifact-command.ts +1 -1
  186. package/lib/task/artifact-lifecycle.ts +58 -67
  187. package/lib/task/artifact-name.ts +0 -7
  188. package/lib/task/artifact-operations.ts +3 -3
  189. package/lib/task/capabilities.ts +5 -6
  190. package/lib/task/commands/log.ts +0 -7
  191. package/lib/task/commands/status.ts +14 -79
  192. package/lib/task/commit-operation.ts +29 -51
  193. package/lib/task/completion-facts.ts +45 -42
  194. package/lib/task/control-authority.ts +27 -317
  195. package/lib/task/control-recovery.ts +2 -5
  196. package/lib/task/create.ts +2 -5
  197. package/lib/task/decision-intents.ts +5 -5
  198. package/lib/task/delivery-target.ts +0 -40
  199. package/lib/task/events.ts +89 -123
  200. package/lib/task/finalization.ts +52 -15
  201. package/lib/task/ledger-intents.ts +1 -1
  202. package/lib/task/lifecycle-execution.ts +37 -89
  203. package/lib/task/lifecycle.ts +48 -44
  204. package/lib/task/local-artifact-finalization.ts +0 -7
  205. package/lib/task/manual-validation-evidence.ts +1 -47
  206. package/lib/task/platform-operation-recovery.ts +117 -104
  207. package/lib/task/pr-delivery-fact.ts +2 -11
  208. package/lib/task/qualification-confirmation.ts +6 -6
  209. package/lib/task/resolve-ref.ts +0 -23
  210. package/lib/task/review-command.ts +2 -2
  211. package/lib/task/review-finalization.ts +1 -27
  212. package/lib/task/review-fingerprint.ts +0 -8
  213. package/lib/task/secure-fs.ts +0 -42
  214. package/lib/task/short-id.ts +0 -43
  215. package/lib/task/skill-scope.ts +0 -1
  216. package/lib/task/verification-engine.ts +56 -287
  217. package/lib/task/verification.ts +5 -5
  218. package/lib/task/write.ts +12 -1
  219. package/package.json +2 -2
  220. package/templates/.agents/README.en.md +1 -3
  221. package/templates/.agents/README.zh-CN.md +0 -2
  222. package/templates/.agents/rules/README.en.md +0 -1
  223. package/templates/.agents/rules/README.zh-CN.md +0 -1
  224. package/templates/.agents/rules/commit-and-pr.en.md +1 -1
  225. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
  226. package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
  227. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
  228. package/templates/.agents/rules/pr-sync.en.md +4 -2
  229. package/templates/.agents/rules/pr-sync.zh-CN.md +6 -9
  230. package/templates/.agents/rules/task-management.en.md +3 -3
  231. package/templates/.agents/rules/task-management.zh-CN.md +3 -3
  232. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  233. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  234. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  235. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  236. package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
  237. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
  238. package/templates/.agents/skills/commit/SKILL.en.md +2 -2
  239. package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
  240. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
  241. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
  242. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  243. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  244. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +2 -2
  245. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +2 -2
  246. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -25
  247. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -26
  248. package/templates/.agents/skills/create-pr/SKILL.en.md +1 -1
  249. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
  250. package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -2
  251. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -2
  252. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
  253. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
  254. package/templates/.agents/skills/create-task/SKILL.en.md +0 -18
  255. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +0 -18
  256. package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
  257. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
  258. package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
  259. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
  260. package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
  261. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
  262. package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
  263. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
  264. package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
  265. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
  266. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
  267. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
  268. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
  269. package/templates/.agents/skills/watch-pr/SKILL.en.md +1 -1
  270. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
  271. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
  272. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
  273. package/templates/.agents/templates/task.en.md +1 -0
  274. package/templates/.agents/templates/task.zh-CN.md +1 -0
  275. package/templates/.claude/settings.json +0 -24
  276. package/templates/.codex/hooks.json +0 -50
  277. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
  278. package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
  279. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
  280. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
  281. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
  282. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
  283. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
  284. package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
  285. package/dist/lib/internal/task-orchestration.js +0 -71
  286. package/dist/lib/platform/verification.js +0 -6
  287. package/dist/lib/run/prompt.js +0 -2
  288. package/dist/lib/sandbox/engines/authority.js +0 -289
  289. package/dist/lib/task/delegation-receipts.js +0 -410
  290. package/dist/lib/task/orchestration.js +0 -1233
  291. package/dist/lib/task/verification-checks.js +0 -9
  292. package/dist/lib/task/workspace-snapshot.js +0 -121
  293. package/dist/lifecycle-build-manifest.json +0 -6
  294. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
  295. package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
  296. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
  297. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
  298. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
  299. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
  300. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
  301. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
  302. package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
  303. package/lib/internal/task-orchestration.ts +0 -74
  304. package/lib/platform/verification.ts +0 -11
  305. package/lib/run/prompt.ts +0 -1
  306. package/lib/sandbox/engines/authority.ts +0 -365
  307. package/lib/task/delegation-receipts.ts +0 -547
  308. package/lib/task/orchestration.ts +0 -1651
  309. package/lib/task/verification-checks.ts +0 -10
  310. package/lib/task/workspace-snapshot.ts +0 -144
  311. package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
  312. package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
  313. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
  314. package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
  315. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
  316. package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
  317. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
  318. package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
  319. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
  320. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
  321. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
  322. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
  323. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
  324. package/templates/.claude/commands/run-task.en.md +0 -8
  325. package/templates/.claude/commands/run-task.zh-CN.md +0 -8
  326. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
  327. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
  328. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
  329. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
  330. package/templates/.opencode/commands/run-task.en.md +0 -11
  331. package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
@@ -4,7 +4,9 @@ import { execFileSync } from 'node:child_process';
4
4
 
5
5
  import { resolveBranchWorktree } from '../git/branch-worktree.ts';
6
6
 
7
- import { appendActivityEntry, locateActivityLog, pairEntries, startedBackedRows } from './activity-log.ts';
7
+ import { appendActivityEntry, inspectActivityLog } from './activity-log.ts';
8
+ import { lifecycleExecutions, serializeLifecycleExecution } from './lifecycle-execution.ts';
9
+ import type { LifecycleExecution } from './lifecycle-execution.ts';
8
10
  import {
9
11
  buildArtifactLinkSection,
10
12
  inspectArtifactDirectory,
@@ -28,13 +30,9 @@ import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.
28
30
  import { extractReviewBaseline, extractReviewedHead, extractReviewedSnapshotTree } from './review-fingerprint.ts';
29
31
  import { resolveTaskRef } from './resolve-ref.ts';
30
32
  import { findSectionHeading } from './sections.ts';
31
- import { validateLifecycleExecution } from './lifecycle-execution.ts';
32
- import { commitOrchestrationStageCompletion } from './orchestration.ts';
33
- import type { OrchestrationStageCompletion } from './orchestration.ts';
34
33
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
35
34
  import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
36
35
  import { validateLocalArtifact } from './local-artifact-finalization.ts';
37
- import type { LocalArtifactFamily } from './local-artifact-finalization.ts';
38
36
  import { buildLifecycleFacts, canStart, effectiveReworkTarget } from './capabilities.ts';
39
37
  import type { ExplicitTrigger, LifecycleAction, TriggerInitiator, TriggerReason } from './capabilities.ts';
40
38
  import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.ts';
@@ -43,7 +41,7 @@ import { parseTaskQualification } from './qualification-audit.ts';
43
41
  import { getArtifactSchema } from './artifact-schema.ts';
44
42
  import { canonicalSemanticDigest, inspectArtifactContract } from './artifact-operations.ts';
45
43
  import { inspectReviewIdentity } from './review-identity.ts';
46
- import { parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
44
+ import { hasValidArtifactCompletion, parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
47
45
  import { readManualValidationCompletion } from './manual-validation-completion.ts';
48
46
  import { parseLifecyclePathDecision } from './lifecycle-path.ts';
49
47
 
@@ -65,14 +63,13 @@ type TaskEventErrorCode =
65
63
  | 'EVENT_LOG_MISSING' | 'EVENT_START_MISSING' | 'EVENT_ALREADY_COMPLETED'
66
64
  | 'EVENT_LOG_CONFLICT' | 'EVENT_ARTIFACT_CONFLICT' | 'EVENT_FINDING_COUNT_MISMATCH'
67
65
  | 'EVENT_VERDICT_INVALID'
68
- | 'EVENT_ORCHESTRATION_COMMIT_FAILED'
69
66
  | 'MANUAL_VALIDATION_RECEIPT_MISSING' | 'MANUAL_VALIDATION_RECEIPT_INVALID'
70
67
  | 'MANUAL_VALIDATION_RECEIPT_IDENTITY_MISMATCH'
71
68
  | 'MANUAL_VALIDATION_TRANSACTION_MISSING' | 'MANUAL_VALIDATION_TRANSACTION_INVALID'
72
69
  | 'MANUAL_VALIDATION_TRANSACTION_IDENTITY_MISMATCH' | 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID'
73
70
  | ArtifactErrorCode | TaskWriteErrorCode;
74
71
  type TaskEventRequest = {
75
- taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean; orchestrated?: boolean;
72
+ taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean;
76
73
  initiator?: TriggerInitiator; requestId?: string; reasonCode?: TriggerReason;
77
74
  sourceFinding?: string; sourceArtifact?: string; sourceSha256?: string;
78
75
  round?: number; question?: number; artifact?: string; fixFor?: string; implementationInput?: string;
@@ -83,9 +80,7 @@ type TaskEventRequest = {
83
80
  transactionId?: string; receiptDigest?: string; prHeadSha?: string;
84
81
  };
85
82
  type TaskEventError = { code: TaskEventErrorCode; message: string };
86
- type TaskEventOptions = TaskWriteOptions & {
87
- commitOrchestrationCompletion?: (plan: OrchestrationStageCompletion) => void;
88
- };
83
+ type TaskEventOptions = TaskWriteOptions;
89
84
  type TaskEventResult = {
90
85
  status: 'planned' | 'applied' | 'no-op' | 'failed'; changed: boolean;
91
86
  event: string; requestRef: string; taskId: string | null; taskMdPath: string | null;
@@ -95,6 +90,7 @@ type TaskEventResult = {
95
90
  artifactContext: ArtifactContextResult | null;
96
91
  timestamp: string | null; agentInfraVersion: string | null;
97
92
  operations: readonly TaskOperationSummary[]; error: TaskEventError | null;
93
+ warnings?: readonly { code: string; message: string }[];
98
94
  };
99
95
 
100
96
  function branchWorktree(repoRoot: string, branch: string): string | null {
@@ -125,17 +121,17 @@ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun', 'initiator',
125
121
  const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[] }> = {
126
122
  'analyze.started': { optional: ['round'] },
127
123
  'analyze.awaiting-input': { required: ['question'] },
128
- 'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
124
+ 'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
129
125
  'review-analysis.started': { optional: ['round'] },
130
- 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
126
+ 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
131
127
  'plan.started': { optional: ['round'] },
132
- 'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
128
+ 'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
133
129
  'review-plan.started': { optional: ['round'] },
134
- 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
130
+ 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
135
131
  'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
136
- 'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
132
+ 'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
137
133
  'review-code.started': { optional: ['round'] },
138
- 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
134
+ 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
139
135
  'manual-validation.started': { optional: ['round', 'transactionId'] },
140
136
  'manual-validation.completed': { required: ['artifact', 'summaryResult', 'transactionId', 'receiptDigest', 'prHeadSha'], optional: ['round'] },
141
137
  'validation-run.started': { optional: ['round'] },
@@ -157,7 +153,7 @@ function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | n
157
153
  if (value !== undefined && (!Number.isInteger(value) || value < (key === 'round' || key === 'question' ? 1 : 0))) return { code: 'EVENT_PAYLOAD_INVALID', message: `'${key}' must be a ${key === 'round' || key === 'question' ? 'positive' : 'non-negative'} integer` };
158
154
  }
159
155
  if (request.verdict && !['approved', 'changes-requested', 'rejected'].includes(request.verdict)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'verdict is invalid' };
160
- if (request.initiator && !['human', 'model', 'orchestrator'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
156
+ if (request.initiator && !['human', 'model'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
161
157
  if (request.requestId !== undefined && (!request.requestId.trim() || /[\r\n]/.test(request.requestId))) return { code: 'EVENT_PAYLOAD_INVALID', message: 'requestId must be a non-empty single line' };
162
158
  if (request.reasonCode && !['user-request', 'new-requirement', 'upstream-fact-doubt', 'review-finding', 'manual-review-supplement', 'retry', 'validation-rerun'].includes(request.reasonCode)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'reasonCode is invalid' };
163
159
  for (const [name, value] of [['sourceFinding', request.sourceFinding], ['sourceArtifact', request.sourceArtifact], ['sourceSha256', request.sourceSha256]] as const) {
@@ -368,27 +364,19 @@ function validateManualValidationCompletion(
368
364
  return null;
369
365
  }
370
366
 
371
- function openStartedIdentity(rows: ReturnType<typeof pairEntries>, family: EventFamily) {
372
- const spec = FAMILY[family];
367
+ function openStartedIdentity(rows: LifecycleExecution[], family: EventFamily) {
368
+ const matches = rows.filter((item) => item.family === family);
373
369
  if (family === 'manual-validation') {
374
- const row = rows.filter((item) => item.step === spec.label && item.started && !item.done).at(-1);
375
- const completed = rows.filter((item) => item.step === spec.label && item.done).length;
376
- return row ? { row, round: completed + 1, fixFor: undefined, implementationInput: undefined } : null;
377
- }
378
- const escaped = spec.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
379
- const pattern = new RegExp(`^${escaped} \\(Round (\\d+)(?:(?:, fix for (review-code(?:-r\\d+)?\\.md))|(?:, decision (II-[1-9]\\d*)))?\\)$`);
380
- const matches = rows.flatMap((row) => {
381
- if (!row.started || row.done) return [];
382
- const match = pattern.exec(row.step);
383
- return match ? [{ row, round: Number(match[1]), fixFor: match[2], implementationInput: match[3] }] : [];
384
- });
385
- return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true as const } : null;
370
+ const row = matches.at(-1);
371
+ return row ? { row, round: row.round!, fixFor: undefined, implementationInput: undefined } : null;
372
+ }
373
+ return matches.length === 1 ? { row: matches[0]!, round: matches[0]!.round!, fixFor: matches[0]!.fixFor, implementationInput: matches[0]!.implementationInput } : matches.length > 1 ? { conflict: true as const } : null;
386
374
  }
387
375
 
388
376
  function repairMissingCodeFixQualifier(
389
377
  request: TaskEventRequest,
390
378
  family: EventFamily,
391
- open: { row: { step: string }; round: number; fixFor?: string; implementationInput?: string },
379
+ open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
392
380
  repoRoot: string
393
381
  ) {
394
382
  if (family !== 'code' || open.fixFor !== undefined || !request.fixFor || request.implementationInput !== undefined) {
@@ -411,12 +399,12 @@ function repairMissingCodeFixQualifier(
411
399
  function resolveOpenStartedEvent(
412
400
  request: TaskEventRequest,
413
401
  family: EventFamily,
414
- open: { row: { step: string; agent: string; started: string; note: string }; round: number; fixFor?: string; implementationInput?: string },
402
+ open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
415
403
  repoRoot: string
416
404
  ) {
417
405
  if (open.row.agent !== request.agent) return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' } as TaskEventError };
418
406
  if (family === 'manual-validation' && request.transactionId !== undefined) {
419
- const existingTransactionId = /(?:^|;\s*)transaction=([A-Za-z0-9][A-Za-z0-9._-]{0,127})(?:;|$)/u.exec(open.row.note)?.[1];
407
+ const existingTransactionId = open.row.transactionId;
420
408
  if (existingTransactionId !== undefined && existingTransactionId !== request.transactionId) {
421
409
  return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' } as TaskEventError };
422
410
  }
@@ -428,7 +416,7 @@ function resolveOpenStartedEvent(
428
416
  const repair = repairMissingCodeFixQualifier(request, family, open, repoRoot);
429
417
  if (!repair) return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `fixFor '${request.fixFor}' conflicts with open event` } as TaskEventError };
430
418
  if ('error' in repair) return { status: 'error' as const, error: repair.error, context: repair.context };
431
- return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: open.row.step } };
419
+ return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: `${FAMILY[family].label} (Round ${open.round})`, family: open.row.family, round: open.row.round } };
432
420
  }
433
421
  if (request.implementationInput !== open.implementationInput) {
434
422
  return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `implementationInput '${request.implementationInput ?? ''}' conflicts with open event` } as TaskEventError };
@@ -442,19 +430,12 @@ function resolveOpenStartedEvent(
442
430
  fixFor: open.fixFor,
443
431
  implementationInput: open.implementationInput
444
432
  },
445
- startedAt: open.row.started
433
+ startedAt: open.row.startedAt
446
434
  };
447
435
  }
448
436
 
449
- function hasOtherOpenStarted(rows: ReturnType<typeof pairEntries>, allowedAction: string): boolean {
450
- return rows.some((row) => row.started && !row.done && row.step !== allowedAction);
451
- }
452
-
453
- function hasConflictingOpenStarted(
454
- rows: ReturnType<typeof pairEntries>,
455
- recovery: { action: string } | null
456
- ): boolean {
457
- return recovery ? hasOtherOpenStarted(rows, recovery.action) : rows.some((row) => row.started && !row.done);
437
+ function hasConflictingOpenStarted(rows: LifecycleExecution[], recovery: { family: string; round?: number } | null): boolean {
438
+ return rows.some((row) => !recovery || row.family !== recovery.family || row.round !== recovery.round);
458
439
  }
459
440
 
460
441
  function reviewInputFamily(family: EventFamily): ArtifactFamily {
@@ -467,7 +448,7 @@ function lifecycleAction(family: EventFamily): LifecycleAction {
467
448
 
468
449
  function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitTrigger {
469
450
  return {
470
- initiator: request.initiator ?? (request.orchestrated ? 'orchestrator' : request.agent === 'human' ? 'human' : 'model'),
451
+ initiator: request.initiator ?? (request.agent === 'human' ? 'human' : 'model'),
471
452
  requestId: request.requestId ?? `${request.taskRef}:${request.event}:${request.round ?? 1}`,
472
453
  requestedAction: lifecycleAction(family),
473
454
  reasonCode: request.reasonCode ?? (request.fixFor || request.implementationInput ? 'review-finding' : 'user-request'),
@@ -475,7 +456,7 @@ function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitT
475
456
  ...(request.sourceArtifact ? { sourceArtifact: request.sourceArtifact } : {}),
476
457
  ...(request.sourceSha256 ? { sourceSha256: request.sourceSha256 } : {}),
477
458
  ...(request.implementationInput ? { implementationInput: request.implementationInput } : {}),
478
- explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined || request.orchestrated === true
459
+ explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined
479
460
  };
480
461
  }
481
462
 
@@ -639,12 +620,16 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
639
620
  let frontmatter;
640
621
  try { frontmatter = parseTypedTaskFrontmatter(content); }
641
622
  catch (error) { return failed(request, { code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
642
- const section = locateActivityLog(content);
643
- if (!section) return failed(request, { code: 'EVENT_LOG_MISSING', message: 'task has no unique Activity Log section' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
644
- const rows = startedBackedRows(pairEntries(section.entries));
623
+ const section = inspectActivityLog(content).section;
624
+ let rows: LifecycleExecution[];
625
+ try {
626
+ rows = lifecycleExecutions(content);
627
+ } catch (error) {
628
+ return failed(request, { code: 'EVENT_TRANSITION_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
629
+ }
645
630
  let normalized = request;
646
631
  let artifactContext: ArtifactContextResult | null = null;
647
- let supersededOpenStart: { action: string } | null = null;
632
+ let supersededOpenStart: { action: string; family: string; round?: number } | null = null;
648
633
  if (initialParts.phase === 'started') {
649
634
  const openIdentity = openStartedIdentity(rows, initialParts.family);
650
635
  if (openIdentity && 'conflict' in openIdentity) return failed(request, { code: 'EVENT_LOG_CONFLICT', message: 'artifact family has more than one open started event' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
@@ -674,10 +659,11 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
674
659
  }
675
660
  const eventIdentity = identity(normalized);
676
661
  const currentStep = typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '';
677
- const matchingRows = rows.filter((item) => item.step === eventIdentity.action);
678
662
  const manual = eventIdentity.family === 'manual-validation';
679
- const openRows = matchingRows.filter((item) => item.started && !item.done);
680
- const completedRows = matchingRows.filter((item) => item.done);
663
+ const openRows = rows.filter((item) => item.family === eventIdentity.family && (manual || (item.round === normalized.round && item.fixFor === normalized.fixFor && item.implementationInput === normalized.implementationInput)));
664
+ const completionRecorded = normalized.artifact !== undefined && parseCompletionFacts(frontmatter.completion_facts)
665
+ .some((fact) => fact.event === normalized.event && fact.output === normalized.artifact);
666
+ const hasStartedIdentity = openRows.length > 0;
681
667
  if (!manual && openRows.length > 1) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'event identity has more than one open attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
682
668
  const row = openRows.at(-1);
683
669
  let completedArtifact: ArtifactIdentity | null = null;
@@ -685,14 +671,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
685
671
  if (eventIdentity.phase === 'started' && row) {
686
672
  if (row.agent !== normalized.agent) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
687
673
  if (manual && normalized.transactionId !== undefined) {
688
- const existingTransactionId = /(?:^|;\s*)transaction=([A-Za-z0-9][A-Za-z0-9._-]{0,127})(?:;|$)/u.exec(row.note)?.[1];
674
+ const existingTransactionId = row.transactionId;
689
675
  if (existingTransactionId !== undefined && existingTransactionId !== normalized.transactionId) {
690
676
  return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
691
677
  }
692
678
  }
693
- return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.started, frontmatter, artifactContext);
694
- }
695
- if (eventIdentity.phase === 'completed' && !row?.started && completedRows.length === 0) return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires a started event or an earlier completed attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
679
+ return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.startedAt, frontmatter, artifactContext);
680
+ }
681
+ const replayFact = eventIdentity.phase === 'completed' && normalized.artifact && normalized.requestId
682
+ ? parseCompletionFacts(frontmatter.completion_facts).find((fact) => fact.event === normalized.event
683
+ && fact.output === normalized.artifact && fact.requestId === normalized.requestId)
684
+ : undefined;
685
+ const validReplayFact = Boolean(replayFact && normalized.artifact
686
+ && hasValidArtifactCompletion(content, resolved.taskDir, normalized.artifact, normalized.event));
687
+ const completedByHistory = manual || eventIdentity.family === 'validation-run';
688
+ const completedHistoryReplay = completedByHistory && completionRecorded;
689
+ if (eventIdentity.phase === 'completed' && !hasStartedIdentity && !completedHistoryReplay && !validReplayFact) return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires a started event or an earlier completed attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
696
690
  if (eventIdentity.phase === 'completed') {
697
691
  const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact!, normalized.round);
698
692
  if (!validated.ok) return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
@@ -750,10 +744,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
750
744
  }
751
745
  }
752
746
  }
753
- if (eventIdentity.phase === 'waiting' && section.entries.some((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)) {
754
- const existing = section.entries.find((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)!;
755
- return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, existing.time, frontmatter, artifactContext);
756
- }
757
747
  if (eventIdentity.phase === 'started') {
758
748
  const trigger = eventTrigger(normalized, eventIdentity.family);
759
749
  const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, false, resolved.repoRoot);
@@ -761,7 +751,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
761
751
  const capability = canStart(lifecycleAction(eventIdentity.family), facts.facts, trigger);
762
752
  const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
763
753
  || capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN';
764
- if (!capability.allowed && (normalized.initiator === 'orchestrator' || safetyFailure)
754
+ if (!capability.allowed && safetyFailure
765
755
  && !(supersededOpenStart && capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN')) {
766
756
  return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
767
757
  }
@@ -773,29 +763,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
773
763
  completedArtifact?.path ?? null
774
764
  );
775
765
  if (findingCountError) return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
776
- let orchestrationCompletion: OrchestrationStageCompletion | null = null;
777
- if (eventIdentity.phase === 'completed' && normalized.orchestrated
778
- && eventIdentity.family !== 'manual-validation' && eventIdentity.family !== 'validation-run') {
779
- const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
780
- const execution = validateLifecycleExecution(normalized.taskRef, {
781
- mode: 'orchestrated',
782
- identity: {
783
- stage: orchestrationStage,
784
- round: normalized.round!,
785
- artifact: normalized.artifact!,
786
- role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
787
- },
788
- agent: normalized.agent,
789
- dryRun: normalized.dryRun
790
- }, { repoRoot: options.repoRoot });
791
- if (!execution.ok) {
792
- return failed(normalized, {
793
- code: 'EVENT_TRANSITION_INVALID',
794
- message: `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`
795
- }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
796
- }
797
- orchestrationCompletion = execution.completionPlan;
798
- }
799
766
  let metadata;
800
767
  try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
801
768
  catch (error) { return failed(normalized, { code: 'METADATA_CAPTURE_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
@@ -828,6 +795,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
828
795
  artifactContext
829
796
  );
830
797
  }
798
+ if (!hasStartedIdentity && !completedHistoryReplay) {
799
+ return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion replay does not match the existing completion fact' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
800
+ }
831
801
  try {
832
802
  const rework = reworkIntentMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
833
803
  if ('error' in rework) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: rework.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
@@ -838,19 +808,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
838
808
  }
839
809
  const step = eventIdentity.phase === 'started' || eventIdentity.target === null ? currentStep : eventIdentity.target;
840
810
  const logStep = eventIdentity.phase === 'started' ? `${eventIdentity.action} [started]` : eventIdentity.action;
841
- const supersededBody = supersededOpenStart
842
- ? appendActivityEntry(section, {
843
- time: metadata.timestamp,
844
- step: `${supersededOpenStart.action} [aborted]`,
845
- agent: normalized.agent,
846
- note: `superseded by ${eventIdentity.action}`
847
- })
848
- : section.body;
849
- const body = appendActivityEntry(
850
- supersededOpenStart ? { ...section, body: supersededBody } : section,
851
- { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note }
852
- );
811
+ let body: string | null = null;
812
+ if (section) {
813
+ const supersededBody = supersededOpenStart
814
+ ? appendActivityEntry(section, {
815
+ time: metadata.timestamp, step: `${supersededOpenStart.action} [aborted]`,
816
+ agent: normalized.agent, note: `superseded by ${eventIdentity.action}`
817
+ }) : section.body;
818
+ body = appendActivityEntry({ ...section, body: supersededBody },
819
+ { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
820
+ }
853
821
  const frontmatterSet: Record<string, string> = { current_step: step, assigned_to: normalized.agent };
822
+ if (eventIdentity.phase === 'started' || eventIdentity.phase === 'completed') {
823
+ const open = rows.filter((item) => !openRows.includes(item) && (!supersededOpenStart || item.family !== supersededOpenStart.family || item.round !== supersededOpenStart.round));
824
+ if (eventIdentity.phase === 'started') open.push({ family: eventIdentity.family, agent: normalized.agent, startedAt: metadata.timestamp, round: normalized.round, fixFor: normalized.fixFor, implementationInput: normalized.implementationInput, transactionId: normalized.transactionId });
825
+ frontmatterSet.lifecycle_execution = serializeLifecycleExecution(open, content);
826
+ }
854
827
  if (currentFact) frontmatterSet.completion_facts = JSON.stringify(replaceCompletionFact(parseCompletionFacts(frontmatter.completion_facts), currentFact));
855
828
  if (completedArtifact && ['analyze', 'plan', 'code'].includes(eventIdentity.family)) {
856
829
  const task = parseTaskQualification(content);
@@ -909,7 +882,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
909
882
  }
910
883
  if (eventIdentity.phase === 'started' && normalized.implementationInput) frontmatterSet.last_reviewed_commit = '';
911
884
  const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
912
- { kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove }
885
+ { kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove, ...(frontmatterSet.lifecycle_execution ? { lifecycleExecutionDomain: 'ordinary' as const } : {}) }
913
886
  ];
914
887
  if (completedArtifact) {
915
888
  const link = buildArtifactLinkSection(content, completedArtifact);
@@ -942,30 +915,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
942
915
  body: renderImplementationInputs(implementationRows)
943
916
  });
944
917
  }
945
- mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
918
+ if (section && body !== null) mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
946
919
  const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
947
920
  if (result.status === 'failed') return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
948
- if (!normalized.dryRun && orchestrationCompletion) {
949
- try {
950
- (options.commitOrchestrationCompletion ?? commitOrchestrationStageCompletion)(orchestrationCompletion);
951
- } catch (error) {
952
- return failed(normalized, {
953
- code: 'EVENT_ORCHESTRATION_COMMIT_FAILED',
954
- message: `task.md was written but orchestration completion could not be persisted; manual recovery is required: ${error instanceof Error ? error.message : String(error)}`
955
- }, {
956
- taskId: result.taskId,
957
- taskMdPath: result.taskMdPath,
958
- fromStep: currentStep,
959
- toStep: step,
960
- action: eventIdentity.action,
961
- phase: eventIdentity.phase,
962
- timestamp: result.timestamp,
963
- agentInfraVersion: result.agentInfraVersion,
964
- operations: result.operations,
965
- artifactContext
966
- });
967
- }
968
- }
969
921
  return {
970
922
  status: result.status, changed: result.changed, event: normalized.event,
971
923
  requestRef: normalized.taskRef, taskId: result.taskId, taskMdPath: result.taskMdPath,
@@ -991,5 +943,19 @@ function successNoOp(
991
943
  };
992
944
  }
993
945
 
994
- export { eventCatalog, validateTaskEventRequest, applyTaskEvent };
946
+ function applyTaskEventWithWarnings(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
947
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
948
+ let warnings: { code: string; message: string }[] = [];
949
+ if (resolved.ok) {
950
+ try {
951
+ const inspected = inspectActivityLog(fs.readFileSync(resolved.taskMdPath, 'utf8'));
952
+ if (!inspected.section) warnings = [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous; no entry was appended' }];
953
+ else if (inspected.invalidEntries.length) warnings = [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries' }];
954
+ } catch { /* The core reports task read errors. */ }
955
+ }
956
+ const result = applyTaskEvent(request, options);
957
+ return result.status === 'failed' || warnings.length === 0 ? result : { ...result, warnings };
958
+ }
959
+
960
+ export { eventCatalog, validateTaskEventRequest, applyTaskEventWithWarnings as applyTaskEvent };
995
961
  export type { TaskEventName, TaskEventRequest, TaskEventResult, TaskEventError, TaskEventErrorCode, TaskEventOptions, Verdict };
@@ -10,13 +10,13 @@ import { taskIssueIdentity } from '../platform/task-identities.ts';
10
10
  import { inspectPlatformIssue, syncPlatformIssue } from '../platform/issues.ts';
11
11
  import type { IssueResult, SyncOptions as IssueSyncOptions } from '../platform/issues.ts';
12
12
  import { resourceIdentityEquals } from '../platform/resource-identity.ts';
13
+ import { activityWarnings } from './activity-log.ts';
13
14
  import { parseTaskFrontmatter } from './frontmatter.ts';
14
15
  import { recoverPlatformOperations } from './platform-operation-recovery.ts';
15
16
  import {
16
17
  applyTaskLifecycle,
17
18
  inspectTaskLifecycleProgress,
18
19
  type TaskLifecycleOptions,
19
- type TaskLifecycleRequest,
20
20
  type TaskLifecycleResult,
21
21
  type TaskCompletionProjection,
22
22
  previewTaskCompletion
@@ -33,6 +33,7 @@ import {
33
33
  } from './operation-outcome.ts';
34
34
  import { readSandboxControlManifest } from '../sandbox/control/lifecycle.ts';
35
35
  import { validateSandboxControlIdentity } from '../sandbox/control/identity-sentinel.ts';
36
+ import { parseDeliverySummaryContent, renderDeliverySummaryContent } from '../platform/issue-summary-content.ts';
36
37
 
37
38
  const RECEIPT_VERSION = 4 as const;
38
39
  const FINALIZATION_STEPS = ['lifecycle', 'task-comment', 'verification', 'summary'] as const;
@@ -105,6 +106,7 @@ type TaskFinalizationStep = Readonly<{
105
106
  error: FinalizationError | null;
106
107
  completedSteps?: readonly string[];
107
108
  pendingSteps?: readonly string[];
109
+ warnings?: readonly OperationWarning[];
108
110
  }>;
109
111
 
110
112
  type TaskCommentSyncOutcome = Readonly<{
@@ -331,7 +333,8 @@ function lifecycleStep(result: TaskLifecycleResult): TaskFinalizationStep {
331
333
  changed: result.changed,
332
334
  error: result.error ? errorOf(result.error, 'LIFECYCLE_FAILED') : null,
333
335
  completedSteps: result.completedSteps ?? [],
334
- pendingSteps: result.pendingSteps ?? []
336
+ pendingSteps: result.pendingSteps ?? [],
337
+ warnings: (result.warnings ?? []).map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }))
335
338
  };
336
339
  }
337
340
 
@@ -347,7 +350,17 @@ function verificationStep(result: TaskVerificationResult): TaskFinalizationStep
347
350
  return {
348
351
  status: result.status,
349
352
  changed: false,
350
- error: result.status === 'pass' ? null : verificationFailure(result)
353
+ error: result.status === 'pass' ? null : verificationFailure(result),
354
+ warnings: result.invocations.flatMap(({ payload }) => {
355
+ const checks = Array.isArray(payload.checks) ? payload.checks : [payload];
356
+ return checks.flatMap((check) => {
357
+ if (!check || typeof check !== 'object' || !Array.isArray(check.warnings)) return [];
358
+ return check.warnings.filter((message: unknown): message is string => typeof message === 'string').map((message: string) => ({
359
+ code: 'VERIFICATION_DIAGNOSTIC', message, retryable: true, step: 'verification',
360
+ target: typeof check.checkId === 'string' ? check.checkId : String(check.type ?? 'check'), severity: 'IMPORTANT' as const
361
+ }));
362
+ });
363
+ })
351
364
  };
352
365
  }
353
366
 
@@ -493,7 +506,7 @@ function issueCapability(receipt: TaskFinalizationReceipt, scope: Exclude<Finali
493
506
 
494
507
  function capabilityError(code: 'FINALIZATION_CAPABILITY_STALE' | 'FINALIZATION_SCOPE_INVALID', message: string): Error {
495
508
  const error = new Error(message);
496
- error.name = 'OrchestrationStateError';
509
+ error.name = 'TaskFinalizationCapabilityError';
497
510
  Object.assign(error, { code });
498
511
  return error;
499
512
  }
@@ -730,16 +743,20 @@ function readDeliverySummary(taskDir: string, taskId: string): { body: string; s
730
743
  } catch {
731
744
  throw Object.assign(new Error('delivery summary staging record is unavailable'), { code: 'SUMMARY_STAGING_INVALID' });
732
745
  }
733
- if (value.taskId !== taskId || typeof value.body !== 'string' || typeof value.sha256 !== 'string') {
746
+ if (value.taskId !== taskId || !value.content || typeof value.contentSha256 !== 'string') {
734
747
  throw Object.assign(new Error('delivery summary staging record is invalid'), { code: 'SUMMARY_STAGING_INVALID' });
735
748
  }
736
- const canonical = canonicalizeSummaryBody(value.body);
737
- if (!canonical.ok || canonical.value !== value.body) {
738
- throw Object.assign(new Error('delivery summary staging body is not canonical'), { code: 'SUMMARY_STAGING_INVALID' });
749
+ let content;
750
+ try { content = parseDeliverySummaryContent(value.content); }
751
+ catch { throw Object.assign(new Error('delivery summary staging payload is invalid'), { code: 'SUMMARY_STAGING_INVALID' }); }
752
+ if (content.taskId !== taskId || createHash('sha256').update(JSON.stringify(content)).digest('hex') !== value.contentSha256) {
753
+ throw Object.assign(new Error('delivery summary staging digest does not match payload'), { code: 'SUMMARY_STAGING_INVALID' });
739
754
  }
755
+ const body = renderDeliverySummaryContent(content);
756
+ const canonical = canonicalizeSummaryBody(body);
757
+ if (!canonical.ok) throw Object.assign(new Error('delivery summary staging body is not canonical'), { code: 'SUMMARY_STAGING_INVALID' });
740
758
  const digest = createHash('sha256').update(canonical.value).digest('hex');
741
- if (digest !== value.sha256) throw Object.assign(new Error('delivery summary staging digest does not match body'), { code: 'SUMMARY_STAGING_INVALID' });
742
- return { body: canonical.value, sha256: value.sha256 };
759
+ return { body: canonical.value, sha256: digest };
743
760
  }
744
761
 
745
762
  async function syncPendingSummary(input: {
@@ -810,7 +827,7 @@ function terminalResult(
810
827
  ): TaskFinalizationResult {
811
828
  const pending = pendingSteps(receipt);
812
829
  const blocked = [steps.backfill, steps.lifecycle, steps.taskComment, steps.verification, steps.summary].some((step) => step?.status === 'blocked');
813
- const warnings = openWarnings(receipt);
830
+ const warnings = mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? [], steps.verification?.warnings ?? []);
814
831
  const postLifecyclePending = receipt.lifecycle === 'done' && (pending.some((step) => step !== 'lifecycle') || receipt.warningProjection === 'pending');
815
832
  const terminalVerificationPending = receipt.lifecycle === 'done' && receipt.verification === 'pending';
816
833
  const resultError = error ?? (terminalVerificationPending ? steps.verification?.error : null) ?? null;
@@ -855,7 +872,7 @@ function preparedResult(
855
872
  verification: steps.verification ?? null,
856
873
  summary: steps.summary ?? null,
857
874
  completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt),
858
- result: 'prepared', warnings: openWarnings(receipt), error: null
875
+ result: 'prepared', warnings: mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? []), error: null
859
876
  };
860
877
  }
861
878
 
@@ -1130,7 +1147,7 @@ async function prepareTaskFinalizationCore(
1130
1147
  return preparedResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification, summary: summary.step }, changed);
1131
1148
  }
1132
1149
 
1133
- async function prepareTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1150
+ async function prepareTaskFinalizationInner(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1134
1151
  if (request.intent !== 'complete' || !request.taskRef || !request.agent) {
1135
1152
  return failed(null, { code: 'TASK_FINALIZATION_PAYLOAD_INVALID', message: 'complete finalization requires taskRef and agent', retryable: false });
1136
1153
  }
@@ -1306,6 +1323,25 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
1306
1323
  }
1307
1324
  }
1308
1325
 
1326
+ function withActivityWarnings(result: TaskFinalizationResult, request: TaskFinalizationRequest, options: TaskFinalizationOptions): TaskFinalizationResult {
1327
+ if (result.status === 'failed' || result.status === 'blocked') return result;
1328
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
1329
+ if (!resolved.ok) return result;
1330
+ let diagnostics: ReturnType<typeof activityWarnings>;
1331
+ try { diagnostics = activityWarnings(fs.readFileSync(resolved.taskMdPath, 'utf8')); }
1332
+ catch { return result; }
1333
+ const warnings = diagnostics.map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }));
1334
+ return { ...result, warnings: mergeOperationWarnings(result.warnings, warnings) };
1335
+ }
1336
+
1337
+ async function prepareTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1338
+ return withActivityWarnings(await prepareTaskFinalizationInner(request, options), request, options);
1339
+ }
1340
+
1341
+ async function commitPreparedTaskFinalizationWithWarnings(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1342
+ return withActivityWarnings(await commitPreparedTaskFinalization(request, options), request, options);
1343
+ }
1344
+
1309
1345
  async function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1310
1346
  const prepared = await prepareTaskFinalization(request, options);
1311
1347
  if (prepared.status !== 'prepared') return prepared;
@@ -1322,12 +1358,13 @@ async function applyTaskFinalization(request: TaskFinalizationRequest, options:
1322
1358
  });
1323
1359
  }
1324
1360
  }
1325
- return commitPreparedTaskFinalization(request, options);
1361
+ const committed = await commitPreparedTaskFinalizationWithWarnings(request, options);
1362
+ return { ...committed, warnings: mergeOperationWarnings(prepared.warnings, committed.warnings) };
1326
1363
  }
1327
1364
 
1328
1365
  export {
1329
1366
  applyFinalizationReceiptMutation,
1330
- commitPreparedTaskFinalization,
1367
+ commitPreparedTaskFinalizationWithWarnings as commitPreparedTaskFinalization,
1331
1368
  applyTaskFinalization,
1332
1369
  prepareTaskFinalization,
1333
1370
  issueCapability as createFinalizationCapability,
@@ -16,7 +16,7 @@ import { writeTask } from './write.ts';
16
16
  import type { TaskMutation, TaskOperationSummary, TaskWriteOptions } from './write.ts';
17
17
  import { parseLegacyReworkIntentDocument, parseReworkIntentDocument, reworkIntentMutation, upsertReworkIntent } from './rework-intent.ts';
18
18
  import type { ReworkClassification, ReworkIntent, ReworkTarget } from './rework-intent.ts';
19
- import { extractSection, extractSubSection } from './sections.ts';
19
+ import { extractSection } from './sections.ts';
20
20
  import { parseLifecyclePathDecision } from './lifecycle-path.ts';
21
21
  import { scanVisibleMarkdown } from './markdown.ts';
22
22
  import { inspectArtifactDirectory } from './artifact-lifecycle.ts';