@fitlab-ai/agent-infra 0.9.2 → 0.9.4

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 (428) hide show
  1. package/README.md +12 -9
  2. package/README.zh-CN.md +12 -9
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +134 -108
  6. package/dist/lib/agent-clients/adapter.js +137 -4
  7. package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
  8. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  9. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  10. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  11. package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
  12. package/dist/lib/agent-clients/adapters/codex.js +9 -0
  13. package/dist/lib/agent-clients/adapters/index.js +2 -2
  14. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  15. package/dist/lib/agent-clients/adapters/opencode.js +24 -3
  16. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  17. package/dist/lib/agent-clients/config.js +42 -4
  18. package/dist/lib/agent-clients/next-steps.js +11 -2
  19. package/dist/lib/agent-clients/reconcile.js +2 -1
  20. package/dist/lib/agent-clients/registry.js +16 -2
  21. package/dist/lib/agent-clients/schema.js +18 -0
  22. package/dist/lib/agent-clients/tokens.js +49 -0
  23. package/dist/lib/agent-clients/types.js +1 -1
  24. package/dist/lib/defaults.json +1 -1
  25. package/dist/lib/git/workflow.js +54 -1
  26. package/dist/lib/internal/agent-client.js +61 -4
  27. package/dist/lib/internal/git-workflow.js +6 -1
  28. package/dist/lib/internal/platform-checks.js +3 -3
  29. package/dist/lib/internal/platform-comment.js +29 -2
  30. package/dist/lib/internal/platform-issue.js +7 -0
  31. package/dist/lib/internal/platform-pr-review.js +132 -0
  32. package/dist/lib/internal/platform-pr.js +20 -2
  33. package/dist/lib/internal/platform-release-notes.js +52 -16
  34. package/dist/lib/internal/pr-review-grade.js +140 -0
  35. package/dist/lib/internal/release-workflow.js +13 -6
  36. package/dist/lib/internal/sandbox-control.js +24 -0
  37. package/dist/lib/internal/task-activity.js +105 -0
  38. package/dist/lib/internal/task-event.js +17 -1
  39. package/dist/lib/internal/task-ledger.js +12 -3
  40. package/dist/lib/internal/task-lifecycle.js +26 -1
  41. package/dist/lib/internal/task-orchestration.js +167 -18
  42. package/dist/lib/internal/task-review.js +8 -3
  43. package/dist/lib/platform/adapters.js +8 -1
  44. package/dist/lib/platform/completion-backfill.js +122 -0
  45. package/dist/lib/platform/github-client.js +19 -2
  46. package/dist/lib/platform/issue-comments.js +3 -2
  47. package/dist/lib/platform/merged-pr-equivalence.js +115 -5
  48. package/dist/lib/platform/pr-checks.js +65 -42
  49. package/dist/lib/platform/pr-review.js +166 -0
  50. package/dist/lib/platform/pull-requests.js +371 -4
  51. package/dist/lib/platform/release-notes.js +85 -3
  52. package/dist/lib/platform/releases.js +13 -5
  53. package/dist/lib/pr-review/evidence-grading.js +229 -0
  54. package/dist/lib/process-data/index.js +239 -0
  55. package/dist/lib/process-data/normalize.js +198 -0
  56. package/dist/lib/process-data/privacy.js +33 -0
  57. package/dist/lib/process-data/reconcile.js +95 -0
  58. package/dist/lib/process-data/repair.js +58 -0
  59. package/dist/lib/process-data/sources.js +345 -0
  60. package/dist/lib/process-data/store.js +282 -0
  61. package/dist/lib/process-data/types.js +2 -0
  62. package/dist/lib/run/index.js +4 -3
  63. package/dist/lib/run/tui.js +10 -13
  64. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  65. package/dist/lib/sandbox/capture.js +7 -2
  66. package/dist/lib/sandbox/commands/create.js +109 -248
  67. package/dist/lib/sandbox/commands/enter.js +15 -47
  68. package/dist/lib/sandbox/commands/list-running.js +16 -6
  69. package/dist/lib/sandbox/commands/ls.js +10 -6
  70. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  71. package/dist/lib/sandbox/commands/refresh.js +4 -84
  72. package/dist/lib/sandbox/commands/rm.js +24 -3
  73. package/dist/lib/sandbox/commands/show.js +13 -4
  74. package/dist/lib/sandbox/commands/start.js +7 -4
  75. package/dist/lib/sandbox/config.js +2 -0
  76. package/dist/lib/sandbox/constants.js +6 -0
  77. package/dist/lib/sandbox/control/client.js +44 -0
  78. package/dist/lib/sandbox/control/protocol.js +35 -0
  79. package/dist/lib/sandbox/control/server.js +109 -0
  80. package/dist/lib/sandbox/dockerfile.js +36 -13
  81. package/dist/lib/sandbox/mounts.js +17 -4
  82. package/dist/lib/sandbox/recovery.js +128 -5
  83. package/dist/lib/sandbox/redaction.js +12 -0
  84. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  85. package/dist/lib/sandbox/workspace-identity.js +95 -0
  86. package/dist/lib/sandbox/workspace-view.js +103 -0
  87. package/dist/lib/task/activity-intent.js +307 -0
  88. package/dist/lib/task/artifact-lifecycle.js +2 -1
  89. package/dist/lib/task/commands/log.js +15 -14
  90. package/dist/lib/task/commit-finalization.js +267 -0
  91. package/dist/lib/task/commit-intent.js +165 -0
  92. package/dist/lib/task/decision-intents.js +31 -17
  93. package/dist/lib/task/delegation-receipts.js +25 -4
  94. package/dist/lib/task/events.js +67 -28
  95. package/dist/lib/task/finalization-artifacts.js +35 -0
  96. package/dist/lib/task/implementation-inputs.js +54 -7
  97. package/dist/lib/task/ledger-intents.js +35 -1
  98. package/dist/lib/task/lifecycle-execution.js +46 -0
  99. package/dist/lib/task/orchestration.js +753 -54
  100. package/dist/lib/task/resolve-ref.js +41 -1
  101. package/dist/lib/task/review-finalization.js +29 -9
  102. package/dist/lib/task/task-execution-lock.js +231 -0
  103. package/dist/lib/task/verification-checks.js +1 -1
  104. package/dist/lib/task/verification-engine.js +218 -2
  105. package/dist/lib/task/verification.js +4 -3
  106. package/dist/lib/task/workspace-snapshot.js +17 -5
  107. package/lib/agent-clients/adapter.ts +201 -4
  108. package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
  109. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  110. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  111. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  112. package/lib/agent-clients/adapters/claude-code.ts +31 -4
  113. package/lib/agent-clients/adapters/codex.ts +9 -0
  114. package/lib/agent-clients/adapters/index.ts +2 -2
  115. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  116. package/lib/agent-clients/adapters/opencode.ts +27 -3
  117. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  118. package/lib/agent-clients/config.ts +49 -4
  119. package/lib/agent-clients/next-steps.ts +15 -2
  120. package/lib/agent-clients/reconcile.ts +2 -1
  121. package/lib/agent-clients/registry.ts +19 -1
  122. package/lib/agent-clients/schema.ts +18 -0
  123. package/lib/agent-clients/tokens.ts +53 -0
  124. package/lib/agent-clients/types.ts +15 -1
  125. package/lib/defaults.json +1 -1
  126. package/lib/git/workflow.ts +66 -2
  127. package/lib/internal/agent-client.ts +59 -4
  128. package/lib/internal/git-workflow.ts +5 -1
  129. package/lib/internal/platform-checks.ts +4 -4
  130. package/lib/internal/platform-comment.ts +17 -2
  131. package/lib/internal/platform-issue.ts +4 -0
  132. package/lib/internal/platform-pr-review.ts +104 -0
  133. package/lib/internal/platform-pr.ts +14 -1
  134. package/lib/internal/platform-release-notes.ts +59 -16
  135. package/lib/internal/pr-review-grade.ts +130 -0
  136. package/lib/internal/release-workflow.ts +13 -6
  137. package/lib/internal/sandbox-control.ts +24 -0
  138. package/lib/internal/task-activity.ts +91 -0
  139. package/lib/internal/task-event.ts +9 -1
  140. package/lib/internal/task-ledger.ts +12 -3
  141. package/lib/internal/task-lifecycle.ts +26 -1
  142. package/lib/internal/task-orchestration.ts +123 -14
  143. package/lib/internal/task-review.ts +8 -3
  144. package/lib/platform/adapters.ts +29 -2
  145. package/lib/platform/completion-backfill.ts +134 -0
  146. package/lib/platform/github-client.ts +20 -2
  147. package/lib/platform/issue-comments.ts +3 -2
  148. package/lib/platform/merged-pr-equivalence.ts +127 -5
  149. package/lib/platform/pr-checks.ts +73 -46
  150. package/lib/platform/pr-review.ts +201 -0
  151. package/lib/platform/pull-requests.ts +444 -3
  152. package/lib/platform/release-notes.ts +100 -4
  153. package/lib/platform/releases.ts +16 -4
  154. package/lib/pr-review/evidence-grading.ts +318 -0
  155. package/lib/process-data/index.ts +224 -0
  156. package/lib/process-data/normalize.ts +202 -0
  157. package/lib/process-data/privacy.ts +41 -0
  158. package/lib/process-data/reconcile.ts +110 -0
  159. package/lib/process-data/repair.ts +64 -0
  160. package/lib/process-data/sources.ts +354 -0
  161. package/lib/process-data/store.ts +315 -0
  162. package/lib/process-data/types.ts +135 -0
  163. package/lib/run/index.ts +5 -3
  164. package/lib/run/tui.ts +14 -12
  165. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  166. package/lib/sandbox/capture.ts +9 -2
  167. package/lib/sandbox/commands/create.ts +126 -280
  168. package/lib/sandbox/commands/enter.ts +13 -59
  169. package/lib/sandbox/commands/list-running.ts +23 -6
  170. package/lib/sandbox/commands/ls.ts +22 -6
  171. package/lib/sandbox/commands/rebuild.ts +4 -3
  172. package/lib/sandbox/commands/refresh.ts +4 -126
  173. package/lib/sandbox/commands/rm.ts +24 -3
  174. package/lib/sandbox/commands/show.ts +30 -4
  175. package/lib/sandbox/commands/start.ts +6 -4
  176. package/lib/sandbox/config.ts +4 -0
  177. package/lib/sandbox/constants.ts +8 -0
  178. package/lib/sandbox/control/client.ts +55 -0
  179. package/lib/sandbox/control/protocol.ts +75 -0
  180. package/lib/sandbox/control/server.ts +117 -0
  181. package/lib/sandbox/dockerfile.ts +66 -13
  182. package/lib/sandbox/mounts.ts +24 -4
  183. package/lib/sandbox/recovery.ts +163 -6
  184. package/lib/sandbox/redaction.ts +14 -0
  185. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  186. package/lib/sandbox/tool-types.ts +16 -0
  187. package/lib/sandbox/workspace-identity.ts +123 -0
  188. package/lib/sandbox/workspace-view.ts +143 -0
  189. package/lib/server/server.schema.json +2 -2
  190. package/lib/task/activity-intent.ts +417 -0
  191. package/lib/task/artifact-lifecycle.ts +2 -1
  192. package/lib/task/commands/log.ts +15 -14
  193. package/lib/task/commit-finalization.ts +356 -0
  194. package/lib/task/commit-intent.ts +230 -0
  195. package/lib/task/decision-intents.ts +32 -12
  196. package/lib/task/delegation-receipts.ts +34 -5
  197. package/lib/task/events.ts +75 -30
  198. package/lib/task/finalization-artifacts.ts +58 -0
  199. package/lib/task/implementation-inputs.ts +62 -8
  200. package/lib/task/ledger-intents.ts +43 -3
  201. package/lib/task/lifecycle-execution.ts +106 -0
  202. package/lib/task/orchestration.ts +1019 -72
  203. package/lib/task/resolve-ref.ts +46 -1
  204. package/lib/task/review-finalization.ts +40 -9
  205. package/lib/task/task-execution-lock.ts +296 -0
  206. package/lib/task/verification-checks.ts +1 -1
  207. package/lib/task/verification-engine.ts +249 -2
  208. package/lib/task/verification.ts +5 -3
  209. package/lib/task/workspace-snapshot.ts +26 -5
  210. package/package.json +3 -3
  211. package/templates/.agents/QUICKSTART.en.md +25 -8
  212. package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
  213. package/templates/.agents/README.en.md +10 -7
  214. package/templates/.agents/README.zh-CN.md +10 -7
  215. package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
  216. package/templates/.agents/rules/README.en.md +1 -1
  217. package/templates/.agents/rules/README.zh-CN.md +1 -1
  218. package/templates/.agents/rules/create-issue.github.en.md +4 -2
  219. package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
  220. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  221. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  222. package/templates/.agents/rules/issue-fields.github.en.md +3 -1
  223. package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
  224. package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
  225. package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
  226. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
  227. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
  228. package/templates/.agents/rules/issue-sync.github.en.md +7 -3
  229. package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
  230. package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
  231. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
  232. package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
  233. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
  234. package/templates/.agents/rules/next-step-output.en.md +3 -1
  235. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
  236. package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
  237. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
  238. package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
  239. package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
  240. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
  241. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
  242. package/templates/.agents/rules/pr-sync.en.md +3 -1
  243. package/templates/.agents/rules/pr-sync.github.en.md +11 -1
  244. package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
  245. package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
  246. package/templates/.agents/rules/release-commands.en.md +1 -1
  247. package/templates/.agents/rules/release-commands.github.en.md +12 -2
  248. package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
  249. package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
  250. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  251. package/templates/.agents/rules/task-management.en.md +13 -0
  252. package/templates/.agents/rules/task-management.zh-CN.md +13 -0
  253. package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
  254. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
  255. package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
  256. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
  257. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
  258. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
  259. package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
  260. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
  261. package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
  262. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
  263. package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
  264. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
  265. package/templates/.agents/skills/commit/SKILL.en.md +23 -11
  266. package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
  267. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  268. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  269. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
  270. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
  271. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  272. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  273. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  274. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  275. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  276. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  277. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
  279. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  280. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  281. package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
  282. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
  283. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  284. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  285. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
  286. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
  287. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
  288. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
  289. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  290. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  291. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
  292. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
  293. package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
  294. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
  295. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  296. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  297. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
  298. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
  299. package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
  300. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
  301. package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
  302. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
  303. package/templates/.agents/skills/release/SKILL.en.md +16 -10
  304. package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
  305. package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
  306. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
  307. package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
  308. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
  309. package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
  310. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
  311. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  312. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  313. package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
  314. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
  315. package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
  316. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
  317. package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
  318. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
  319. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
  320. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
  321. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
  322. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
  323. package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
  324. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
  325. package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
  326. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
  327. package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
  328. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
  329. package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
  330. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
  331. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
  332. package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
  333. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
  334. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
  335. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
  336. package/templates/.agents/templates/task.en.md +2 -2
  337. package/templates/.agents/templates/task.zh-CN.md +2 -2
  338. package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
  339. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
  340. package/templates/.agents/workflows/code-review.en.yaml +1 -1
  341. package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
  342. package/templates/.agents/workflows/feature-development.en.yaml +4 -4
  343. package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
  344. package/templates/.agents/workflows/refactoring.en.yaml +3 -3
  345. package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
  346. package/templates/.claude/commands/post-release.en.md +1 -0
  347. package/templates/.claude/commands/post-release.zh-CN.md +1 -0
  348. package/templates/.claude/commands/review-pr.en.md +8 -0
  349. package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
  350. package/templates/.claude/commands/watch-pr.en.md +1 -1
  351. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  352. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  353. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  354. package/templates/.opencode/commands/post-release.en.md +2 -0
  355. package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
  356. package/templates/.opencode/commands/review-pr.en.md +11 -0
  357. package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
  358. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  359. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  360. package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
  361. package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
  362. package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
  363. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
  364. package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
  365. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
  366. package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
  367. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
  368. package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
  369. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
  370. package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
  371. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
  372. package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
  373. package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
  374. package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
  375. package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
  376. package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
  377. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
  378. package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
  379. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
  380. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
  381. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
  382. package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
  383. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
  384. package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
  385. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
  386. package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
  387. package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
  388. package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
  389. package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
  390. package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
  391. package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
  392. package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
  393. package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
  394. package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
  395. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
  396. package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
  397. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
  398. package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
  399. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
  400. package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
  401. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
  402. package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
  403. package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
  404. package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
  405. package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
  406. package/templates/.gemini/commands/_project_/release.en.toml +0 -8
  407. package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
  408. package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
  409. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
  410. package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
  411. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
  412. package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
  413. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
  414. package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
  415. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
  416. package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
  417. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
  418. package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
  419. package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
  420. package/templates/.gemini/commands/_project_/test.en.toml +0 -6
  421. package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
  422. package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
  423. package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
  424. package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
  425. package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
  426. package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
  427. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
  428. package/templates/.gemini/settings.json +0 -3
