@fitlab-ai/agent-infra 0.9.10 → 0.9.11

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 (269) hide show
  1. package/README.md +13 -3
  2. package/README.zh-CN.md +13 -3
  3. package/bin/cli.ts +17 -4
  4. package/dist/bin/cli.js +19 -4
  5. package/dist/bin/internal-cli.js +50 -4
  6. package/dist/lib/agent-client.js +0 -1
  7. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +0 -4
  8. package/dist/lib/agent-clients/adapters/traecli.js +7 -8
  9. package/dist/lib/agent-clients/config.js +14 -99
  10. package/dist/lib/agent-clients/reconcile.js +1 -11
  11. package/dist/lib/agent-clients/schema.js +5 -4
  12. package/dist/lib/agent-clients/tokens.js +5 -15
  13. package/dist/lib/decide.js +14 -30
  14. package/dist/lib/defaults.json +4 -0
  15. package/dist/lib/init.js +2 -2
  16. package/dist/lib/internal/release-workflow.js +0 -1
  17. package/dist/lib/internal/task-finalization.js +19 -9
  18. package/dist/lib/internal/task-ledger.js +8 -2
  19. package/dist/lib/internal/task-lifecycle.js +17 -93
  20. package/dist/lib/internal/task-orchestration.js +30 -216
  21. package/dist/lib/internal/task-validate.js +2 -1
  22. package/dist/lib/merge.js +205 -103
  23. package/dist/lib/process-data/normalize.js +2 -9
  24. package/dist/lib/run/host.js +46 -16
  25. package/dist/lib/sandbox/agent-client-reconciler.js +4 -12
  26. package/dist/lib/sandbox/commands/create.js +3 -3
  27. package/dist/lib/sandbox/commands/enter.js +18 -4
  28. package/dist/lib/sandbox/config.js +3 -12
  29. package/dist/lib/sandbox/control/executor.js +131 -39
  30. package/dist/lib/sandbox/control/lifecycle.js +29 -20
  31. package/dist/lib/sandbox/control/server.js +18 -16
  32. package/dist/lib/sandbox/mounts.js +3 -2
  33. package/dist/lib/sandbox/recovery.js +123 -22
  34. package/dist/lib/sandbox/workspace-identity.js +14 -0
  35. package/dist/lib/sandbox/workspace-view.js +8 -9
  36. package/dist/lib/self-update.js +278 -0
  37. package/dist/lib/server/protocol.js +5 -5
  38. package/dist/lib/task/activity-log.js +4 -1
  39. package/dist/lib/task/artifact-lifecycle.js +4 -2
  40. package/dist/lib/task/codex-orchestration.js +1 -1
  41. package/dist/lib/task/command-options.js +1 -3
  42. package/dist/lib/task/commands/cat.js +0 -5
  43. package/dist/lib/task/commands/decisions.js +76 -92
  44. package/dist/lib/task/commands/files.js +6 -6
  45. package/dist/lib/task/commands/grep.js +25 -61
  46. package/dist/lib/task/commands/issue-body.js +6 -6
  47. package/dist/lib/task/commands/log.js +25 -10
  48. package/dist/lib/task/commands/show.js +5 -6
  49. package/dist/lib/task/commands/status.js +8 -8
  50. package/dist/lib/task/commit-operation.js +21 -25
  51. package/dist/lib/task/commit-policy.js +1 -1
  52. package/dist/lib/task/control-authority.js +431 -0
  53. package/dist/lib/task/create.js +6 -1
  54. package/dist/lib/task/current-contract.js +35 -0
  55. package/dist/lib/task/decision-details.js +263 -0
  56. package/dist/lib/task/decision-intents.js +5 -2
  57. package/dist/lib/task/events.js +11 -5
  58. package/dist/lib/task/index.js +19 -20
  59. package/dist/lib/task/ledger-intents.js +8 -9
  60. package/dist/lib/task/ledger.js +13 -6
  61. package/dist/lib/task/lifecycle.js +16 -0
  62. package/dist/lib/task/orchestration.js +50 -13
  63. package/dist/lib/task/review-artifacts.js +31 -12
  64. package/dist/lib/task/review-finalization.js +19 -6
  65. package/dist/lib/task/verification-engine.js +38 -15
  66. package/dist/lib/task/verification-review.js +1 -1
  67. package/dist/lib/task/workspace-snapshot.js +5 -11
  68. package/dist/lib/task/write.js +11 -1
  69. package/dist/lib/update.js +6 -37
  70. package/dist/lib/version.js +5 -1
  71. package/dist/lifecycle-build-manifest.json +3 -3
  72. package/lib/agent-client.ts +0 -1
  73. package/lib/agent-clients/adapters/opencode-sandbox.ts +0 -5
  74. package/lib/agent-clients/adapters/traecli.ts +7 -8
  75. package/lib/agent-clients/config.ts +14 -144
  76. package/lib/agent-clients/reconcile.ts +1 -12
  77. package/lib/agent-clients/schema.ts +5 -4
  78. package/lib/agent-clients/tokens.ts +5 -18
  79. package/lib/decide.ts +12 -22
  80. package/lib/defaults.json +4 -0
  81. package/lib/init.ts +2 -2
  82. package/lib/internal/release-workflow.ts +0 -1
  83. package/lib/internal/task-finalization.ts +27 -13
  84. package/lib/internal/task-ledger.ts +8 -2
  85. package/lib/internal/task-lifecycle.ts +33 -76
  86. package/lib/internal/task-orchestration.ts +33 -190
  87. package/lib/internal/task-validate.ts +3 -2
  88. package/lib/merge.ts +236 -120
  89. package/lib/process-data/normalize.ts +2 -8
  90. package/lib/run/host.ts +63 -14
  91. package/lib/sandbox/agent-client-reconciler.ts +5 -15
  92. package/lib/sandbox/commands/create.ts +4 -4
  93. package/lib/sandbox/commands/enter.ts +24 -4
  94. package/lib/sandbox/config.ts +2 -14
  95. package/lib/sandbox/control/container-identity.ts +2 -2
  96. package/lib/sandbox/control/executor.ts +148 -51
  97. package/lib/sandbox/control/lifecycle.ts +34 -28
  98. package/lib/sandbox/control/protocol.ts +1 -3
  99. package/lib/sandbox/control/server.ts +15 -12
  100. package/lib/sandbox/control/state.ts +7 -7
  101. package/lib/sandbox/mounts.ts +4 -3
  102. package/lib/sandbox/recovery.ts +162 -34
  103. package/lib/sandbox/tools.ts +1 -1
  104. package/lib/sandbox/workspace-identity.ts +28 -0
  105. package/lib/sandbox/workspace-view.ts +14 -10
  106. package/lib/self-update.ts +341 -0
  107. package/lib/server/protocol.ts +5 -5
  108. package/lib/task/activity-log.ts +6 -1
  109. package/lib/task/artifact-lifecycle.ts +5 -3
  110. package/lib/task/codex-orchestration.ts +2 -1
  111. package/lib/task/command-options.ts +1 -2
  112. package/lib/task/commands/cat.ts +0 -4
  113. package/lib/task/commands/decisions.ts +80 -75
  114. package/lib/task/commands/files.ts +6 -6
  115. package/lib/task/commands/grep.ts +23 -51
  116. package/lib/task/commands/issue-body.ts +6 -6
  117. package/lib/task/commands/log.ts +22 -10
  118. package/lib/task/commands/show.ts +5 -6
  119. package/lib/task/commands/status.ts +8 -8
  120. package/lib/task/commit-operation.ts +25 -30
  121. package/lib/task/commit-policy.ts +1 -2
  122. package/lib/task/control-authority.ts +563 -0
  123. package/lib/task/create.ts +6 -1
  124. package/lib/task/current-contract.ts +49 -0
  125. package/lib/task/decision-details.ts +340 -0
  126. package/lib/task/decision-intents.ts +7 -2
  127. package/lib/task/events.ts +10 -5
  128. package/lib/task/index.ts +19 -20
  129. package/lib/task/ledger-intents.ts +6 -8
  130. package/lib/task/ledger.ts +17 -7
  131. package/lib/task/lifecycle.ts +20 -0
  132. package/lib/task/orchestration.ts +40 -15
  133. package/lib/task/review-artifacts.ts +53 -15
  134. package/lib/task/review-finalization.ts +33 -7
  135. package/lib/task/verification-engine.ts +33 -18
  136. package/lib/task/verification-review.ts +1 -1
  137. package/lib/task/workspace-snapshot.ts +4 -13
  138. package/lib/task/write.ts +20 -1
  139. package/lib/update.ts +6 -40
  140. package/lib/version.ts +6 -1
  141. package/package.json +1 -1
  142. package/templates/.agents/README.en.md +5 -3
  143. package/templates/.agents/README.zh-CN.md +5 -3
  144. package/templates/.agents/rules/compatibility-policy.en.md +5 -4
  145. package/templates/.agents/rules/compatibility-policy.zh-CN.md +5 -4
  146. package/templates/.agents/rules/create-issue.github.en.md +1 -1
  147. package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
  148. package/templates/.agents/rules/human-decision-context.en.md +9 -7
  149. package/templates/.agents/rules/human-decision-context.zh-CN.md +9 -7
  150. package/templates/.agents/rules/issue-fields.github.en.md +1 -1
  151. package/templates/.agents/rules/issue-fields.github.zh-CN.md +1 -1
  152. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  153. package/templates/.agents/rules/issue-pr-commands.github.en.md +1 -1
  154. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +1 -1
  155. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  156. package/templates/.agents/rules/issue-sync.github.en.md +1 -1
  157. package/templates/.agents/rules/issue-sync.github.zh-CN.md +2 -2
  158. package/templates/.agents/rules/milestone-inference.github.en.md +1 -1
  159. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +1 -1
  160. package/templates/.agents/rules/next-step-output.en.md +3 -3
  161. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -3
  162. package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -1
  163. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -1
  164. package/templates/.agents/rules/pr-sync.en.md +1 -1
  165. package/templates/.agents/rules/pr-sync.github.en.md +1 -1
  166. package/templates/.agents/rules/pr-sync.github.zh-CN.md +1 -1
  167. package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
  168. package/templates/.agents/rules/release-commands.github.en.md +6 -0
  169. package/templates/.agents/rules/release-commands.github.zh-CN.md +6 -0
  170. package/templates/.agents/rules/review-handshake.en.md +1 -1
  171. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  172. package/templates/.agents/rules/task-management.en.md +1 -2
  173. package/templates/.agents/rules/task-management.zh-CN.md +1 -2
  174. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  175. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  176. package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
  177. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
  178. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  179. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  180. package/templates/.agents/skills/check-task/SKILL.en.md +2 -2
  181. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +2 -2
  182. package/templates/.agents/skills/close-codescan/SKILL.en.md +1 -1
  183. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +1 -1
  184. package/templates/.agents/skills/close-dependabot/SKILL.en.md +1 -1
  185. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +1 -1
  186. package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
  187. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
  188. package/templates/.agents/skills/commit/SKILL.en.md +27 -7
  189. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -4
  190. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +5 -5
  191. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -5
  192. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  193. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  194. package/templates/.agents/skills/create-pr/SKILL.en.md +5 -7
  195. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +5 -7
  196. package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -4
  197. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -4
  198. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +203 -0
  199. package/templates/.agents/skills/create-release-note/SKILL.en.md +5 -6
  200. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +5 -6
  201. package/templates/.agents/skills/create-task/SKILL.en.md +1 -1
  202. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
  203. package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
  204. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
  205. package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
  206. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
  207. package/templates/.agents/skills/restore-task/SKILL.en.md +1 -1
  208. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +1 -1
  209. package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -3
  210. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -3
  211. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -0
  212. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -0
  213. package/templates/.agents/skills/review-code/SKILL.en.md +5 -3
  214. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -3
  215. package/templates/.agents/skills/review-code/config/verify.en.json +1 -0
  216. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -0
  217. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +2 -1
  218. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +2 -1
  219. package/templates/.agents/skills/review-plan/SKILL.en.md +5 -3
  220. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -3
  221. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -0
  222. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -0
  223. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +4 -0
  224. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +4 -0
  225. package/templates/.agents/skills/run-task/SKILL.en.md +4 -0
  226. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +4 -0
  227. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
  228. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
  229. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +140 -109
  230. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  231. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  232. package/templates/.agents/templates/task.en.md +1 -1
  233. package/templates/.agents/templates/task.zh-CN.md +1 -1
  234. package/templates/.claude/commands/analyze-task.en.md +1 -1
  235. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  236. package/templates/.claude/commands/block-task.en.md +1 -1
  237. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  238. package/templates/.claude/commands/cancel-task.en.md +1 -1
  239. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  240. package/templates/.claude/commands/check-task.en.md +1 -1
  241. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  242. package/templates/.claude/commands/code-task.en.md +1 -1
  243. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  244. package/templates/.claude/commands/commit.en.md +1 -1
  245. package/templates/.claude/commands/commit.zh-CN.md +1 -1
  246. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  247. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  248. package/templates/.claude/commands/complete-task.en.md +1 -1
  249. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  250. package/templates/.claude/commands/create-pr.en.md +1 -1
  251. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  252. package/templates/.claude/commands/plan-task.en.md +1 -1
  253. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  254. package/templates/.claude/commands/review-analysis.en.md +1 -1
  255. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  256. package/templates/.claude/commands/review-code.en.md +1 -1
  257. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  258. package/templates/.claude/commands/review-plan.en.md +1 -1
  259. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  260. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  261. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  262. package/templates/.claude/commands/run-task.en.md +1 -1
  263. package/templates/.claude/commands/run-task.zh-CN.md +1 -1
  264. package/templates/.claude/commands/watch-pr.en.md +1 -1
  265. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  266. package/templates/{.trae/skills → .traecli/commands}/update-agent-infra.en.md +0 -1
  267. package/templates/{.trae/skills → .traecli/commands}/update-agent-infra.zh-CN.md +0 -1
  268. package/dist/lib/builtin-tuis.js +0 -40
  269. package/lib/builtin-tuis.ts +0 -56
