@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
@@ -1,37 +1,11 @@
1
- import { spawnSync } from 'node:child_process';
2
1
  import fs from 'node:fs';
3
2
  import path from 'node:path';
4
- import { isRemovedHashShortIdInput } from '../task/short-id.js';
5
3
  import { resolveProjectTaskWorkspaceRoot } from '../task/workspace-root.js';
6
4
  const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
7
- const SHORT_ID_RE = /^\d+$/;
8
5
  export const TASK_WORKSPACE_STATES = ['active', 'completed', 'blocked', 'archive'];
9
- function resolveShortIdStrict(arg, repoRoot) {
10
- const scriptPath = path.join(repoRoot, '.agents', 'scripts', 'task-short-id.js');
11
- if (!fs.existsSync(scriptPath)) {
12
- throw new Error(`Short id '${arg}' provided but task-short-id.js script is missing at ${scriptPath}`);
13
- }
14
- const result = spawnSync('node', [scriptPath, 'resolve', arg], { encoding: 'utf8', cwd: repoRoot });
15
- if (result.status !== 0) {
16
- throw new Error(`Short id '${arg}' not found in active task registry: ${(result.stderr || '').trim()}`);
17
- }
18
- return result.stdout.trim();
19
- }
20
6
  function stripQuotes(value) {
21
7
  return value.replace(/^(["'])(.*)\1$/, '$2');
22
8
  }
23
- function readTaskContent(repoRoot, taskId) {
24
- const taskRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
25
- for (const state of TASK_WORKSPACE_STATES) {
26
- const taskPath = state === 'archive'
27
- ? path.join(taskRoot, state, ...findArchiveTaskParts(repoRoot, taskId), 'local', 'task.md')
28
- : path.join(taskRoot, state, taskId, 'task.md');
29
- if (fs.existsSync(taskPath)) {
30
- return { content: fs.readFileSync(taskPath, 'utf8'), state, taskMd: taskPath };
31
- }
32
- }
33
- throw new Error(`Task not found: ${taskId}`);
34
- }
35
9
  function taskWorkspaceCandidates(repoRoot, taskId) {
36
10
  const taskRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
37
11
  const hot = TASK_WORKSPACE_STATES.filter((state) => state !== 'archive').flatMap((state) => {
@@ -89,21 +63,6 @@ function resolveBranchFromTaskContent(content, taskId) {
89
63
  }
90
64
  throw new Error(`Task ${taskId} has no branch field in task.md`);
91
65
  }
92
- export function resolveTaskBranch(arg, repoRoot) {
93
- if (isRemovedHashShortIdInput(arg)) {
94
- throw new Error(`Invalid task short id '${arg}': task short ids must use bare digits`);
95
- }
96
- if (SHORT_ID_RE.test(arg)) {
97
- const taskId = resolveShortIdStrict(arg, repoRoot);
98
- const { content } = readTaskContent(repoRoot, taskId);
99
- return resolveBranchFromTaskContent(content, taskId);
100
- }
101
- if (!TASK_ID_RE.test(arg)) {
102
- return arg;
103
- }
104
- const { content } = readTaskContent(repoRoot, arg);
105
- return resolveBranchFromTaskContent(content, arg);
106
- }
107
66
  export function resolveTaskWorkspace(taskId, repoRoot) {
108
67
  if (!TASK_ID_RE.test(taskId))
109
68
  throw new Error(`Invalid task id: ${taskId}`);
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { createSandboxCapabilityPlan } from './agent-client-reconciler.js';
3
- import { safeNameCandidates, sanitizeBranchName } from './constants.js';
3
+ import { safeNameCandidates } from './constants.js';
4
4
  import { hostJoin } from './engines/wsl2-paths.js';
5
5
  export function tmpfsSeedStagingPath(toolId, index) {
6
6
  return `/run/agent-infra/tmpfs-seeds/${toolId}/${index}`;
@@ -233,9 +233,6 @@ export function parseCustomTools(value, options) {
233
233
  export function resolveTools(config) {
234
234
  return [...createSandboxCapabilityPlan(config).tools];
235
235
  }
236
- export function toolConfigDir(tool, project, branch) {
237
- return hostJoin(tool.sandboxBase, project, sanitizeBranchName(branch));
238
- }
239
236
  export function toolConfigDirCandidates(tool, project, branch) {
240
237
  return safeNameCandidates(branch).map((name) => hostJoin(tool.sandboxBase, project, name));
241
238
  }
@@ -295,8 +295,7 @@ export function finalizeSandboxControlManifest(setup, identity) {
295
295
  const manifest = {
296
296
  ...setup.manifestDraft,
297
297
  engine: identity.engine,
298
- containerIdentity: { id: identity.id, labels: { ...identity.labels } },
299
- authorityEvidence: identity.authorityEvidence
298
+ containerIdentity: { id: identity.id, labels: { ...identity.labels } }
300
299
  };
301
300
  const persistedManifest = {
302
301
  ...manifest,
@@ -4,9 +4,6 @@ export function textMessage(text) {
4
4
  export function markdownMessage(markdown) {
5
5
  return { kind: 'markdown', markdown };
6
6
  }
7
- export function tableMessage(columns, rows, title) {
8
- return { kind: 'table', title, columns, rows };
9
- }
10
7
  export function statusCard(title, tone, fields, body) {
11
8
  return { kind: 'status-card', title, tone, fields, body };
12
9
  }
@@ -20,9 +17,6 @@ export function streamEvent(title, phase, text, exitCode, signal) {
20
17
  message.signal = signal;
21
18
  return message;
22
19
  }
23
- export function commandResult(title, exitCode, signal, stdout, stderr) {
24
- return { kind: 'command-result', title, exitCode, signal, stdout, stderr };
25
- }
26
20
  export function normalizeOutbound(message) {
27
21
  return typeof message === 'string' ? textMessage(message) : message;
28
22
  }
@@ -1,12 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import { normalizeAgentToken } from '../agent-clients/tokens.js';
3
3
  import { resolveTaskRef } from './resolve-ref.js';
4
- import { locateActivityLog, appendActivityEntry } from './activity-log.js';
4
+ import { locateActivityLog, appendActivityEntry, inspectActivityLog } from './activity-log.js';
5
+ import { lifecycleExecutions, prReviewExecution, serializeLifecycleExecution } from './lifecycle-execution.js';
5
6
  import { assertWritableInventory, buildArtifactLinkSection, inspectTaskArtifacts } from './artifact-lifecycle.js';
6
7
  import { parseArtifactName } from './artifact-name.js';
7
8
  import { captureTaskWriteMetadata, writeTask } from './write.js';
8
9
  const HEAD_RE = /^[0-9a-f]{40}$/;
9
- const REVIEW_ACTION_RE = /^Review PR \(Round ([1-9]\d*)\)( \[started\])?$/;
10
10
  const VERDICTS = new Set(['approved', 'changes-requested', 'commented']);
11
11
  const OUTCOMES = new Set(['aborted', 'superseded']);
12
12
  const SUCCESS_STATUSES = new Set(['applied', 'no-op']);
@@ -76,47 +76,37 @@ function readSnapshot(taskRef, repoRoot) {
76
76
  catch (error) {
77
77
  return { ok: false, code: 'TASK_READ_FAILED', message: error instanceof Error ? error.message : String(error), taskId: resolved.taskId };
78
78
  }
79
- const activity = locateActivityLog(content);
80
- if (!activity)
81
- return { ok: false, code: 'ACTIVITY_SECTION_MISSING', message: 'task has no unique Activity Log section', taskId: resolved.taskId };
82
- const knownRounds = new Set(inventory.artifacts.map((artifact) => artifact.round));
83
- for (const entry of activity.entries) {
84
- const match = REVIEW_ACTION_RE.exec(entry.step);
85
- if (match && !knownRounds.has(Number(match[1]))) {
86
- return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `Activity Log round ${match[1]} has no canonical pr-review artifact`, taskId: resolved.taskId };
87
- }
79
+ let pr;
80
+ try {
81
+ pr = prReviewExecution(content);
82
+ }
83
+ catch (error) {
84
+ return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: String(error), taskId: resolved.taskId };
88
85
  }
89
86
  const states = [];
90
87
  for (const identity of inventory.artifacts) {
91
88
  const parsed = parseArtifactRecord(identity);
92
89
  if ('code' in parsed)
93
90
  return { ok: false, ...parsed, taskId: resolved.taskId };
94
- const base = `Review PR (Round ${identity.round})`;
95
- const started = activity.entries.filter((entry) => entry.step === `${base} [started]`);
96
- const terminal = activity.entries.filter((entry) => entry.step === base);
97
- if (started.length > 1 || terminal.length > 1) {
98
- return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `${base} has duplicate started or terminal rows`, taskId: resolved.taskId };
99
- }
100
- if (terminal.length === 1 && started.length === 0 && !terminal[0].note.startsWith('receipt ')) {
101
- return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `${base} has a terminal row without a matching started row`, taskId: resolved.taskId };
91
+ const started = pr.open?.artifact === identity.name ? pr.open : null;
92
+ const terminals = pr.terminals.filter((entry) => entry.artifact === identity.name);
93
+ if (terminals.length > 1)
94
+ return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `duplicate PR review terminal for ${identity.name}`, taskId: resolved.taskId };
95
+ const terminal = terminals[0];
96
+ if (terminal) {
97
+ const matches = (terminal.note.startsWith('Verdict: ') && LOCAL_COMPLETION_STATUSES.has(parsed.status))
98
+ || (terminal.note.startsWith('Outcome: Aborted, ') && parsed.status === 'aborted')
99
+ || (terminal.note.startsWith('Outcome: Superseded, ') && parsed.status === 'superseded')
100
+ || (terminal.note.startsWith('receipt ') && SUCCESS_STATUSES.has(parsed.status));
101
+ if (!matches)
102
+ return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `terminal note conflicts with artifact status ${parsed.status}`, taskId: resolved.taskId };
102
103
  }
103
- if (terminal.length === 1) {
104
- const note = terminal[0].note;
105
- const terminalMatchesStatus = (note.startsWith('Verdict: ') && LOCAL_COMPLETION_STATUSES.has(parsed.status))
106
- || (note.startsWith('Outcome: Aborted, ') && parsed.status === 'aborted')
107
- || (note.startsWith('Outcome: Superseded, ') && parsed.status === 'superseded')
108
- || (note.startsWith('receipt ') && SUCCESS_STATUSES.has(parsed.status));
109
- if (!terminalMatchesStatus) {
110
- return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: `${base} terminal note conflicts with artifact status ${parsed.status}`, taskId: resolved.taskId };
111
- }
112
- }
113
- states.push({
114
- ...parsed,
115
- startedAgent: started[0]?.agent ?? null,
116
- terminalAgent: terminal[0]?.agent ?? null,
117
- terminalNote: terminal[0]?.note ?? null
118
- });
104
+ if ((started && started.head !== parsed.head) || (terminal && terminal.head !== parsed.head))
105
+ return { ok: false, code: 'ACTIVITY_IDENTITY_MISMATCH', message: `head does not match ${identity.name}`, taskId: resolved.taskId };
106
+ states.push({ ...parsed, startedAgent: started?.agent ?? null, terminalAgent: terminal?.agent ?? null, terminalNote: terminal?.note ?? null });
119
107
  }
108
+ if ((pr.open && !states.some((state) => state.identity.name === pr.open.artifact)) || pr.terminals.some((entry) => !states.some((state) => state.identity.name === entry.artifact)))
109
+ return { ok: false, code: 'ACTIVITY_STATE_CONFLICT', message: 'PR review execution references a missing artifact', taskId: resolved.taskId };
120
110
  const openStates = states.filter((state) => state.startedAgent !== null && state.terminalNote === null);
121
111
  const preparedStates = states.filter((state) => state.status === 'pending' && state.startedAgent === null && state.terminalNote === null);
122
112
  if (openStates.length > 1 || preparedStates.length > 1) {
@@ -250,10 +240,16 @@ function applyActivityIntent(intent, normalizedAgent, options) {
250
240
  return failed(intent, 'METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), state.taskId);
251
241
  }
252
242
  const section = locateActivityLog(state.content);
253
- const mutations = [{
254
- kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading,
255
- body: appendActivityEntry(section, { time: metadata.timestamp, step, agent: normalizedAgent, note })
256
- }];
243
+ const pr = prReviewExecution(state.content);
244
+ if (intent.kind === 'pr-review-start')
245
+ pr.open = { artifact: intent.artifact, head: intent.head, agent: normalizedAgent, startedAt: metadata.timestamp };
246
+ else {
247
+ pr.open = null;
248
+ pr.terminals.push({ artifact: intent.artifact, head: intent.head, agent: normalizedAgent, note });
249
+ }
250
+ const mutations = [{ kind: 'frontmatter', lifecycleExecutionDomain: 'pr-review', set: { lifecycle_execution: serializeLifecycleExecution(lifecycleExecutions(state.content), state.content, pr) } }];
251
+ if (section)
252
+ mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body: appendActivityEntry(section, { time: metadata.timestamp, step, agent: normalizedAgent, note }) });
257
253
  if (linkArtifact) {
258
254
  const link = buildArtifactLinkSection(state.content, roundState.identity);
259
255
  mutations.push({ kind: 'section', aliases: link.aliases, heading: link.heading, body: link.body });
@@ -296,6 +292,15 @@ export function applyPrReviewActivityIntent(intent, options = {}) {
296
292
  if (resolved.state !== 'active') {
297
293
  return failed(intent, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
298
294
  }
299
- return applyActivityIntent(intent, validated.agent, { ...options, repoRoot: resolved.repoRoot });
295
+ let warnings = [];
296
+ try {
297
+ const inspected = inspectActivityLog(fs.readFileSync(resolved.taskMdPath, 'utf8'));
298
+ warnings = !inspected.section ? [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous' }] : inspected.invalidEntries.length ? [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries' }] : [];
299
+ }
300
+ catch { /* The operation reports read errors. */ }
301
+ const result = applyActivityIntent(intent, validated.agent, { ...options, repoRoot: resolved.repoRoot });
302
+ if (result.status === 'failed')
303
+ return result;
304
+ return warnings.length ? { ...result, warnings } : result;
300
305
  }
301
306
  //# sourceMappingURL=activity-intent.js.map
@@ -3,8 +3,6 @@ const ENTRY_RE = /^- (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}) — \*
3
3
  const STARTED_SUFFIX_RE = /\s*\[started\]\s*$/;
4
4
  const ABORTED_SUFFIX_RE = /\s*\[aborted\]\s*$/;
5
5
  const ATTEMPT_RE = /(?:^|;\s*)attempt=([A-Za-z0-9-]{8,64})(?:;|$)/;
6
- const COMMIT_STARTED_RE = /^started; attempt=([A-Za-z0-9-]{8,64}); baseline=([a-f0-9]{40,64}); agent=([a-z-]+)$/;
7
- const LIFECYCLE_STEP_RE = /^(?:Complete Manual Validation|(?:Analyze Task|Review Analysis|Plan Task|Review Plan|Code Task|Review Code|Run Manual Validation) \(Round [1-9]\d*(?:(?:, fix for review-code(?:-r[2-9]|-r[1-9]\d+)?\.md)|(?:, decision II-[1-9]\d*))?\))$/;
8
6
  function parseActivityLog(content) {
9
7
  const section = locateActivityLog(content);
10
8
  return section ? { sectionFound: true, entries: section.entries } : { sectionFound: false, entries: [] };
@@ -33,6 +31,14 @@ function inspectActivityLog(content) {
33
31
  const body = content.slice(heading.end + 1, end).replace(/\r\n/g, '\n').replace(/^\n+|\n+$/g, '');
34
32
  return { section: { heading: heading.text, body, entries }, invalidEntries };
35
33
  }
34
+ function activityWarnings(content) {
35
+ const inspected = inspectActivityLog(content);
36
+ if (!inspected.section)
37
+ return [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous; repair the section to resume logging' }];
38
+ if (inspected.invalidEntries.length)
39
+ return [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries; repair the entries' }];
40
+ return [];
41
+ }
36
42
  function locateActivityLog(content) {
37
43
  const { section } = inspectActivityLog(content);
38
44
  if (!section)
@@ -47,13 +53,6 @@ function appendActivityEntry(section, entry) {
47
53
  function activityAttempt(note) {
48
54
  return ATTEMPT_RE.exec(note)?.[1] ?? null;
49
55
  }
50
- function parseCommitAttemptStarted(note) {
51
- const match = COMMIT_STARTED_RE.exec(note);
52
- return match ? { attempt: match[1], baseline: match[2], agent: match[3] } : null;
53
- }
54
- function commitAttemptStartedNote(attempt) {
55
- return `started; attempt=${attempt.attempt}; baseline=${attempt.baseline}; agent=${attempt.agent}`;
56
- }
57
56
  function pairEntries(entries) {
58
57
  const rows = [];
59
58
  const open = new Map();
@@ -94,11 +93,5 @@ function pairEntries(entries) {
94
93
  function startedBackedRows(rows) {
95
94
  return rows.filter((row) => row.started !== '');
96
95
  }
97
- function hasOpenLifecycleExecution(content) {
98
- const section = locateActivityLog(content);
99
- if (!section)
100
- return false;
101
- return pairEntries(section.entries).some((row) => row.done === '' && LIFECYCLE_STEP_RE.test(row.step));
102
- }
103
- export { activityAttempt, appendActivityEntry, hasOpenLifecycleExecution, commitAttemptStartedNote, inspectActivityLog, locateActivityLog, pairEntries, parseActivityLog, parseCommitAttemptStarted, startedBackedRows };
96
+ export { activityAttempt, activityWarnings, appendActivityEntry, inspectActivityLog, locateActivityLog, pairEntries, parseActivityLog, startedBackedRows };
104
97
  //# sourceMappingURL=activity-log.js.map
@@ -88,7 +88,7 @@ export function executeArtifactCommand(command, options = {}) {
88
88
  }
89
89
  catch { /* an absent candidate is created only for the selected identity */ }
90
90
  if ((context.status !== 'ready' && !matchingInitializedSkeleton) || (context.next?.name !== artifact
91
- && !hasOpenArtifactRound(fs.readFileSync(resolved.taskMdPath, 'utf8'), family, parsed.round)
91
+ && !hasOpenArtifactRound(taskDir, fs.readFileSync(resolved.taskMdPath, 'utf8'), family, parsed.round)
92
92
  && !matchingInitializedSkeleton)) {
93
93
  return fail('ARTIFACT_INIT_CONTEXT_INVALID', context.error?.message ?? `artifact '${artifact}' is not the next ${family} artifact`);
94
94
  }
@@ -2,46 +2,42 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { ARTIFACT_FAMILY_CATALOG, artifactName, parseArtifactName } from './artifact-name.js';
4
4
  import { resolveTaskRef } from './resolve-ref.js';
5
- import { locateActivityLog, pairEntries, startedBackedRows } from './activity-log.js';
5
+ import { lifecycleExecutions } from './lifecycle-execution.js';
6
6
  import { parseImplementationInputs, selectPendingImplementationInput } from './implementation-inputs.js';
7
7
  import { parseTypedTaskFrontmatter } from './frontmatter.js';
8
8
  import { parseVerdict } from './review-artifacts.js';
9
9
  import { extractSection, findSectionHeading } from './sections.js';
10
10
  import { receiptForOutput, receiptsForOutput, sha256File } from './artifact-receipts.js';
11
- import { artifactCompletionOrder, hasArtifactCompletionFact, hasArtifactCompletionLog, parseCompletionFacts } from './completion-facts.js';
11
+ import { hasArtifactCompletionRecord, hasValidArtifactCompletion } from './completion-facts.js';
12
12
  import { inspectReviewIdentity } from './review-identity.js';
13
13
  import { parseLifecyclePathDecision } from './lifecycle-path.js';
14
14
  import { parseReworkIntentDocument } from './rework-intent.js';
15
15
  import { selectArtifactDisposition } from './artifact-selection.js';
16
16
  import { executionInputsMatchLatest } from './execution-inputs.js';
17
17
  const artifactFamilyCatalog = ARTIFACT_FAMILY_CATALOG;
18
- const ARTIFACT_STEPS = {
19
- analysis: 'Analyze Task', 'review-analysis': 'Review Analysis',
20
- plan: 'Plan Task', 'review-plan': 'Review Plan',
21
- code: 'Code Task', 'review-code': 'Review Code'
22
- };
23
18
  /** Init, repair and finalization share the same authoritative round identity. */
24
- export function hasOpenArtifactRound(content, family, round) {
25
- return openArtifactRounds(content, family).includes(round);
19
+ export function hasOpenArtifactRound(taskDir, content, family, round) {
20
+ return openArtifactRounds(taskDir, content, family).includes(round);
26
21
  }
27
- function openArtifactRounds(content, family) {
28
- const activity = locateActivityLog(content);
29
- const step = ARTIFACT_STEPS[family];
30
- if (!activity || !step)
31
- return [];
32
- const qualifier = family === 'code'
33
- ? '(?:, (?:fix for review-code(?:-r(?:[2-9]|[1-9]\\d+))?\\.md|decision II-[1-9]\\d*))?'
34
- : '';
35
- const expected = new RegExp(`^${step} \\(Round ([1-9]\\d*)${qualifier}\\)$`);
36
- return [...new Set(startedBackedRows(pairEntries(activity.entries))
37
- .filter((row) => expected.test(row.step) && !row.done)
38
- .map((row) => Number(expected.exec(row.step)?.[1])))].sort((left, right) => left - right);
22
+ function openArtifactRounds(taskDir, content, family) {
23
+ const executionFamily = family === 'analysis' ? 'analyze' : family;
24
+ const event = completionEvent(family);
25
+ return [...new Set(lifecycleExecutions(content)
26
+ .filter((item) => item.family === executionFamily && item.round !== undefined)
27
+ .flatMap((item) => {
28
+ const round = item.round;
29
+ const name = artifactName(family, round);
30
+ if (!event || !hasArtifactCompletionRecord(content, name, event))
31
+ return [round];
32
+ if (!hasValidArtifactCompletion(content, taskDir, name, event))
33
+ throw new Error(`completion evidence for started ${family} Round ${round} is invalid`);
34
+ return [];
35
+ }))].sort((left, right) => left - right);
39
36
  }
40
- function hasCompletedArtifactRound(content, family, round, name) {
37
+ function hasCompletedArtifactRound(taskDir, content, family, round, name) {
41
38
  const event = completionEvent(family);
42
39
  return Boolean(event && parseArtifactName(name)?.round === round
43
- && artifactCompletionOrder(content, name, event) !== null
44
- && hasArtifactCompletionFact(content, name, event));
40
+ && hasValidArtifactCompletion(content, taskDir, name, event));
45
41
  }
46
42
  function completionEvent(family) {
47
43
  if (family === 'analysis')
@@ -153,7 +149,16 @@ function inspectArtifactDirectory(taskDir, family, identity = {}) {
153
149
  }
154
150
  artifacts.sort((left, right) => left.round - right.round);
155
151
  knownArtifacts.sort((left, right) => left.round - right.round);
156
- const openRounds = openArtifactRounds(taskContent, family);
152
+ let openRounds;
153
+ try {
154
+ openRounds = openArtifactRounds(taskDir, taskContent, family);
155
+ }
156
+ catch (error) {
157
+ return failure(requestRef, family, {
158
+ code: 'ARTIFACT_SELECTION_INDETERMINATE',
159
+ message: error instanceof Error ? error.message : String(error)
160
+ }, { taskId: identity.taskId ?? null, taskDir, taskState: identity.taskState ?? null });
161
+ }
157
162
  const knownRounds = new Set(knownArtifacts.map((item) => item.round));
158
163
  for (const round of openRounds)
159
164
  knownRounds.add(round);
@@ -166,11 +171,8 @@ function inspectArtifactDirectory(taskDir, family, identity = {}) {
166
171
  }
167
172
  const event = completionEvent(family);
168
173
  const completed = event
169
- ? artifacts.flatMap((artifact) => {
170
- const order = artifactCompletionOrder(taskContent, artifact.name, event);
171
- return order !== null && hasArtifactCompletionFact(taskContent, artifact.path, event)
172
- ? [{ artifact, order }] : [];
173
- }).sort((left, right) => left.order - right.order).map(({ artifact }) => artifact)
174
+ ? artifacts.filter((artifact) => hasValidArtifactCompletion(taskContent, taskDir, artifact.name, event))
175
+ .sort((left, right) => left.round - right.round)
174
176
  : [];
175
177
  if (openRounds.length > 1)
176
178
  diagnostics.push(diagnostic('MULTIPLE_OPEN_ROUNDS', family, null, `multiple incomplete ${family} rounds are open: ${openRounds.join(', ')}`));
@@ -321,8 +323,8 @@ function hasSelectionEvidence(content, family, options, context, pathState) {
321
323
  const reportContent = fs.readFileSync(context.latest.path, 'utf8');
322
324
  const identity = inspectReviewIdentity(context.taskDir, reportContent, options.repoRoot);
323
325
  return identity.status !== 'matched'
324
- || !hasArtifactCompletionFact(content, context.latest.path, 'review-code.completed')
325
- || !hasArtifactCompletionLog(content, context.latest.name, 'review-code.completed');
326
+ || !context.taskDir
327
+ || !hasValidArtifactCompletion(content, context.taskDir, context.latest.name, 'review-code.completed');
326
328
  }
327
329
  catch {
328
330
  return true;
@@ -366,14 +368,11 @@ function attachArtifactSelection(context, pathState, options) {
366
368
  });
367
369
  if (!context.next)
368
370
  return fail('ARTIFACT_SELECTION_INDETERMINATE', 'artifact inventory did not provide a writable identity');
369
- let taskContent;
370
- try {
371
- taskContent = fs.readFileSync(path.join(context.taskDir, 'task.md'), 'utf8');
372
- }
373
- catch (error) {
374
- return fail('ARTIFACT_SELECTION_INDETERMINATE', error instanceof Error ? error.message : String(error));
375
- }
376
- const openRounds = openArtifactRounds(taskContent, family);
371
+ const state = readArtifactSelectionState(context.taskDir, family);
372
+ if (!state.ok)
373
+ return fail('ARTIFACT_SELECTION_INDETERMINATE', state.message);
374
+ const taskContent = state.content;
375
+ const openRounds = state.openRounds;
377
376
  if (openRounds.length > 1)
378
377
  return fail('ARTIFACT_TOPOLOGY_CONFLICT', `multiple incomplete ${family} rounds are open: ${openRounds.join(', ')}`);
379
378
  const openRound = openRounds[0] ?? null;
@@ -399,6 +398,15 @@ function attachArtifactSelection(context, pathState, options) {
399
398
  return fail('ARTIFACT_SELECTION_INDETERMINATE', error instanceof Error ? error.message : String(error));
400
399
  }
401
400
  }
401
+ function readArtifactSelectionState(taskDir, family) {
402
+ try {
403
+ const content = fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8');
404
+ return { ok: true, content, openRounds: openArtifactRounds(taskDir, content, family) };
405
+ }
406
+ catch (error) {
407
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
408
+ }
409
+ }
402
410
  function resolveArtifactContextFromTask(taskRef, family, options, resolvedTask) {
403
411
  const inventory = inspectTaskArtifacts(taskRef, family, options, resolvedTask);
404
412
  if (inventory.status === 'failed')
@@ -469,9 +477,6 @@ function resolveArtifactContextFromTask(taskRef, family, options, resolvedTask)
469
477
  function resolveArtifactContext(taskRef, family, options = {}) {
470
478
  return resolveArtifactContextFromTask(taskRef, family, options);
471
479
  }
472
- export function resolveArtifactContextForResolvedTask(resolvedTask, family, options = {}) {
473
- return resolveArtifactContextFromTask(resolvedTask.taskId, family, options, resolvedTask);
474
- }
475
480
  function resolveCodeContext(inventory, options, resolvedTask) {
476
481
  const taskRef = inventory.requestRef;
477
482
  const pathState = lifecyclePathState(inventory.taskDir);
@@ -486,8 +491,7 @@ function resolveCodeContext(inventory, options, resolvedTask) {
486
491
  const taskContent = fs.readFileSync(path.join(inventory.taskDir, 'task.md'), 'utf8');
487
492
  const hasPendingImplementation = parseImplementationInputs(taskContent).rows.some((input) => input.needsImplementation && input.status === 'pending');
488
493
  if (hasPendingImplementation && !reviewCode.latest) {
489
- const candidate = reviewCode.artifacts.at(-1)?.name ?? 'review-code.md';
490
- return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', `cannot find completed Activity Log identity for ${candidate}`);
494
+ return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', 'no valid review-code completion fact is available for pending implementation inputs');
491
495
  }
492
496
  }
493
497
  catch (error) {
@@ -508,12 +512,10 @@ function resolveCodeContext(inventory, options, resolvedTask) {
508
512
  const review = reviewCode.latest;
509
513
  const openInputs = review ? [...inputs, review] : inputs;
510
514
  const openVerdict = review ? parseVerdict(review.path) : null;
511
- const openRow = locateActivityLog(taskContent)
512
- ? startedBackedRows(pairEntries(locateActivityLog(taskContent).entries))
513
- .find((row) => row.step.startsWith(`Code Task (Round ${openRound}`) && !row.done)
514
- : null;
515
- const decisionInput = /, decision (II-[1-9]\d*)\)$/u.exec(openRow?.step ?? '')?.[1] ?? null;
516
- const fixInput = /, fix for (review-code(?:-r\d+)?\.md)\)$/u.exec(openRow?.step ?? '')?.[1] ?? null;
515
+ const openRow = lifecycleExecutions(taskContent)
516
+ .find((row) => row.family === 'code' && row.round === openRound);
517
+ const decisionInput = openRow?.implementationInput ?? null;
518
+ const fixInput = openRow?.fixFor ?? null;
517
519
  const mode = decisionInput ? 'decision'
518
520
  : fixInput || (openVerdict?.ok && openVerdict.verdict === 'Changes Requested') ? 'fix'
519
521
  : 'init';
@@ -544,7 +546,7 @@ function resolveCodeContext(inventory, options, resolvedTask) {
544
546
  const verdict = parseVerdict(review.path);
545
547
  if (!verdict.ok)
546
548
  return contextFailure(inventory, 'ARTIFACT_VERDICT_INVALID', `${verdict.code}: ${verdict.message}`, review.name);
547
- const decision = resolveDecisionImplementationInput(inventory, review);
549
+ const decision = resolveDecisionImplementationInput(reviewCode, review);
548
550
  if ('error' in decision)
549
551
  return contextFailure(inventory, 'ARTIFACT_REFERENCE_INVALID', decision.error, review.name);
550
552
  if (decision.input) {
@@ -598,12 +600,10 @@ function resolveDecisionImplementationInput(inventory, review) {
598
600
  const pending = rows.filter((row) => row.needsImplementation && row.status === 'pending');
599
601
  if (pending.length === 0)
600
602
  return { input: null };
601
- const activity = locateActivityLog(content);
602
- if (!activity)
603
- return { error: 'task has no unique Activity Log section' };
604
- const completed = activity.entries.some((entry) => /^Review Code \(Round \d+\)$/.test(entry.step) && entry.note.includes(`→ ${review.name}`));
605
- if (!completed)
606
- return { error: `cannot find completed Activity Log identity for ${review.name}` };
603
+ if (inventory.latest?.name !== review.name
604
+ || !inventory.completed.some((artifact) => artifact.name === review.name)) {
605
+ return { error: `Review Code completion facts do not validate ${review.name}` };
606
+ }
607
607
  try {
608
608
  return { input: selectPendingImplementationInput(rows) };
609
609
  }
@@ -653,14 +653,12 @@ export function validateArtifactPublication(taskDir, family, name) {
653
653
  if (existing) {
654
654
  try {
655
655
  const task = fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8');
656
- if (hasCompletedArtifactRound(task, family, existing.round, name)) {
656
+ if (hasCompletedArtifactRound(taskDir, task, family, existing.round, name)) {
657
657
  return { code: 'ARTIFACT_IDENTITY_INVALID', message: `completed artifact '${name}' is immutable` };
658
658
  }
659
659
  const event = completionEvent(family);
660
- const frontmatter = parseTypedTaskFrontmatter(task);
661
- const completionFactExists = event !== null && parseCompletionFacts(frontmatter.completion_facts)
662
- .some((fact) => fact.event === event && fact.output === name);
663
- if (event && completionFactExists && artifactCompletionOrder(task, name, event) !== null) {
660
+ const completionFactExists = event !== null && hasArtifactCompletionRecord(task, name, event);
661
+ if (event && completionFactExists) {
664
662
  return { code: 'ARTIFACT_IDENTITY_INVALID', message: `completion evidence for '${name}' does not match its current content` };
665
663
  }
666
664
  }
@@ -26,11 +26,5 @@ export function parseArtifactName(name) {
26
26
  return null;
27
27
  return { family: match[1], round, name };
28
28
  }
29
- export function maxArtifactRound(names, family) {
30
- return names.reduce((max, name) => {
31
- const identity = parseArtifactName(name);
32
- return identity?.family === family ? Math.max(max, identity.round) : max;
33
- }, 0);
34
- }
35
29
  export { ARTIFACT_FAMILY_CATALOG };
36
30
  //# sourceMappingURL=artifact-name.js.map
@@ -59,7 +59,7 @@ function stripHtmlComments(content) {
59
59
  function diagnostic(code, message, sectionId, line) {
60
60
  return { code, message, sectionId, line };
61
61
  }
62
- function sectionHeadings(schema, section) {
62
+ function sectionHeadings(section) {
63
63
  return [section.headings.zh, section.headings.en];
64
64
  }
65
65
  function canonicalContent(content) {
@@ -82,7 +82,7 @@ function inspectArtifactStructure(content, schema) {
82
82
  diagnostics.push(diagnostic('ARTIFACT_UNCLOSED_FENCE', 'artifact contains an unclosed Markdown fence', null, null));
83
83
  const headingsBySection = new Map();
84
84
  for (const section of schema.sections) {
85
- const aliases = sectionHeadings(schema, section);
85
+ const aliases = sectionHeadings(section);
86
86
  const exact = scanned.headings.filter((heading) => heading.level === 2 && aliases.includes(heading.text));
87
87
  const punctuated = scanned.headings.filter((heading) => heading.level === 2 && aliases.some((alias) => heading.text === `${alias}:` || heading.text === `${alias}:`));
88
88
  headingsBySection.set(section.id, exact.length > 0 ? exact : punctuated);
@@ -182,7 +182,7 @@ function inspectArtifactStateCheck(content, schema, scopeToStateCheckSection) {
182
182
  };
183
183
  }
184
184
  const scanned = scanVisibleMarkdown(content);
185
- const headings = scanned.headings.filter((heading) => (heading.level === 2 && sectionHeadings(schema, stateCheck).includes(heading.text)));
185
+ const headings = scanned.headings.filter((heading) => (heading.level === 2 && sectionHeadings(stateCheck).includes(heading.text)));
186
186
  if (headings.length !== 1) {
187
187
  return { ok: true, family: schema.family, semanticDigest: canonicalSemanticDigest(content), diagnostics: [] };
188
188
  }
@@ -7,11 +7,11 @@ import { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from '.
7
7
  import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.js';
8
8
  import { parseReworkIntentDocument } from './rework-intent.js';
9
9
  import { sha256File } from './artifact-receipts.js';
10
- import { hasOpenLifecycleExecution } from './activity-log.js';
10
+ import { lifecycleExecutions } from './lifecycle-execution.js';
11
11
  import { parseQualificationAudit, parseTaskQualification } from './qualification-audit.js';
12
12
  import { parseLifecyclePathDecision, pathIncludes } from './lifecycle-path.js';
13
13
  import { parseImplementationInputs } from './implementation-inputs.js';
14
- import { hasArtifactCompletionFact, hasArtifactCompletionLog } from './completion-facts.js';
14
+ import { hasValidArtifactCompletion } from './completion-facts.js';
15
15
  import { inspectReviewIdentity } from './review-identity.js';
16
16
  import { inspectArtifactDirectory } from './artifact-lifecycle.js';
17
17
  import { executionInputsMatchLatest as executionReceiptsMatchLatest } from './execution-inputs.js';
@@ -389,8 +389,7 @@ function buildLifecycleFacts(taskDir, content, taskState = 'active', executionBu
389
389
  if (family === 'review-code') {
390
390
  const identity = inspectReviewIdentity(taskDir, reviewContent, repositoryRoot);
391
391
  reviewCodeIdentityValid = identity.status === 'matched'
392
- && hasArtifactCompletionFact(content, path.join(taskDir, latest), 'review-code.completed')
393
- && hasArtifactCompletionLog(content, latest, 'review-code.completed');
392
+ && hasValidArtifactCompletion(content, taskDir, latest, 'review-code.completed');
394
393
  }
395
394
  const parsed = parseReviewSummary(reviewContent);
396
395
  if (!parsed.ok)
@@ -455,7 +454,7 @@ function buildLifecycleFacts(taskDir, content, taskState = 'active', executionBu
455
454
  reviewedInputs, executionInputs, artifactHashes,
456
455
  reworkIntents: rework.intents,
457
456
  unresolvedLedger,
458
- executionBusy: executionBusy || hasOpenLifecycleExecution(content),
457
+ executionBusy: lifecycleExecutions(content).some((item) => item.family !== 'other') || executionBusy,
459
458
  recommendedAction: null,
460
459
  qualificationStale: qualificationStaleArtifacts.length > 0,
461
460
  qualificationStaleArtifacts,
@@ -84,12 +84,6 @@ function humanValidationCount(note) {
84
84
  function isHumanCountField(field) {
85
85
  return fieldNumber(field, 'manual-validation') !== undefined || fieldNumber(field, 'human-decision') !== undefined;
86
86
  }
87
- // A step is human-executed when its agent token is not a known AI token.
88
- // Known long names classify as AI; empty or unknown tokens classify as non-AI
89
- // (human).
90
- export function isHumanAgent(agent) {
91
- return classifyAgent(agent).status !== 'ai';
92
- }
93
87
  // Fold the two human counts into a review row's verdict NOTE: comma-joined, right
94
88
  // after the blockers/major/minor list and before the ` → artifact` link, mirroring
95
89
  // the review count line. Review done notes already carry `Manual-validation` as a