@@ -0,0 +1,229 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parseTaskFrontmatter } from '../task/frontmatter.js';
4
+ export class HostResolutionError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.name = 'HostResolutionError';
9
+ this.code = code;
10
+ }
11
+ }
12
+ function toPositiveNumber(value) {
13
+ const n = Number(value);
14
+ return Number.isInteger(n) && n > 0 ? n : null;
15
+ }
16
+ /**
17
+ * Parse the PR body for closing-issue references. Handles the conventional
18
+ * `Closes #1` / `Fixes: #2, #3` shapes (case-insensitive, comma/space
19
+ * separated, optional keyword list on the same logical line).
20
+ */
21
+ export function extractClosingIssueNumbers(body) {
22
+ const result = [];
23
+ const seen = new Set();
24
+ const linePattern = /(?:^|\n)[^\n]*\b(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\b[^\n]*/gi;
25
+ let lineMatch;
26
+ while ((lineMatch = linePattern.exec(body)) !== null) {
27
+ const line = lineMatch[0];
28
+ for (const numMatch of line.matchAll(/#(\d+)/g)) {
29
+ const n = Number(numMatch[1]);
30
+ if (Number.isInteger(n) && n > 0 && !seen.has(n)) {
31
+ seen.add(n);
32
+ result.push(n);
33
+ }
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ /**
39
+ * Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
40
+ * PR number or to one of the PR's closing issues. A task is emitted at most once;
41
+ * a direct `pr_number` hit takes priority over the issue-number reverse lookup.
42
+ */
43
+ export function collectHostCandidates(input) {
44
+ const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
45
+ const candidates = [];
46
+ let entries;
47
+ try {
48
+ entries = fs.readdirSync(activeRoot, { withFileTypes: true });
49
+ }
50
+ catch {
51
+ return [];
52
+ }
53
+ for (const entry of entries) {
54
+ if (!entry.isDirectory())
55
+ continue;
56
+ const taskDir = path.join(activeRoot, entry.name);
57
+ const taskMdPath = path.join(taskDir, 'task.md');
58
+ let content;
59
+ try {
60
+ content = fs.readFileSync(taskMdPath, 'utf8');
61
+ }
62
+ catch {
63
+ continue;
64
+ }
65
+ const frontmatter = parseTaskFrontmatter(content);
66
+ const issueNumber = toPositiveNumber(frontmatter.issue_number);
67
+ const prNumber = toPositiveNumber(frontmatter.pr_number);
68
+ if (prNumber === input.prNumber) {
69
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
70
+ }
71
+ else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
72
+ candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
73
+ }
74
+ }
75
+ return candidates;
76
+ }
77
+ /**
78
+ * Collapse a candidate list into a typed HostResolution. Zero candidates ->
79
+ * none; exactly one -> unique; more than one (no stable selection rule) ->
80
+ * ambiguous (fail closed, AN-6).
81
+ */
82
+ export function resolveHostFromCandidates(candidates) {
83
+ if (candidates.length === 0)
84
+ return { kind: 'none' };
85
+ if (candidates.length === 1) {
86
+ const candidate = candidates[0];
87
+ return {
88
+ kind: 'unique',
89
+ taskId: candidate.taskId,
90
+ taskDir: candidate.taskDir,
91
+ issueNumber: candidate.issueNumber ?? 0,
92
+ prNumber: candidate.prNumber ?? 0
93
+ };
94
+ }
95
+ return {
96
+ kind: 'ambiguous',
97
+ candidates: candidates.map((candidate) => ({ taskId: candidate.taskId, issueNumber: candidate.issueNumber ?? 0 }))
98
+ };
99
+ }
100
+ function hasNoLifecycleArtifacts(presence) {
101
+ return !presence.hasAnalysis && !presence.hasPlan && !presence.hasCode &&
102
+ !presence.hasReviewAnalysis && !presence.hasReviewPlan && !presence.hasReviewCode &&
103
+ !presence.hasPriorPrReview;
104
+ }
105
+ function hasFullArtifacts(presence) {
106
+ return presence.hasAnalysis && presence.hasPlan && presence.hasCode &&
107
+ presence.hasReviewAnalysis && presence.hasReviewPlan && presence.hasReviewCode;
108
+ }
109
+ function isTrusted(head) {
110
+ return head.issueNumberBound && head.taskIssueMatches && (!head.prNumberBound || head.taskPrMatches);
111
+ }
112
+ /**
113
+ * Derive the S1(a) trust factor `taskIssueMatches` (PL-3) mechanically from
114
+ * resolved data: a unique host is trusted on the issue dimension only when the
115
+ * task's bound issue_number is among the PR's closing issues. Ambiguous/none
116
+ * hosts and tasks without a positive issue_number cannot be confirmed -> false
117
+ * (fail closed to S2/audit). `resolve-host` emits this value so the prompt layer
118
+ * does not derive the trust factor ad hoc (CD-2).
119
+ */
120
+ export function deriveTaskIssueMatches(host, closingIssues) {
121
+ return host.kind === 'unique' && host.issueNumber > 0 && closingIssues.includes(host.issueNumber);
122
+ }
123
+ /**
124
+ * S1 -> S2 -> S3 classification (analysis §6.1). The ambiguous host is rejected
125
+ * before classification (AN-6 fail closed). S3(a) is host.kind === 'none';
126
+ * S3(b) is a unique task with no lifecycle artifacts and no prior pr-review
127
+ * (PL-5/PL-9 symmetric: any review-only task falls to S2).
128
+ */
129
+ export function classifyScenario(host, presence, head) {
130
+ if (host.kind === 'ambiguous') {
131
+ throw new HostResolutionError('HOST_AMBIGUOUS', 'multiple candidate hosts; resolve before evidence classification');
132
+ }
133
+ if (host.kind === 'none')
134
+ return 'S3';
135
+ if (hasNoLifecycleArtifacts(presence))
136
+ return 'S3';
137
+ const priorHeadMatches = presence.hasPriorPrReview && head.priorHeadSha !== null && head.priorHeadSha === head.currentHeadSha;
138
+ if (hasFullArtifacts(presence) && priorHeadMatches && isTrusted(head))
139
+ return 'S1';
140
+ return 'S2';
141
+ }
142
+ /**
143
+ * Freshness is benchmarked against the prior `pr-review*` reviewed head SHA
144
+ * (analysis §6.2, AN-7). No prior review -> n/a/n/a (first-review special case).
145
+ */
146
+ export function evaluateHead(head) {
147
+ if (head.priorHeadSha === null)
148
+ return { freshness: 'n/a', alignment: 'n/a' };
149
+ const freshness = head.priorHeadSha === head.currentHeadSha ? 'fresh' : 'stale';
150
+ const aligned = freshness === 'fresh' && isTrusted(head);
151
+ return { freshness, alignment: aligned ? 'aligned' : 'misaligned' };
152
+ }
153
+ /**
154
+ * Pure-evidence risk aggregation (analysis §6.3, AN-5): any priority factor
155
+ * (sensitivity / sourceCredibility) HIGH -> HIGH; otherwise any HIGH -> MEDIUM;
156
+ * all LOW -> LOW. Identity factors are structurally absent from the input type.
157
+ */
158
+ export function gradeRisk(factors) {
159
+ const priority = [factors.sensitivity, factors.sourceCredibility];
160
+ if (priority.includes('HIGH'))
161
+ return 'HIGH';
162
+ const values = Object.values(factors);
163
+ if (values.includes('HIGH'))
164
+ return 'MEDIUM';
165
+ return 'LOW';
166
+ }
167
+ /**
168
+ * verify / audit / reconstruct selection matrix (analysis §6.4). S3 ->
169
+ * reconstruct; S2 -> audit; S1 fresh+aligned -> verify (LOW/MEDIUM risk) or
170
+ * audit (HIGH risk); any other S1 combination falls back to audit.
171
+ */
172
+ export function selectMode(scenario, freshness, alignment, risk) {
173
+ if (scenario === 'S3')
174
+ return 'reconstruct';
175
+ if (scenario === 'S2')
176
+ return 'audit';
177
+ if (freshness === 'fresh' && alignment === 'aligned') {
178
+ return risk === 'HIGH' ? 'audit' : 'verify';
179
+ }
180
+ return 'audit';
181
+ }
182
+ function buildReason(input) {
183
+ const pieces = [];
184
+ if (input.firstReview)
185
+ pieces.push('first review (no prior pr-review head)');
186
+ if (input.hasPriorPrReview)
187
+ pieces.push(`prior head ${input.freshness}`);
188
+ if (input.freshness === 'fresh')
189
+ pieces.push(`alignment ${input.alignment}`);
190
+ pieces.push(`evidence scenario ${input.scenario}`);
191
+ pieces.push(`risk ${input.risk}`);
192
+ pieces.push(`mode ${input.mode}`);
193
+ return pieces.join('; ');
194
+ }
195
+ /**
196
+ * Full decision pipeline: classify -> freshness/alignment -> risk -> mode,
197
+ * producing a traceable DecisionRecord (AC3). Ambiguous hosts are rejected
198
+ * before any classification runs (AN-6).
199
+ */
200
+ export function decide(input) {
201
+ if (input.host.kind === 'ambiguous') {
202
+ throw new HostResolutionError('HOST_AMBIGUOUS', 'ambiguous host; resolve before evidence classification');
203
+ }
204
+ const scenario = classifyScenario(input.host, input.presence, input.head);
205
+ const { freshness, alignment } = evaluateHead(input.head);
206
+ const risk = gradeRisk(input.riskFactors);
207
+ const mode = selectMode(scenario, freshness, alignment, risk);
208
+ const firstReview = !input.presence.hasPriorPrReview;
209
+ return {
210
+ host: input.host,
211
+ scenario,
212
+ freshness,
213
+ alignment,
214
+ risk,
215
+ mode,
216
+ firstReview,
217
+ reason: buildReason({
218
+ scenario,
219
+ freshness,
220
+ alignment,
221
+ risk,
222
+ mode,
223
+ firstReview,
224
+ hasPriorPrReview: input.presence.hasPriorPrReview
225
+ })
226
+ };
227
+ }
228
+ export { hasFullArtifacts, hasNoLifecycleArtifacts, isTrusted };
229
+ //# sourceMappingURL=evidence-grading.js.map
@@ -0,0 +1,239 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { detectRepoRoot } from '../task/resolve-ref.js';
5
+ import { normalizeObjects } from './normalize.js';
6
+ import { reconcileRecords } from './reconcile.js';
7
+ import { readAppliedOverlays, repairSnapshot } from './repair.js';
8
+ import { collectGitHubObjects, collectLocalObjects } from './sources.js';
9
+ import { canonicalJsonBytes, createObjectStore, publishSnapshot, verifySnapshot } from './store.js';
10
+ const USAGE = `Usage: ai data <command> [options]
11
+
12
+ Commands:
13
+ capture [--source all|local|github] [--root <dir>] [--include-excerpts]
14
+ verify <snapshot-id> [--root <dir>]
15
+ audit <snapshot-id> [--root <dir>] [--format json|text]
16
+ repair <snapshot-id> [--root <dir>] [--apply]
17
+ export <snapshot-id> [--root <dir>] [--repairs none|applied] [--output <file|->]
18
+ `;
19
+ function parseArgs(args, valueOptions, booleanOptions) {
20
+ const positionals = [];
21
+ const options = new Map();
22
+ for (let index = 0; index < args.length; index += 1) {
23
+ const arg = args[index];
24
+ if (!arg.startsWith('--')) {
25
+ positionals.push(arg);
26
+ continue;
27
+ }
28
+ if (booleanOptions.has(arg)) {
29
+ if (options.has(arg))
30
+ throw new Error(`duplicate option: ${arg}`);
31
+ options.set(arg, true);
32
+ continue;
33
+ }
34
+ if (!valueOptions.has(arg))
35
+ throw new Error(`unknown option: ${arg}`);
36
+ const value = args[index + 1];
37
+ if (!value || value.startsWith('--'))
38
+ throw new Error(`missing value for ${arg}`);
39
+ if (options.has(arg))
40
+ throw new Error(`duplicate option: ${arg}`);
41
+ options.set(arg, value);
42
+ index += 1;
43
+ }
44
+ return { positionals, options };
45
+ }
46
+ function dataRoot(repoRoot, requested) {
47
+ const workspace = path.resolve(repoRoot, '.agents', 'workspace');
48
+ const resolved = path.resolve(repoRoot, requested ?? path.join('.agents', 'workspace', 'process-data'));
49
+ const relative = path.relative(repoRoot, resolved);
50
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
51
+ throw new Error('data root must be inside the repository');
52
+ const taskRoots = ['active', 'blocked', 'completed', 'archive'].map((state) => path.join(workspace, state));
53
+ if (resolved === workspace || taskRoots.some((taskRoot) => resolved === taskRoot || resolved.startsWith(`${taskRoot}${path.sep}`))) {
54
+ throw new Error('data root cannot be the workspace root or a task directory');
55
+ }
56
+ let current = resolved;
57
+ while (current !== repoRoot) {
58
+ if (fs.existsSync(current) && fs.lstatSync(current).isSymbolicLink())
59
+ throw new Error('data root cannot traverse a symlink');
60
+ current = path.dirname(current);
61
+ }
62
+ return resolved;
63
+ }
64
+ function repositoryIdentity(repoRoot) {
65
+ try {
66
+ return execFileSync('git', ['config', '--get', 'remote.origin.url'], { cwd: repoRoot, encoding: 'utf8' }).trim() || path.basename(repoRoot);
67
+ }
68
+ catch {
69
+ return path.basename(repoRoot);
70
+ }
71
+ }
72
+ function writeJson(value) {
73
+ process.stdout.write(`${JSON.stringify(value)}\n`);
74
+ }
75
+ function optionString(parsed, name) {
76
+ const value = parsed.options.get(name);
77
+ return typeof value === 'string' ? value : undefined;
78
+ }
79
+ function capture(args) {
80
+ const parsed = parseArgs(args, new Set(['--source', '--root']), new Set(['--include-excerpts']));
81
+ if (parsed.positionals.length > 0)
82
+ throw new Error('capture does not accept positional arguments');
83
+ const scope = optionString(parsed, '--source') ?? 'all';
84
+ if (!['all', 'local', 'github'].includes(scope))
85
+ throw new Error('--source must be all, local, or github');
86
+ const repoRoot = detectRepoRoot();
87
+ const root = dataRoot(repoRoot, optionString(parsed, '--root'));
88
+ const observedFrom = new Date().toISOString();
89
+ const objects = [];
90
+ const endpoints = [];
91
+ let repository = repositoryIdentity(repoRoot);
92
+ if (scope === 'all' || scope === 'local') {
93
+ const local = collectLocalObjects(repoRoot, { includeExcerpts: parsed.options.has('--include-excerpts') });
94
+ if (!local.ok) {
95
+ writeJson({ ok: false, error: local.error });
96
+ return 2;
97
+ }
98
+ objects.push(...local.value);
99
+ }
100
+ if (scope === 'all' || scope === 'github') {
101
+ const github = collectGitHubObjects(repoRoot);
102
+ if (!github.ok) {
103
+ writeJson({ ok: false, error: github.error });
104
+ return 2;
105
+ }
106
+ objects.push(...github.value.objects);
107
+ endpoints.push(...github.value.endpoints);
108
+ repository = github.value.repository;
109
+ }
110
+ const store = createObjectStore(root);
111
+ for (const object of objects) {
112
+ if (object.content !== undefined && object.disposition?.state === 'included') {
113
+ const stored = store.put(Buffer.from(object.content, 'utf8'));
114
+ if (stored.sha256 !== object.sha256)
115
+ throw new Error(`source hash mismatch: ${object.sourceIdentity}`);
116
+ }
117
+ }
118
+ const records = normalizeObjects(objects);
119
+ const reconciliation = reconcileRecords(records, scope);
120
+ const observedTo = new Date().toISOString();
121
+ const published = publishSnapshot(root, {
122
+ scope: scope,
123
+ repository,
124
+ observedFrom,
125
+ observedTo,
126
+ objects: objects.map(({ content: _content, ...object }) => object),
127
+ endpoints,
128
+ excerptsEnabled: parsed.options.has('--include-excerpts'),
129
+ records,
130
+ quality: reconciliation.findings,
131
+ repairs: reconciliation.repairs
132
+ });
133
+ writeJson({ ok: true, snapshotId: published.snapshotId, scope, created: published.created, objects: objects.length, records: records.length });
134
+ return 0;
135
+ }
136
+ function verify(args) {
137
+ const parsed = parseArgs(args, new Set(['--root']), new Set());
138
+ if (parsed.positionals.length !== 1)
139
+ throw new Error('verify requires one snapshot id');
140
+ const repoRoot = detectRepoRoot();
141
+ const result = verifySnapshot(dataRoot(repoRoot, optionString(parsed, '--root')), parsed.positionals[0]);
142
+ writeJson(result);
143
+ return result.ok ? 0 : 1;
144
+ }
145
+ function audit(args) {
146
+ const parsed = parseArgs(args, new Set(['--root', '--format']), new Set());
147
+ if (parsed.positionals.length !== 1)
148
+ throw new Error('audit requires one snapshot id');
149
+ const format = optionString(parsed, '--format') ?? 'text';
150
+ if (!['json', 'text'].includes(format))
151
+ throw new Error('--format must be json or text');
152
+ const repoRoot = detectRepoRoot();
153
+ const root = dataRoot(repoRoot, optionString(parsed, '--root'));
154
+ const verified = verifySnapshot(root, parsed.positionals[0]);
155
+ if (!verified.ok || !verified.snapshotPath || !verified.manifest) {
156
+ writeJson(verified);
157
+ return 1;
158
+ }
159
+ const quality = JSON.parse(fs.readFileSync(path.join(verified.snapshotPath, 'quality.json'), 'utf8'));
160
+ const records = fs.readFileSync(path.join(verified.snapshotPath, 'normalized.jsonl'), 'utf8').split('\n').filter(Boolean).map((line) => {
161
+ const { schema: _schema, ...record } = JSON.parse(line);
162
+ return record;
163
+ });
164
+ const recomputed = reconcileRecords(records, verified.manifest.scope);
165
+ if (!canonicalJsonBytes(recomputed.findings).equals(canonicalJsonBytes(quality.findings))) {
166
+ writeJson({ ok: false, error: { code: 'QUALITY_MISMATCH', message: 'stored quality baseline does not match recomputed findings' } });
167
+ return 1;
168
+ }
169
+ if (format === 'json')
170
+ writeJson({ ok: true, snapshotId: parsed.positionals[0], findings: recomputed.findings });
171
+ else
172
+ process.stdout.write(`Snapshot ${parsed.positionals[0]}: ${quality.findings.length} findings\n`);
173
+ return 0;
174
+ }
175
+ function repair(args) {
176
+ const parsed = parseArgs(args, new Set(['--root']), new Set(['--apply']));
177
+ if (parsed.positionals.length !== 1)
178
+ throw new Error('repair requires one snapshot id');
179
+ const repoRoot = detectRepoRoot();
180
+ const result = repairSnapshot(dataRoot(repoRoot, optionString(parsed, '--root')), parsed.positionals[0], parsed.options.has('--apply'));
181
+ writeJson({ ok: true, ...result });
182
+ return 0;
183
+ }
184
+ function exportSnapshot(args) {
185
+ const parsed = parseArgs(args, new Set(['--root', '--repairs', '--output']), new Set());
186
+ if (parsed.positionals.length !== 1)
187
+ throw new Error('export requires one snapshot id');
188
+ const repairMode = optionString(parsed, '--repairs') ?? 'none';
189
+ if (!['none', 'applied'].includes(repairMode))
190
+ throw new Error('--repairs must be none or applied');
191
+ const output = optionString(parsed, '--output') ?? '-';
192
+ const repoRoot = detectRepoRoot();
193
+ const root = dataRoot(repoRoot, optionString(parsed, '--root'));
194
+ const verified = verifySnapshot(root, parsed.positionals[0]);
195
+ if (!verified.ok || !verified.snapshotPath) {
196
+ writeJson(verified);
197
+ return 1;
198
+ }
199
+ let content = fs.readFileSync(path.join(verified.snapshotPath, 'normalized.jsonl'), 'utf8');
200
+ if (repairMode === 'applied')
201
+ content += readAppliedOverlays(root, parsed.positionals[0]);
202
+ if (output === '-')
203
+ process.stdout.write(content);
204
+ else {
205
+ const destination = path.resolve(repoRoot, output);
206
+ const relative = path.relative(repoRoot, destination);
207
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
208
+ throw new Error('export output must be inside the repository');
209
+ fs.writeFileSync(destination, content, { flag: 'wx', mode: 0o600 });
210
+ writeJson({ ok: true, snapshotId: parsed.positionals[0], output: relative });
211
+ }
212
+ return 0;
213
+ }
214
+ async function cmdData(args) {
215
+ const [command, ...rest] = args;
216
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
217
+ process.stdout.write(USAGE);
218
+ return command ? 0 : 1;
219
+ }
220
+ try {
221
+ switch (command) {
222
+ case 'capture': return capture(rest);
223
+ case 'verify': return verify(rest);
224
+ case 'audit': return audit(rest);
225
+ case 'repair': return repair(rest);
226
+ case 'export': return exportSnapshot(rest);
227
+ default:
228
+ process.stderr.write(`Unknown data command: ${command}\n`);
229
+ process.stdout.write(USAGE);
230
+ return 1;
231
+ }
232
+ }
233
+ catch (error) {
234
+ writeJson({ ok: false, error: { code: 'DATA_COMMAND_FAILED', message: error instanceof Error ? error.message : String(error) } });
235
+ return 1;
236
+ }
237
+ }
238
+ export { cmdData, dataRoot };
239
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,198 @@
1
+ import { sha256 } from './store.js';
2
+ const TASK_ID_RE = /TASK-\d{8}-\d{6}/;
3
+ const ACTIVITY_RE = /^- (\d{4}-\d{2}-\d{2} [^ ]+) — \*\*(.+?)\*\* by ([^ ]+) — (.+)$/gm;
4
+ const LEDGER_RE = /^\|\s*((?:AN|PL|CD)-\d+)\s*\|\s*(analysis|plan|code)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|$/gm;
5
+ const RULING_RE = /^###\s+(HDR-\d+)\s*$([\s\S]*?)(?=^###\s+|^##\s+|(?![\s\S]))/gm;
6
+ const CONFLICT_STATUSES = new Set(['open', 'accepted', 'adjusted', 'refuted', 'cannot-judge', 'needs-human-decision']);
7
+ function recordId(kind, identity, suffix = '') {
8
+ return `${kind}:${sha256(`${identity}\0${suffix}`).slice(0, 24)}`;
9
+ }
10
+ function canonicalActor(raw) {
11
+ const lowered = raw.toLowerCase();
12
+ const aliases = {
13
+ 'claude-code': 'claude',
14
+ 'antigravity-cli': 'antigravity',
15
+ 'gemini-cli': 'gemini',
16
+ gemini: 'gemini'
17
+ };
18
+ if (['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'human'].includes(lowered))
19
+ return lowered;
20
+ return aliases[lowered] ?? null;
21
+ }
22
+ function nextOccurrence(occurrences, identity) {
23
+ const occurrence = (occurrences.get(identity) ?? 0) + 1;
24
+ occurrences.set(identity, occurrence);
25
+ return occurrence === 1 ? '' : `occurrence=${occurrence}`;
26
+ }
27
+ function normalizePlatformPage(object) {
28
+ if (!object.content)
29
+ return [];
30
+ try {
31
+ const page = JSON.parse(object.content);
32
+ if (!Array.isArray(page))
33
+ return [];
34
+ return page.map((entry, index) => {
35
+ const value = entry;
36
+ const identity = String(value.id ?? value.node_id ?? value.sha ?? value.number ?? `${object.sourceIdentity}:${index}`);
37
+ const platformIdentity = /\/issues\?/.test(object.sourceIdentity) && typeof value.number === 'number'
38
+ ? `issue:${value.number}`
39
+ : /\/pulls\?/.test(object.sourceIdentity) && typeof value.number === 'number'
40
+ ? `pr:${value.number}`
41
+ : /\/issues\/\d+\/comments/.test(object.sourceIdentity)
42
+ ? `issue-comment:${identity}`
43
+ : /\/pulls\/\d+\/reviews/.test(object.sourceIdentity)
44
+ ? `review:${identity}`
45
+ : /\/pulls\/\d+\/commits/.test(object.sourceIdentity)
46
+ ? `commit:${identity}`
47
+ : `platform:${identity}`;
48
+ const binding = typeof value.body === 'string' ? value.body.match(TASK_ID_RE)?.[0] : undefined;
49
+ return {
50
+ recordId: recordId('platform-resource', object.sourceIdentity, identity),
51
+ kind: 'platform-resource',
52
+ sourceIdentity: platformIdentity,
53
+ sourceSha256: object.sha256,
54
+ ...(binding ? { binding } : {}),
55
+ data: entry
56
+ };
57
+ });
58
+ }
59
+ catch {
60
+ return [];
61
+ }
62
+ }
63
+ function normalizeObjects(objects) {
64
+ const records = [];
65
+ for (const object of objects) {
66
+ if (object.disposition?.state && object.disposition.state !== 'included') {
67
+ records.push({
68
+ recordId: recordId('missing', object.sourceIdentity),
69
+ kind: 'missing',
70
+ sourceIdentity: object.sourceIdentity,
71
+ sourceSha256: object.sha256,
72
+ data: object.disposition.state === 'excluded-sensitive'
73
+ ? { reason: 'privacy-excluded', ruleId: object.disposition.ruleId }
74
+ : { reason: object.disposition.reason }
75
+ });
76
+ continue;
77
+ }
78
+ if (object.sourceKind === 'github-rest') {
79
+ records.push(...normalizePlatformPage(object));
80
+ continue;
81
+ }
82
+ if (object.sourceKind === 'operational-report') {
83
+ records.push({
84
+ recordId: recordId('operational-report', object.sourceIdentity),
85
+ kind: 'operational-report',
86
+ sourceIdentity: object.sourceIdentity,
87
+ sourceSha256: object.sha256
88
+ });
89
+ continue;
90
+ }
91
+ if (object.sourceKind === 'structured-telemetry') {
92
+ let data = { availability: 'unknown' };
93
+ try {
94
+ data = JSON.parse(object.content ?? '{}');
95
+ }
96
+ catch {
97
+ data = { availability: 'unavailable', reason: 'invalid receipt JSON' };
98
+ }
99
+ records.push({
100
+ recordId: recordId('telemetry', object.sourceIdentity),
101
+ kind: 'telemetry',
102
+ sourceIdentity: object.sourceIdentity,
103
+ sourceSha256: object.sha256,
104
+ data
105
+ });
106
+ continue;
107
+ }
108
+ const taskId = object.sourceIdentity.match(TASK_ID_RE)?.[0];
109
+ if (/\/task\.md$/.test(object.sourceIdentity) && taskId) {
110
+ const activityOccurrences = new Map();
111
+ const findingOccurrences = new Map();
112
+ const issueNumber = object.content?.match(/^issue_number:\s*(\d+)$/m)?.[1];
113
+ const agentInfraVersion = object.content?.match(/^agent_infra_version:\s*(\S+)$/m)?.[1];
114
+ records.push({
115
+ recordId: recordId('task', taskId),
116
+ kind: 'task',
117
+ sourceIdentity: taskId,
118
+ sourceSha256: object.sha256,
119
+ ...(issueNumber ? { binding: `issue:${issueNumber}` } : {}),
120
+ data: {
121
+ agentInfraVersion: agentInfraVersion
122
+ ? { state: 'known', value: agentInfraVersion }
123
+ : { state: 'unknown', reason: 'legacy-task-missing-agent-infra-version' }
124
+ }
125
+ });
126
+ for (const match of object.content?.matchAll(ACTIVITY_RE) ?? []) {
127
+ const rawActor = match[3];
128
+ const identity = `${match[1]}:${match[2]}`;
129
+ const occurrence = nextOccurrence(activityOccurrences, identity);
130
+ records.push({
131
+ recordId: recordId('lifecycle-event', taskId, occurrence ? `${identity}\0${occurrence}` : identity),
132
+ kind: 'lifecycle-event',
133
+ sourceIdentity: `${taskId}#activity=${match[1]}`,
134
+ sourceSha256: object.sha256,
135
+ data: {
136
+ timestamp: match[1],
137
+ action: match[2],
138
+ actorRaw: rawActor,
139
+ actorCanonical: canonicalActor(rawActor),
140
+ note: match[4]
141
+ }
142
+ });
143
+ }
144
+ for (const match of object.content?.matchAll(LEDGER_RE) ?? []) {
145
+ const findingId = match[1].trim();
146
+ const stage = match[2].trim();
147
+ const round = match[3].trim();
148
+ const severity = match[4].trim();
149
+ const status = match[5].trim();
150
+ const evidence = match[6].trim();
151
+ const identity = `${taskId}#finding=${findingId}`;
152
+ const occurrence = nextOccurrence(findingOccurrences, identity);
153
+ const data = { findingId, stage, round, severity, status, evidence };
154
+ records.push({
155
+ recordId: recordId('review-finding', identity, occurrence),
156
+ kind: 'review-finding',
157
+ sourceIdentity: identity,
158
+ sourceSha256: object.sha256,
159
+ binding: taskId,
160
+ data
161
+ });
162
+ if (status && CONFLICT_STATUSES.has(status)) {
163
+ records.push({
164
+ recordId: recordId('conflict', identity, occurrence),
165
+ kind: 'conflict',
166
+ sourceIdentity: `${identity}#status=${status}`,
167
+ sourceSha256: object.sha256,
168
+ binding: taskId,
169
+ data
170
+ });
171
+ }
172
+ }
173
+ for (const match of object.content?.matchAll(RULING_RE) ?? []) {
174
+ const rulingId = match[1];
175
+ const identity = `${taskId}#ruling=${rulingId}`;
176
+ records.push({
177
+ recordId: recordId('human-ruling', identity),
178
+ kind: 'human-ruling',
179
+ sourceIdentity: identity,
180
+ sourceSha256: object.sha256,
181
+ binding: taskId,
182
+ data: { rulingId, evidence: match[2].trim() }
183
+ });
184
+ }
185
+ continue;
186
+ }
187
+ records.push({
188
+ recordId: recordId('artifact', object.sourceIdentity),
189
+ kind: 'artifact',
190
+ sourceIdentity: object.sourceIdentity,
191
+ sourceSha256: object.sha256,
192
+ ...(taskId ? { binding: taskId } : {})
193
+ });
194
+ }
195
+ return records.sort((left, right) => left.recordId.localeCompare(right.recordId));
196
+ }
197
+ export { normalizeObjects };
198
+ //# sourceMappingURL=normalize.js.map