@@ -159,27 +159,46 @@ function finalizeReviewSummaryContent(content, counts) {
159
159
  content: content.slice(0, parsed.findingsStart) + line + content.slice(parsed.findingsEnd)
160
160
  };
161
161
  }
162
+ function resolveCanonicalVerdict(summary) {
163
+ if (summary.counts === null) {
164
+ return {
165
+ ok: false,
166
+ verdict: null,
167
+ code: 'REVIEW_FINDING_COUNTS_NOT_FINALIZED',
168
+ message: 'review summary finding counts are not finalized'
169
+ };
170
+ }
171
+ if (summary.verdict === 'Approved' && !equalCounts(summary.counts, { blocker: 0, major: 0, minor: 0 })) {
172
+ return {
173
+ ok: false,
174
+ verdict: null,
175
+ code: 'REVIEW_VERDICT_FINDING_MISMATCH',
176
+ message: 'Approved verdict requires zero finalized findings'
177
+ };
178
+ }
179
+ return { ok: true, verdict: summary.verdict };
180
+ }
162
181
  function parseVerdict(reviewPath) {
163
182
  if (!fs.existsSync(reviewPath)) {
164
- return { ok: false, verdict: null, message: `Review artifact not found: ${path.basename(reviewPath)}` };
183
+ return { ok: false, verdict: null, code: 'REVIEW_ARTIFACT_NOT_FOUND', message: `Review artifact not found: ${path.basename(reviewPath)}` };
184
+ }
185
+ let content;
186
+ try {
187
+ content = fs.readFileSync(reviewPath, 'utf8');
188
+ }
189
+ catch (error) {
190
+ return { ok: false, verdict: null, code: 'REVIEW_ARTIFACT_READ_FAILED', message: `Review artifact could not be read: ${String(error)}` };
165
191
  }
166
- const parsed = parseReviewSummary(fs.readFileSync(reviewPath, 'utf8'));
192
+ const parsed = parseReviewSummary(content);
167
193
  if (!parsed.ok) {
168
194
  return {
169
195
  ok: false,
170
196
  verdict: null,
197
+ code: parsed.code === 'REVIEW_SUMMARY_PLACEHOLDER_INVALID' ? parsed.code : 'REVIEW_SUMMARY_NOT_FOUND',
171
198
  message: `cannot parse review summary in ${path.basename(reviewPath)}: ${parsed.message}`
172
199
  };
173
200
  }
174
- const { verdict, counts } = parsed.summary;
175
- if (verdict !== 'Approved')
176
- return { ok: true, verdict };
177
- return {
178
- ok: true,
179
- verdict: counts && equalCounts(counts, { blocker: 0, major: 0, minor: 0 })
180
- ? 'Approved'
181
- : 'Approved-with-issues'
182
- };
201
+ return resolveCanonicalVerdict(parsed.summary);
183
202
  }
184
- export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict };
203
+ export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict, resolveCanonicalVerdict };
185
204
  //# sourceMappingURL=review-artifacts.js.map
@@ -1,10 +1,11 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { locateActivityLog, pairEntries } from './activity-log.js';
4
+ import { locateActivityLog, pairEntries, startedBackedRows } from './activity-log.js';
5
5
  import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
6
- import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
6
+ import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
7
7
  import { finalizeReviewSummaryContent } from './review-artifacts.js';
8
+ import { inspectDecisionDetailDuplicates, repairDecisionDetailDuplicates } from './decision-details.js';
8
9
  import { resolveTaskRef } from './resolve-ref.js';
9
10
  import { validateLifecycleExecution } from './lifecycle-execution.js';
10
11
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
@@ -40,7 +41,7 @@ function openReviewRound(content, action, round) {
40
41
  if (!section)
41
42
  return false;
42
43
  const expected = `${action} (Round ${round})`;
43
- return pairEntries(section.entries).filter((row) => (row.step === expected && Boolean(row.started) && !row.done)).length === 1;
44
+ return startedBackedRows(pairEntries(section.entries)).filter((row) => (row.step === expected && !row.done)).length === 1;
44
45
  }
45
46
  function cleanupTemp(fileSystem, tempPath) {
46
47
  try {
@@ -103,7 +104,11 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
103
104
  }
104
105
  let rows;
105
106
  try {
106
- rows = parseLedger(taskContent);
107
+ const ledger = parseLedgerDocument(taskContent);
108
+ if (!ledger.present) {
109
+ return failed(request, 'REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`, resolved.taskId);
110
+ }
111
+ rows = ledger.rows;
107
112
  }
108
113
  catch (error) {
109
114
  return failed(request, 'REVIEW_LEDGER_INVALID', String(error), resolved.taskId);
@@ -113,11 +118,19 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
113
118
  return failed(request, 'REVIEW_LEDGER_INVALID', `${ledgerError.code}: ${ledgerError.message}`, resolved.taskId);
114
119
  }
115
120
  const stageStatus = summarizeLedgerStage(rows, stage);
116
- const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
121
+ const repaired = repairDecisionDetailDuplicates(artifactContent);
122
+ if (!repaired.ok) {
123
+ return failed(request, 'REVIEW_DECISION_DETAIL_INVALID', `${repaired.code}: ${repaired.message}`, resolved.taskId, stageStatus);
124
+ }
125
+ const detailInspection = inspectDecisionDetailDuplicates(repaired.content);
126
+ if (!detailInspection.ok) {
127
+ return failed(request, 'REVIEW_DECISION_DETAIL_INVALID', `${detailInspection.code}: ${detailInspection.message}`, resolved.taskId, stageStatus);
128
+ }
129
+ const transformed = finalizeReviewSummaryContent(repaired.content, stageStatus.unresolvedFindingCounts);
117
130
  if (!transformed.ok) {
118
131
  return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
119
132
  }
120
- if (!transformed.changed) {
133
+ if (!repaired.changed && !transformed.changed) {
121
134
  return {
122
135
  ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
123
136
  status: 'no-op',
@@ -12,8 +12,10 @@ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-requ
12
12
  import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
13
13
  import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
14
14
  import { parseTypedTaskFrontmatter } from "./frontmatter.js";
15
- import { parseLedger, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
15
+ import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
16
+ import { isValidAgentInfraVersion } from "../version.js";
16
17
  import { equalCounts, parseReviewSummary } from "./review-artifacts.js";
18
+ import { inspectDecisionDetailDuplicates } from "./decision-details.js";
17
19
  import { loadVerificationConfig } from "./verification-config.js";
18
20
  import { snapshotReview } from "../git/review-snapshot.js";
19
21
  import { OrchestrationStateError, readRun } from "./orchestration.js";
@@ -34,7 +36,6 @@ const DEFAULT_REQUIRED_FIELDS = [
34
36
  "assigned_to"
35
37
  ];
36
38
  const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
37
- const AGENT_INFRA_VERSION_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
38
39
  const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
39
40
  // Start markers (action suffixed with ` [started]`) are excluded from the
40
41
  // "latest action" / freshness computation so a step's in-flight marker never
@@ -89,6 +90,8 @@ function runCheck(type, context, shared) {
89
90
  return checkTaskMeta(context);
90
91
  case "artifact":
91
92
  return checkArtifact(context);
93
+ case "decision-details":
94
+ return checkDecisionDetails(context);
92
95
  case "implementation-input":
93
96
  return checkImplementationInput(context);
94
97
  case "activity-log":
@@ -352,18 +355,17 @@ function checkTaskMeta({ taskDir, config }) {
352
355
  const metadata = task.metadata;
353
356
  const requiredFields = config.required_fields || DEFAULT_REQUIRED_FIELDS;
354
357
  const missingFields = requiredFields.filter((field) => isBlank(metadata[field]));
355
- const blockingMissingFields = missingFields.filter((field) => field !== "agent_infra_version");
358
+ const currentTask = metadata.status === 'active';
359
+ const blockingMissingFields = missingFields.filter((field) => field !== "agent_infra_version" || currentTask);
356
360
  const warnings = [];
357
- if (missingFields.includes("agent_infra_version")) {
361
+ if (missingFields.includes("agent_infra_version") && !currentTask) {
358
362
  warnings.push("field 'agent_infra_version' missing — historical task or skipped version stamp");
359
363
  }
360
364
  if (blockingMissingFields.length > 0) {
361
365
  return failResult("task-meta", `Missing required fields: ${blockingMissingFields.join(", ")}`);
362
366
  }
363
- if (!isBlank(metadata.agent_infra_version) &&
364
- metadata.agent_infra_version !== "unknown" &&
365
- !AGENT_INFRA_VERSION_PATTERN.test(metadata.agent_infra_version)) {
366
- return failResult("task-meta", `Invalid agent_infra_version: ${metadata.agent_infra_version}`);
367
+ if (currentTask && !isValidAgentInfraVersion(metadata.agent_infra_version)) {
368
+ return failResult("task-meta", `Invalid agent_infra_version: ${String(metadata.agent_infra_version ?? 'missing')}`);
367
369
  }
368
370
  const invalidDates = ["created_at", "updated_at", "completed_at", "blocked_at", "cancelled_at"]
369
371
  .filter((field) => !isBlank(metadata[field]) && !DATE_TIME_PATTERN.test(metadata[field]));
@@ -527,6 +529,21 @@ function checkArtifact({ taskDir, config, artifactFile }) {
527
529
  }
528
530
  return passResult("artifact", `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`);
529
531
  }
532
+ function checkDecisionDetails({ taskDir, artifactFile }) {
533
+ const resolvedArtifact = resolveArtifactPath(taskDir, "", artifactFile);
534
+ if (!resolvedArtifact.ok)
535
+ return failResult("decision-details", resolvedArtifact.message);
536
+ const artifactPath = resolvedArtifact.path;
537
+ const stat = safeStat(artifactPath);
538
+ if (!stat?.isFile())
539
+ return failResult("decision-details", `Artifact not found: ${path.basename(artifactPath)}`);
540
+ if (stat.size === 0)
541
+ return passResult("decision-details", `${path.basename(artifactPath)} contains no decision details`);
542
+ const inspection = inspectDecisionDetailDuplicates(fs.readFileSync(artifactPath, "utf8"));
543
+ if (!inspection.ok)
544
+ return failResult("decision-details", `${path.basename(artifactPath)}: ${inspection.message}`);
545
+ return passResult("decision-details", `${path.basename(artifactPath)} has no duplicate decision detail ids`);
546
+ }
530
547
  function checkReviewSummary({ taskDir, config, artifactFile }) {
531
548
  const stage = String(config.stage || "");
532
549
  if (!["analysis", "plan", "code"].includes(stage)) {
@@ -547,7 +564,10 @@ function checkReviewSummary({ taskDir, config, artifactFile }) {
547
564
  return failResult("review-summary", task.message);
548
565
  let rows;
549
566
  try {
550
- rows = parseLedger(task.content);
567
+ const ledger = parseLedgerDocument(task.content);
568
+ if (!ledger.present)
569
+ return failResult("review-summary", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
570
+ rows = ledger.rows;
551
571
  }
552
572
  catch (error) {
553
573
  return failResult("review-summary", `Invalid disagreement ledger: ${String(error)}`);
@@ -817,13 +837,12 @@ function checkReviewLedger({ taskDir, config }) {
817
837
  if (!task.ok) {
818
838
  return failResult("review-ledger", task.message);
819
839
  }
820
- const section = getSectionContent(task.content, LEDGER_SECTION_NAMES);
821
- if (!section.trim()) {
822
- return passResult("review-ledger", "No disagreement ledger section; treated as no open disagreements");
823
- }
824
840
  let rows;
825
841
  try {
826
- rows = parseLedger(task.content).map((row) => [
842
+ const ledger = parseLedgerDocument(task.content);
843
+ if (!ledger.present)
844
+ return failResult("review-ledger", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
845
+ rows = ledger.rows.map((row) => [
827
846
  row.id, row.stage, row.round, row.severity, row.status, row.evidence
828
847
  ]);
829
848
  }
@@ -1068,7 +1087,11 @@ function formatPostReviewExemptions(exemptions) {
1068
1087
  }
1069
1088
  function resolvePostReviewExemption(content) {
1070
1089
  try {
1071
- const rows = parseLedger(content);
1090
+ const ledger = parseLedgerDocument(content);
1091
+ if (!ledger.present) {
1092
+ return { ok: false, code: "POST_REVIEW_EXEMPTION_INVALID", message: `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}` };
1093
+ }
1094
+ const rows = ledger.rows;
1072
1095
  const invalid = validateLedgerRows(rows);
1073
1096
  if (invalid) {
1074
1097
  return {
@@ -1,3 +1,3 @@
1
1
  export { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
2
- export { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
2
+ export { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
3
3
  //# sourceMappingURL=verification-review.js.map
@@ -26,12 +26,6 @@ function captureWorktreeTree(repoRoot, forcedPath) {
26
26
  fs.rmSync(tempDir, { recursive: true, force: true });
27
27
  }
28
28
  }
29
- function captureLegacyWorkspaceSnapshot(repoRoot, taskId) {
30
- const workspaceRelative = taskId
31
- ? `.agents/workspace/active/${taskId}`
32
- : '.agents/workspace/active';
33
- return captureWorktreeTree(repoRoot, workspaceRelative);
34
- }
35
29
  function taskFileFingerprints(stateRoot, taskId) {
36
30
  const activeRoot = path.join(stateRoot, '.agents', 'workspace', 'active');
37
31
  const roots = taskId ? [path.join(activeRoot, taskId)] : [activeRoot];
@@ -46,6 +40,8 @@ function taskFileFingerprints(stateRoot, taskId) {
46
40
  }
47
41
  if (!stat.isFile() && !stat.isSymbolicLink())
48
42
  return;
43
+ if (relative.startsWith('.agents/workspace/active/') && path.posix.basename(relative) === 'orchestration.json')
44
+ return;
49
45
  const content = stat.isSymbolicLink()
50
46
  ? Buffer.from(fs.readlinkSync(absolute))
51
47
  : fs.readFileSync(absolute);
@@ -81,13 +77,11 @@ function decodeWorkspaceFingerprint(value) {
81
77
  throw new Error(`ORCHESTRATION_SNAPSHOT_FAILED: ${error instanceof Error ? error.message : String(error)}`);
82
78
  }
83
79
  }
84
- function captureWorkspaceSnapshot(contextOrRoot, taskId) {
85
- if (typeof contextOrRoot === 'string')
86
- return captureLegacyWorkspaceSnapshot(contextOrRoot, taskId ?? null);
80
+ function captureWorkspaceSnapshot(context) {
87
81
  return encodeWorkspaceFingerprint({
88
82
  version: 2,
89
- gitTree: captureWorktreeTree(contextOrRoot.gitRoot, null),
90
- taskFiles: taskFileFingerprints(contextOrRoot.stateRoot, contextOrRoot.taskId)
83
+ gitTree: captureWorktreeTree(context.gitRoot, null),
84
+ taskFiles: taskFileFingerprints(context.stateRoot, context.taskId)
91
85
  });
92
86
  }
93
87
  function captureRepositorySnapshot(repoRoot) {
@@ -1,10 +1,11 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { VERSION } from '../version.js';
3
+ import { isValidAgentInfraVersion, VERSION } from '../version.js';
4
4
  import { parseTypedTaskFrontmatter, updateTaskFrontmatter } from './frontmatter.js';
5
5
  import { resolveTaskRef } from './resolve-ref.js';
6
6
  import { allowsManualOverride } from './guard-override.js';
7
7
  import { mutateTableRow, upsertSection } from './sections.js';
8
+ import { validateCurrentTaskContract } from './current-contract.js';
8
9
  const DEFAULT_FILE_SYSTEM = {
9
10
  readFileSync: (file) => fs.readFileSync(file, 'utf8'),
10
11
  statModeSync: (file) => fs.statSync(file).mode,
@@ -84,6 +85,12 @@ function writeTask(request, options = {}) {
84
85
  catch (error) {
85
86
  return failure(request, identity, 'TASK_READ_FAILED', error instanceof Error ? error.message : String(error));
86
87
  }
88
+ if (resolved.state === 'active') {
89
+ const contract = validateCurrentTaskContract(original);
90
+ if (!contract.ok) {
91
+ return failure(request, identity, contract.code, contract.message);
92
+ }
93
+ }
87
94
  let candidate = original;
88
95
  const operations = [];
89
96
  try {
@@ -154,6 +161,9 @@ function writeTask(request, options = {}) {
154
161
  catch (error) {
155
162
  return failure(request, identity, 'METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), operations);
156
163
  }
164
+ if (resolved.state === 'active' && !isValidAgentInfraVersion(metadata.agentInfraVersion)) {
165
+ return failure(request, identity, 'TASK_CURRENT_CONTRACT_INVALID', `metadata agentInfraVersion must be a valid v-prefixed semver (received ${metadata.agentInfraVersion})`, operations, metadata);
166
+ }
157
167
  if (candidate === original) {
158
168
  return {
159
169
  status: 'no-op',
@@ -8,27 +8,9 @@ import { renderFile, copySkillDir } from './render.js';
8
8
  const defaults = JSON.parse(fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8'));
9
9
  const CONFIG_DIR = '.agents';
10
10
  const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
11
- // One-time migration of the legacy project-level PR switch to the three-state
12
- // `prFlow` preference. `true` (the old default / "PR flow on") maps to the
13
- // strong constraint `required`; `false` maps to `disabled`. A missing or
14
- // already-migrated config is left untouched (idempotent). Returns the new
15
- // prFlow value when a migration happened, otherwise null.
16
- function migratePrFlow(config) {
17
- if (config.requiresPullRequest === true) {
18
- delete config.requiresPullRequest;
19
- config.prFlow = 'required';
20
- return 'required';
21
- }
22
- if (config.requiresPullRequest === false) {
23
- delete config.requiresPullRequest;
24
- config.prFlow = 'disabled';
25
- return 'disabled';
26
- }
27
- return null;
28
- }
29
- async function cmdUpdate() {
11
+ async function cmdSync() {
30
12
  console.log('');
31
- console.log(' ai update');
13
+ console.log(' ai sync');
32
14
  console.log(' ==================================');
33
15
  console.log('');
34
16
  // check config exists
@@ -61,7 +43,6 @@ async function cmdUpdate() {
61
43
  const sandboxAdded = !config.sandbox;
62
44
  const taskAdded = !config.task;
63
45
  const labelsAdded = !config.labels;
64
- const prFlowMigrated = migratePrFlow(config);
65
46
  if (platformAdded)
66
47
  config.platform = structuredClone(defaults.platform);
67
48
  if (sandboxAdded)
@@ -78,19 +59,13 @@ async function cmdUpdate() {
78
59
  platformType,
79
60
  language
80
61
  });
81
- info(`Updating seed files for: ${project}`);
62
+ info(`Syncing seed files for: ${project}`);
82
63
  console.log('');
83
64
  // update skill
84
65
  copySkillDir(path.join(templateDir, '.agents', 'skills', 'update-agent-infra'), path.join('.agents', 'skills', 'update-agent-infra'), replacements, language, platformType);
85
66
  ok('Updated .agents/skills/update-agent-infra/');
86
67
  renderFile(path.join(templateDir, '.agents', 'scripts', 'lib', 'agent-infra-package.js'), path.join('.agents', 'scripts', 'lib', 'agent-infra-package.js'), replacements);
87
68
  ok('Updated .agents/scripts/lib/agent-infra-package.js');
88
- try {
89
- fs.unlinkSync(path.join('.agents', 'skills', 'update-agent-infra', 'scripts', 'sync-templates.cjs'));
90
- }
91
- catch {
92
- // Ignore missing legacy script from pre-ESM installs.
93
- }
94
69
  const added = {
95
70
  managed: workflowPlan.projectAssets.registry.managed.filter((entry) => !currentRegistry.managed.includes(entry)),
96
71
  merged: workflowPlan.projectAssets.registry.merged.filter((entry) => !currentRegistry.merged.includes(entry))
@@ -110,7 +85,7 @@ async function cmdUpdate() {
110
85
  ok(` merged: ${entry}`);
111
86
  }
112
87
  }
113
- else if (platformAdded || sandboxAdded || taskAdded || labelsAdded || prFlowMigrated) {
88
+ else if (platformAdded || sandboxAdded || taskAdded || labelsAdded) {
114
89
  if (platformAdded) {
115
90
  info(`Default platform config added to ${CONFIG_PATH}.`);
116
91
  }
@@ -123,9 +98,6 @@ async function cmdUpdate() {
123
98
  if (labelsAdded) {
124
99
  info(`Default labels.in config added to ${CONFIG_PATH}.`);
125
100
  }
126
- if (prFlowMigrated) {
127
- info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
128
- }
129
101
  }
130
102
  else {
131
103
  info(`File registry changed in ${CONFIG_PATH}.`);
@@ -142,14 +114,11 @@ async function cmdUpdate() {
142
114
  if (hasNewEntries && platformAdded) {
143
115
  info(`Default platform config added to ${CONFIG_PATH}.`);
144
116
  }
145
- if (hasNewEntries && prFlowMigrated) {
146
- info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
147
- }
148
117
  ok(`Updated ${CONFIG_PATH}`);
149
118
  }
150
119
  // done
151
120
  console.log('');
152
- ok('Seed files updated successfully!');
121
+ ok('Seed files synced successfully!');
153
122
  console.log('');
154
123
  if (workflowPlan.nextSteps.length === 0) {
155
124
  console.log(' No Agent Client project integration enabled.');
@@ -165,5 +134,5 @@ async function cmdUpdate() {
165
134
  console.log('');
166
135
  }
167
136
  }
168
- export { cmdUpdate };
137
+ export { cmdSync };
169
138
  //# sourceMappingURL=update.js.map
@@ -8,5 +8,9 @@ if (!packageJsonUrl) {
8
8
  }
9
9
  const { version } = JSON.parse(readFileSync(packageJsonUrl, 'utf8'));
10
10
  const VERSION = `v${version}`;
11
- export { VERSION };
11
+ const AGENT_INFRA_VERSION_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
12
+ function isValidAgentInfraVersion(value) {
13
+ return typeof value === 'string' && AGENT_INFRA_VERSION_PATTERN.test(value);
14
+ }
15
+ export { VERSION, isValidAgentInfraVersion };
12
16
  //# sourceMappingURL=version.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "protocolVersion": 3,
3
- "packageVersion": "0.9.10",
4
- "sourceInputHash": "fae928c7a46686dd39f9f57424e3caff8aed3ce5de5700475b4a3a8f2954b3a3",
5
- "internalExecutableBuildHash": "a5e143239a8fdd93c4696125aab04b28d7baf59c2a65488705fe930d4965f354"
3
+ "packageVersion": "0.9.11",
4
+ "sourceInputHash": "00e07caf1313615df10d46ae620767d7d15c3cc59712c1da581623057b87e0a6",
5
+ "internalExecutableBuildHash": "8a481b1d79da5e5f31ef79cd3428f1b51df2b859e70724e50dcc5910f8ee40c6"
6
6
  }
@@ -128,7 +128,6 @@ async function cmdAgentClient(args: string[]): Promise<number> {
128
128
  throw new AgentClientCommandError('AGENT_CLIENT_ARGUMENT_INVALID', 'status accepts no arguments');
129
129
  }
130
130
  const plan = workflowPlan(projectRoot, config, { type: 'none' });
131
- process.stdout.write(`source: ${plan.source}\n`);
132
131
  printState(plan.desired);
133
132
  for (const seed of plan.seedOperations) {
134
133
  process.stdout.write(` seed ${seed.target}: ${seed.kind}\n`);
@@ -33,14 +33,9 @@ function ensureOpenCodeSandboxState(
33
33
  const canonicalConfigDir = path.join(toolDir, '.xdg', 'config', 'opencode');
34
34
  const canonicalStateDir = path.join(toolDir, '.xdg', 'state', 'opencode');
35
35
  const canonicalConfigPath = path.join(canonicalConfigDir, 'opencode.json');
36
- const legacyConfigPath = path.join(toolDir, 'opencode.json');
37
36
  fs.mkdirSync(canonicalConfigDir, { recursive: true });
38
37
  fs.mkdirSync(canonicalStateDir, { recursive: true });
39
38
 
40
- if (!fs.existsSync(canonicalConfigPath) && fs.existsSync(legacyConfigPath)) {
41
- fs.copyFileSync(legacyConfigPath, canonicalConfigPath, fs.constants.COPYFILE_EXCL);
42
- }
43
-
44
39
  const hostConfigRoot = resolveXdgRoot(
45
40
  hostEnv.XDG_CONFIG_HOME,
46
41
  path.join(hostHome, '.config')
@@ -25,22 +25,21 @@ const traecliAdapter = defineAgentClientAdapter({
25
25
  actualReasoningEffort: 'unavailable'
26
26
  },
27
27
  project: {
28
- ownedPathPrefixes: ['.trae/'],
29
- managed: ['.trae/skills/'],
28
+ ownedPathPrefixes: ['.traecli/'],
29
+ managed: ['.traecli/commands/'],
30
30
  merged: [],
31
31
  ejected: [],
32
32
  seedCommands: [{
33
33
  templates: {
34
- en: '.trae/skills/update-agent-infra.en.md',
35
- 'zh-CN': '.trae/skills/update-agent-infra.zh-CN.md'
34
+ en: '.traecli/commands/update-agent-infra.en.md',
35
+ 'zh-CN': '.traecli/commands/update-agent-infra.zh-CN.md'
36
36
  },
37
- target: '.trae/skills/update-agent-infra.md'
37
+ target: '.traecli/commands/update-agent-infra.md'
38
38
  }],
39
39
  customCommand: {
40
- target: '.trae/skills/${skillName}.md',
40
+ target: '.traecli/commands/${skillName}.md',
41
41
  frontmatter: {},
42
- includeUsage: true,
43
- inheritDisableModelInvocation: true
42
+ argumentsToken: '$ARGUMENTS'
44
43
  }
45
44
  },
46
45
  sandbox: {