@fitlab-ai/agent-infra 0.8.5 → 0.9.1

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 (467) hide show
  1. package/README.md +6 -1
  2. package/README.zh-CN.md +5 -1
  3. package/bin/cli.ts +2 -2
  4. package/dist/bin/cli.js +2 -2
  5. package/dist/bin/internal-cli.js +103 -0
  6. package/dist/lib/decide.js +81 -90
  7. package/dist/lib/defaults.json +1 -0
  8. package/dist/lib/git/review-snapshot.js +79 -0
  9. package/dist/lib/git/workflow.js +101 -0
  10. package/dist/lib/internal/git-workflow.js +42 -0
  11. package/dist/lib/internal/platform-checks.js +119 -0
  12. package/dist/lib/internal/platform-comment.js +129 -0
  13. package/dist/lib/internal/platform-context.js +46 -0
  14. package/dist/lib/internal/platform-issue.js +142 -0
  15. package/dist/lib/internal/platform-pr.js +146 -0
  16. package/dist/lib/internal/platform-release-notes.js +53 -0
  17. package/dist/lib/internal/release-workflow.js +320 -0
  18. package/dist/lib/internal/task-artifact.js +67 -0
  19. package/dist/lib/internal/task-context.js +43 -0
  20. package/dist/lib/internal/task-event.js +70 -0
  21. package/dist/lib/internal/task-ledger.js +114 -0
  22. package/dist/lib/internal/task-lifecycle.js +58 -0
  23. package/dist/lib/internal/task-short-id.js +83 -0
  24. package/dist/lib/internal/task-snapshot.js +47 -0
  25. package/dist/lib/internal/task-verify.js +50 -0
  26. package/dist/lib/internal/task-warning.js +74 -0
  27. package/dist/lib/platform/adapters.js +14 -0
  28. package/dist/lib/platform/context.js +146 -0
  29. package/dist/lib/platform/github-client.js +124 -0
  30. package/dist/lib/platform/github-release-notes.js +96 -0
  31. package/dist/lib/platform/issue-comments.js +409 -0
  32. package/dist/lib/platform/issue-metadata.js +183 -0
  33. package/dist/lib/platform/issues.js +619 -0
  34. package/dist/lib/platform/merged-pr-equivalence.js +54 -0
  35. package/dist/lib/platform/metadata-labels.js +28 -0
  36. package/dist/lib/platform/pr-checks.js +216 -0
  37. package/dist/lib/platform/pr-summary.js +88 -0
  38. package/dist/lib/platform/pull-request-metadata.js +38 -0
  39. package/dist/lib/platform/pull-requests.js +340 -0
  40. package/dist/lib/platform/release-notes.js +143 -0
  41. package/dist/lib/platform/releases.js +82 -0
  42. package/dist/lib/platform/types.js +22 -0
  43. package/dist/lib/platform/verification-required.js +102 -0
  44. package/dist/lib/platform/verification-sync.js +1014 -0
  45. package/dist/lib/platform/verification.js +6 -0
  46. package/dist/lib/release/channels.js +31 -0
  47. package/dist/lib/release/workflow.js +32 -0
  48. package/dist/lib/render.js +3 -2
  49. package/dist/lib/run/index.js +24 -7
  50. package/dist/lib/sandbox/build-proxy.js +63 -0
  51. package/dist/lib/sandbox/capture.js +25 -3
  52. package/dist/lib/sandbox/commands/create.js +93 -31
  53. package/dist/lib/sandbox/commands/enter.js +34 -11
  54. package/dist/lib/sandbox/commands/list-running.js +10 -8
  55. package/dist/lib/sandbox/commands/rebuild.js +24 -7
  56. package/dist/lib/sandbox/commands/show.js +2 -2
  57. package/dist/lib/sandbox/commands/start.js +53 -15
  58. package/dist/lib/sandbox/image-build.js +2 -1
  59. package/dist/lib/sandbox/index.js +6 -6
  60. package/dist/lib/sandbox/mounts.js +36 -0
  61. package/dist/lib/sandbox/recovery.js +562 -0
  62. package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  63. package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
  64. package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
  65. package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
  66. package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
  67. package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
  68. package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
  69. package/dist/lib/sandbox/shell.js +2 -1
  70. package/dist/lib/sandbox/task-resolver.js +5 -1
  71. package/dist/lib/sandbox/tools.js +19 -0
  72. package/dist/lib/server/protocol.js +5 -5
  73. package/dist/lib/task/activity-log.js +61 -0
  74. package/dist/lib/task/artifact-lifecycle.js +427 -0
  75. package/dist/lib/task/command-options.js +30 -0
  76. package/dist/lib/task/commands/cat.js +36 -6
  77. package/dist/lib/task/commands/decisions.js +80 -46
  78. package/dist/lib/task/commands/files.js +21 -7
  79. package/dist/lib/task/commands/grep.js +55 -7
  80. package/dist/lib/task/commands/issue-body.js +33 -19
  81. package/dist/lib/task/commands/log.js +27 -70
  82. package/dist/lib/task/commands/show.js +20 -7
  83. package/dist/lib/task/commands/status.js +18 -8
  84. package/dist/lib/task/decision-intents.js +154 -0
  85. package/dist/lib/task/decision-items.js +53 -0
  86. package/dist/lib/task/events.js +318 -0
  87. package/dist/lib/task/frontmatter.js +159 -1
  88. package/dist/lib/task/implementation-inputs.js +117 -0
  89. package/dist/lib/task/index.js +12 -9
  90. package/dist/lib/task/issue-form.js +21 -6
  91. package/dist/lib/task/ledger-intents.js +185 -0
  92. package/dist/lib/task/ledger.js +65 -35
  93. package/dist/lib/task/lifecycle.js +484 -0
  94. package/dist/lib/task/resolve-ref.js +152 -32
  95. package/dist/lib/task/review-artifacts.js +101 -0
  96. package/dist/lib/task/review-fingerprint.js +55 -0
  97. package/dist/lib/task/sections.js +358 -4
  98. package/dist/lib/task/short-id.js +292 -7
  99. package/dist/lib/task/snapshot.js +95 -0
  100. package/dist/lib/task/verification-checks.js +8 -0
  101. package/dist/lib/task/verification-config.js +14 -0
  102. package/dist/lib/task/verification-engine.js +923 -0
  103. package/dist/lib/task/verification-review.js +3 -0
  104. package/dist/lib/task/verification-types.js +2 -0
  105. package/dist/lib/task/verification.js +113 -0
  106. package/dist/lib/task/workflow-warning-intents.js +131 -0
  107. package/dist/lib/task/workflow-warnings.js +10 -78
  108. package/dist/lib/task/write.js +241 -0
  109. package/lib/decide.ts +57 -97
  110. package/lib/defaults.json +1 -0
  111. package/lib/git/review-snapshot.ts +73 -0
  112. package/lib/git/workflow.ts +101 -0
  113. package/lib/internal/git-workflow.ts +37 -0
  114. package/lib/internal/platform-checks.ts +101 -0
  115. package/lib/internal/platform-comment.ts +99 -0
  116. package/lib/internal/platform-context.ts +33 -0
  117. package/lib/internal/platform-issue.ts +116 -0
  118. package/lib/internal/platform-pr.ts +119 -0
  119. package/lib/internal/platform-release-notes.ts +55 -0
  120. package/lib/internal/release-workflow.ts +288 -0
  121. package/lib/internal/task-artifact.ts +47 -0
  122. package/lib/internal/task-context.ts +35 -0
  123. package/lib/internal/task-event.ts +51 -0
  124. package/lib/internal/task-ledger.ts +86 -0
  125. package/lib/internal/task-lifecycle.ts +41 -0
  126. package/lib/internal/task-short-id.ts +55 -0
  127. package/lib/internal/task-snapshot.ts +32 -0
  128. package/lib/internal/task-verify.ts +33 -0
  129. package/lib/internal/task-warning.ts +50 -0
  130. package/lib/platform/adapters.ts +30 -0
  131. package/lib/platform/context.ts +164 -0
  132. package/lib/platform/github-client.ts +146 -0
  133. package/lib/platform/github-release-notes.ts +132 -0
  134. package/lib/platform/issue-comments.ts +479 -0
  135. package/lib/platform/issue-metadata.ts +250 -0
  136. package/lib/platform/issues.ts +693 -0
  137. package/lib/platform/merged-pr-equivalence.ts +70 -0
  138. package/lib/platform/metadata-labels.ts +33 -0
  139. package/lib/platform/pr-checks.ts +247 -0
  140. package/lib/platform/pr-summary.ts +90 -0
  141. package/lib/platform/pull-request-metadata.ts +69 -0
  142. package/lib/platform/pull-requests.ts +386 -0
  143. package/lib/platform/release-notes.ts +167 -0
  144. package/lib/platform/releases.ts +71 -0
  145. package/lib/platform/types.ts +74 -0
  146. package/lib/platform/verification-required.ts +109 -0
  147. package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
  148. package/lib/platform/verification.ts +11 -0
  149. package/lib/release/channels.ts +30 -0
  150. package/lib/release/workflow.ts +31 -0
  151. package/lib/render.ts +3 -2
  152. package/lib/run/index.ts +25 -7
  153. package/lib/sandbox/build-proxy.ts +94 -0
  154. package/lib/sandbox/capture.ts +29 -3
  155. package/lib/sandbox/commands/create.ts +120 -36
  156. package/lib/sandbox/commands/enter.ts +38 -11
  157. package/lib/sandbox/commands/list-running.ts +10 -8
  158. package/lib/sandbox/commands/rebuild.ts +29 -7
  159. package/lib/sandbox/commands/show.ts +2 -2
  160. package/lib/sandbox/commands/start.ts +50 -16
  161. package/lib/sandbox/image-build.ts +4 -1
  162. package/lib/sandbox/index.ts +6 -6
  163. package/lib/sandbox/mounts.ts +55 -0
  164. package/lib/sandbox/recovery.ts +828 -0
  165. package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  166. package/lib/sandbox/runtimes/base.dockerfile +8 -1
  167. package/lib/sandbox/runtimes/java17.dockerfile +8 -1
  168. package/lib/sandbox/runtimes/java21.dockerfile +8 -1
  169. package/lib/sandbox/runtimes/node20.dockerfile +8 -1
  170. package/lib/sandbox/runtimes/node22.dockerfile +8 -1
  171. package/lib/sandbox/runtimes/python3.dockerfile +8 -1
  172. package/lib/sandbox/shell.ts +3 -1
  173. package/lib/sandbox/task-resolver.ts +5 -1
  174. package/lib/sandbox/tools.ts +31 -0
  175. package/lib/server/protocol.ts +5 -5
  176. package/lib/task/activity-log.ts +62 -0
  177. package/lib/task/artifact-lifecycle.ts +484 -0
  178. package/lib/task/command-options.ts +32 -0
  179. package/lib/task/commands/cat.ts +22 -9
  180. package/lib/task/commands/decisions.ts +49 -47
  181. package/lib/task/commands/files.ts +14 -6
  182. package/lib/task/commands/grep.ts +34 -7
  183. package/lib/task/commands/issue-body.ts +26 -21
  184. package/lib/task/commands/log.ts +17 -70
  185. package/lib/task/commands/show.ts +14 -6
  186. package/lib/task/commands/status.ts +17 -7
  187. package/lib/task/decision-intents.ts +163 -0
  188. package/lib/task/decision-items.ts +64 -0
  189. package/lib/task/events.ts +320 -0
  190. package/lib/task/frontmatter.ts +202 -2
  191. package/lib/task/implementation-inputs.ts +137 -0
  192. package/lib/task/index.ts +12 -9
  193. package/lib/task/issue-form.ts +24 -6
  194. package/lib/task/ledger-intents.ts +201 -0
  195. package/lib/task/ledger.ts +77 -31
  196. package/lib/task/lifecycle.ts +458 -0
  197. package/lib/task/resolve-ref.ts +197 -36
  198. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  199. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +26 -12
  200. package/lib/task/sections.ts +486 -4
  201. package/lib/task/short-id.ts +403 -9
  202. package/lib/task/snapshot.ts +143 -0
  203. package/lib/task/verification-checks.ts +9 -0
  204. package/lib/task/verification-config.ts +20 -0
  205. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +230 -421
  206. package/lib/task/verification-review.ts +10 -0
  207. package/lib/task/verification-types.ts +29 -0
  208. package/lib/task/verification.ts +156 -0
  209. package/lib/task/workflow-warning-intents.ts +142 -0
  210. package/lib/task/workflow-warnings.ts +10 -78
  211. package/lib/task/write.ts +468 -0
  212. package/package.json +4 -2
  213. package/templates/.agents/README.en.md +4 -3
  214. package/templates/.agents/README.zh-CN.md +4 -3
  215. package/templates/.agents/rules/README.en.md +6 -5
  216. package/templates/.agents/rules/README.zh-CN.md +6 -5
  217. package/templates/.agents/rules/create-issue.en.md +1 -1
  218. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  219. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  220. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  221. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  222. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  223. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  224. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  225. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  226. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  227. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  228. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  229. package/templates/.agents/rules/issue-sync.en.md +1 -1
  230. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  231. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  232. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  233. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  234. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  235. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  236. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  237. package/templates/.agents/rules/next-step-output.en.md +12 -11
  238. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  239. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  240. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  241. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  242. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  243. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  244. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  245. package/templates/.agents/rules/pr-sync.en.md +30 -3
  246. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  247. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  248. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  249. package/templates/.agents/rules/release-commands.en.md +2 -2
  250. package/templates/.agents/rules/release-commands.github.en.md +10 -40
  251. package/templates/.agents/rules/release-commands.github.zh-CN.md +9 -39
  252. package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
  253. package/templates/.agents/rules/review-handshake.en.md +10 -6
  254. package/templates/.agents/rules/review-handshake.zh-CN.md +10 -6
  255. package/templates/.agents/rules/task-management.en.md +11 -2
  256. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  257. package/templates/.agents/rules/task-short-id.en.md +25 -29
  258. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  259. package/templates/.agents/rules/testing-discipline.en.md +20 -2
  260. package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
  261. package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
  262. package/templates/.agents/scripts/task-short-id.js +71 -533
  263. package/templates/.agents/skills/analyze-task/SKILL.en.md +26 -56
  264. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +30 -60
  265. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  266. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  267. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  268. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  269. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  270. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  271. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  272. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  273. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  274. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  275. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  276. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  277. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  278. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  279. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  280. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  281. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  282. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  283. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  284. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  285. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  286. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  287. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  288. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  289. package/templates/.agents/skills/commit/SKILL.en.md +13 -11
  290. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
  291. package/templates/.agents/skills/commit/config/verify.json +1 -2
  292. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  293. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  294. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  295. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  296. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  297. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  298. package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
  299. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
  300. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  301. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  302. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  303. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  304. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  305. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  306. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  307. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  308. package/templates/.agents/skills/complete-task/config/verify.en.json +10 -7
  309. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +10 -7
  310. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  311. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  312. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  313. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  314. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  315. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
  316. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
  317. package/templates/.agents/skills/create-task/SKILL.en.md +16 -13
  318. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +16 -13
  319. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  320. package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
  321. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
  322. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  323. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  324. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  325. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  326. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  327. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  328. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  329. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  330. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  331. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  332. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  333. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  334. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  335. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  336. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  337. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  338. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  339. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  340. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  341. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  342. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  343. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  344. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  345. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  346. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  347. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  348. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  349. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  350. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  351. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  352. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  353. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  354. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  355. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  356. package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
  357. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
  358. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  359. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  360. package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
  361. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
  362. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  363. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  364. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  365. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  366. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  367. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  368. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  369. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  370. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  371. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  372. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  373. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  374. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
  375. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
  376. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
  377. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  378. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  379. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  380. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  381. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  382. package/templates/.agents/templates/task.en.md +24 -1
  383. package/templates/.agents/templates/task.zh-CN.md +24 -1
  384. package/templates/.claude/commands/analyze-task.en.md +1 -1
  385. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  386. package/templates/.claude/commands/block-task.en.md +1 -1
  387. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  388. package/templates/.claude/commands/cancel-task.en.md +1 -1
  389. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  390. package/templates/.claude/commands/check-task.en.md +1 -1
  391. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  392. package/templates/.claude/commands/code-task.en.md +1 -1
  393. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  394. package/templates/.claude/commands/commit.en.md +1 -0
  395. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  396. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  397. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  398. package/templates/.claude/commands/complete-task.en.md +1 -1
  399. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  400. package/templates/.claude/commands/create-pr.en.md +1 -1
  401. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  402. package/templates/.claude/commands/plan-task.en.md +1 -1
  403. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  404. package/templates/.claude/commands/review-analysis.en.md +1 -1
  405. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  406. package/templates/.claude/commands/review-code.en.md +1 -1
  407. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  408. package/templates/.claude/commands/review-plan.en.md +1 -1
  409. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  410. package/templates/.claude/commands/watch-pr.en.md +1 -1
  411. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  412. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  413. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  414. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  415. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  416. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  417. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  418. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  419. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  420. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  421. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  422. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  423. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  424. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  425. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  426. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  427. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  428. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  429. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  430. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  431. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  432. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  433. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  434. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  435. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  436. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  437. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  438. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  439. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  440. package/templates/.git-hooks/check-large-files.cjs +92 -0
  441. package/templates/.git-hooks/check-version-format.sh +5 -1
  442. package/templates/.git-hooks/pre-commit +1 -0
  443. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  444. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  445. package/templates/.opencode/commands/check-task.en.md +1 -1
  446. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  447. package/templates/.opencode/commands/code-task.en.md +1 -1
  448. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  449. package/templates/.opencode/commands/commit.en.md +2 -0
  450. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  451. package/templates/.opencode/commands/complete-task.en.md +1 -1
  452. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  453. package/templates/.opencode/commands/plan-task.en.md +1 -1
  454. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  455. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  456. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  457. package/templates/.opencode/commands/review-code.en.md +1 -1
  458. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  459. package/templates/.opencode/commands/review-plan.en.md +1 -1
  460. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  461. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
  462. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  463. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
  464. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  465. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  466. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  467. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -2,17 +2,22 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
4
  const REGISTRY_NAME = '.short-ids.json';
5
+ const LOCK_NAME = '.short-ids.json.lock';
5
6
 
6
7
  type NormalizeResult =
7
8
  | { kind: 'shortId'; value: string }
8
9
  | { kind: 'pass'; value: string }
9
- | { kind: 'error'; message: string };
10
+ | {
11
+ kind: 'error';
12
+ code: 'SHORT_ID_RESERVED' | 'SHORT_ID_CAPACITY_EXCEEDED';
13
+ message: string;
14
+ };
10
15
 
11
16
  type NormalizeOpts = { shortIdLength: number };
12
17
 
13
18
  function normalizeShortIdInput(input: string, opts: NormalizeOpts): NormalizeResult {
14
19
  const L = opts.shortIdLength;
15
- const m = /^#?(\d+)$/.exec(input);
20
+ const m = /^(\d+)$/.exec(input);
16
21
  if (!m) {
17
22
  return { kind: 'pass', value: input };
18
23
  }
@@ -20,17 +25,175 @@ function normalizeShortIdInput(input: string, opts: NormalizeOpts): NormalizeRes
20
25
  if (n === 0) {
21
26
  return {
22
27
  kind: 'error',
23
- message: `short id '${input}' is invalid (#${'0'.repeat(L)} is reserved)`
28
+ code: 'SHORT_ID_RESERVED',
29
+ message: `short id '${input}' is invalid (${'0'.repeat(L)} is reserved)`
24
30
  };
25
31
  }
26
32
  const max = Math.pow(10, L) - 1;
27
33
  if (n > max) {
28
34
  return {
29
35
  kind: 'error',
36
+ code: 'SHORT_ID_CAPACITY_EXCEEDED',
30
37
  message: `short id ${n} exceeds shortIdLength=${L} capacity (max=${max}); archive tasks or raise task.shortIdLength in .agents/.airc.json`
31
38
  };
32
39
  }
33
- return { kind: 'shortId', value: `#${String(n).padStart(L, '0')}` };
40
+ return { kind: 'shortId', value: String(n).padStart(L, '0') };
41
+ }
42
+
43
+ function isRemovedHashShortIdInput(input: string): boolean {
44
+ return /^#\d+$/.test(input);
45
+ }
46
+
47
+ type ResolveShortIdErrorCode =
48
+ | 'SHORT_ID_RESERVED'
49
+ | 'SHORT_ID_CAPACITY_EXCEEDED'
50
+ | 'SHORT_ID_REGISTRY_NOT_FOUND'
51
+ | 'SHORT_ID_REGISTRY_READ_FAILED'
52
+ | 'SHORT_ID_REGISTRY_INVALID_JSON'
53
+ | 'SHORT_ID_REGISTRY_INVALID_SCHEMA'
54
+ | 'SHORT_ID_REGISTRY_DUPLICATE_TASK'
55
+ | 'SHORT_ID_NOT_FOUND'
56
+ | 'SHORT_ID_STALE';
57
+
58
+ type ResolveShortIdResult =
59
+ | { ok: true; taskId: string }
60
+ | { ok: false; code: ResolveShortIdErrorCode; message: string; taskId: string | null };
61
+
62
+ function shortIdFailure(
63
+ code: ResolveShortIdErrorCode,
64
+ message: string,
65
+ taskId: string | null = null
66
+ ): ResolveShortIdResult {
67
+ return { ok: false, code, message, taskId };
68
+ }
69
+
70
+ function resolveShortIdReadOnly(
71
+ input: string,
72
+ repoRoot: string,
73
+ opts: NormalizeOpts
74
+ ): ResolveShortIdResult {
75
+ const normalized = normalizeShortIdInput(input, opts);
76
+ if (normalized.kind === 'error') {
77
+ return shortIdFailure(normalized.code, normalized.message);
78
+ }
79
+ if (normalized.kind !== 'shortId') {
80
+ return shortIdFailure(
81
+ 'SHORT_ID_NOT_FOUND',
82
+ `short id '${input}' not found in active task registry`
83
+ );
84
+ }
85
+
86
+ const key = normalized.value;
87
+ const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
88
+ if (!fs.existsSync(registryPath)) {
89
+ return shortIdFailure(
90
+ 'SHORT_ID_REGISTRY_NOT_FOUND',
91
+ `short id '${key}' not found; active task registry is empty.`
92
+ );
93
+ }
94
+
95
+ let raw: string;
96
+ try {
97
+ raw = fs.readFileSync(registryPath, 'utf8');
98
+ } catch (error) {
99
+ return shortIdFailure(
100
+ 'SHORT_ID_REGISTRY_READ_FAILED',
101
+ `cannot read registry ${registryPath}: ${error instanceof Error ? error.message : String(error)}`
102
+ );
103
+ }
104
+
105
+ let data: unknown;
106
+ try {
107
+ data = JSON.parse(raw);
108
+ } catch (error) {
109
+ return shortIdFailure(
110
+ 'SHORT_ID_REGISTRY_INVALID_JSON',
111
+ `registry ${registryPath} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
112
+ );
113
+ }
114
+
115
+ const max = Math.pow(10, opts.shortIdLength) - 1;
116
+ const validKey = new RegExp(`^\\d{${opts.shortIdLength}}$`);
117
+ if (
118
+ !data ||
119
+ typeof data !== 'object' ||
120
+ Array.isArray(data) ||
121
+ (data as { version?: unknown }).version !== 1 ||
122
+ !(data as { ids?: unknown }).ids ||
123
+ typeof (data as { ids?: unknown }).ids !== 'object' ||
124
+ Array.isArray((data as { ids?: unknown }).ids)
125
+ ) {
126
+ return shortIdFailure(
127
+ 'SHORT_ID_REGISTRY_INVALID_SCHEMA',
128
+ `registry ${registryPath} has invalid schema`
129
+ );
130
+ }
131
+
132
+ const ids = (data as RegistrySchema).ids;
133
+ const seen = new Map<string, string>();
134
+ for (const [registryKey, taskId] of Object.entries(ids)) {
135
+ const numericKey = Number(registryKey);
136
+ if (
137
+ !validKey.test(registryKey) ||
138
+ numericKey < 1 ||
139
+ numericKey > max ||
140
+ typeof taskId !== 'string' ||
141
+ !/^TASK-\d{8}-\d{6}$/.test(taskId)
142
+ ) {
143
+ return shortIdFailure(
144
+ 'SHORT_ID_REGISTRY_INVALID_SCHEMA',
145
+ `registry ${registryPath} has invalid schema`
146
+ );
147
+ }
148
+ const existing = seen.get(taskId);
149
+ if (existing) {
150
+ return shortIdFailure(
151
+ 'SHORT_ID_REGISTRY_DUPLICATE_TASK',
152
+ `duplicate registry entries for taskId ${taskId} at keys [${existing}, ${registryKey}]; manual resolution required`,
153
+ taskId
154
+ );
155
+ }
156
+ seen.set(taskId, registryKey);
157
+ }
158
+
159
+ const taskId = ids[key];
160
+ if (!taskId) {
161
+ const message = Object.keys(ids).length === 0
162
+ ? `short id '${key}' not found; active task registry is empty.`
163
+ : `short id '${key}' not found in active task registry (it may have been cleaned up after archival; check 'task-short-id.js list').`;
164
+ return shortIdFailure('SHORT_ID_NOT_FOUND', message);
165
+ }
166
+ const taskMdPath = path.join(
167
+ repoRoot,
168
+ '.agents',
169
+ 'workspace',
170
+ 'active',
171
+ taskId,
172
+ 'task.md'
173
+ );
174
+ if (!fs.existsSync(taskMdPath)) {
175
+ const remainingActiveEntries = Object.values(ids).filter((candidateTaskId) =>
176
+ fs.existsSync(
177
+ path.join(
178
+ repoRoot,
179
+ '.agents',
180
+ 'workspace',
181
+ 'active',
182
+ candidateTaskId,
183
+ 'task.md'
184
+ )
185
+ )
186
+ );
187
+ const message = remainingActiveEntries.length === 0
188
+ ? `short id '${key}' not found; active task registry is empty.`
189
+ : `short id '${key}' not found in active task registry (it may have been cleaned up after archival; check 'task-short-id.js list').`;
190
+ return shortIdFailure(
191
+ 'SHORT_ID_STALE',
192
+ message,
193
+ taskId
194
+ );
195
+ }
196
+ return { ok: true, taskId };
34
197
  }
35
198
 
36
199
  type RegistrySchema = {
@@ -38,6 +201,219 @@ type RegistrySchema = {
38
201
  ids: Record<string, string>;
39
202
  };
40
203
 
204
+ type ShortIdMutationEffect = 'alloc' | 'release' | 'none';
205
+ type ShortIdMutationResult = {
206
+ effect: 'allocated' | 'released' | 'unchanged';
207
+ shortId: string | null;
208
+ changed: boolean;
209
+ };
210
+
211
+ function configuredShortIdLength(repoRoot: string): number {
212
+ try {
213
+ const config = JSON.parse(
214
+ fs.readFileSync(path.join(repoRoot, '.agents', '.airc.json'), 'utf8')
215
+ ) as { task?: { shortIdLength?: unknown } };
216
+ const value = config.task?.shortIdLength;
217
+ return typeof value === 'number' && Number.isInteger(value) && value >= 1 ? value : 2;
218
+ } catch {
219
+ return 2;
220
+ }
221
+ }
222
+
223
+ function validateRegistry(data: unknown, registryPath: string, width: number): RegistrySchema {
224
+ if (
225
+ !data || typeof data !== 'object' || Array.isArray(data) ||
226
+ (data as { version?: unknown }).version !== 1 ||
227
+ !(data as { ids?: unknown }).ids || typeof (data as { ids?: unknown }).ids !== 'object' ||
228
+ Array.isArray((data as { ids?: unknown }).ids)
229
+ ) {
230
+ throw Object.assign(new Error(`registry ${registryPath} has invalid schema`), {
231
+ code: 'SHORT_ID_REGISTRY_INVALID_SCHEMA'
232
+ });
233
+ }
234
+ const registry = data as RegistrySchema;
235
+ const keyPattern = new RegExp(`^\\d{${width}}$`);
236
+ const taskIds = new Set<string>();
237
+ for (const [key, taskId] of Object.entries(registry.ids)) {
238
+ if (!keyPattern.test(key) || Number(key) < 1 || typeof taskId !== 'string' || !/^TASK-\d{8}-\d{6}$/.test(taskId)) {
239
+ throw Object.assign(new Error(`registry ${registryPath} has invalid schema`), {
240
+ code: 'SHORT_ID_REGISTRY_INVALID_SCHEMA'
241
+ });
242
+ }
243
+ if (taskIds.has(taskId)) {
244
+ throw Object.assign(new Error(`duplicate registry entries for taskId ${taskId}`), {
245
+ code: 'SHORT_ID_REGISTRY_DUPLICATE_TASK'
246
+ });
247
+ }
248
+ taskIds.add(taskId);
249
+ }
250
+ return registry;
251
+ }
252
+
253
+ function readRegistryStrict(registryPath: string, width: number): RegistrySchema {
254
+ if (!fs.existsSync(registryPath)) return { version: 1, ids: {} };
255
+ let parsed: unknown;
256
+ try {
257
+ parsed = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
258
+ } catch (error) {
259
+ throw Object.assign(new Error(`registry ${registryPath} is not valid JSON: ${String(error)}`), {
260
+ code: 'SHORT_ID_REGISTRY_INVALID_JSON'
261
+ });
262
+ }
263
+ return validateRegistry(parsed, registryPath, width);
264
+ }
265
+
266
+ function withRegistryLock<T>(activeDir: string, operation: () => T): T {
267
+ fs.mkdirSync(activeDir, { recursive: true });
268
+ const lockPath = path.join(activeDir, LOCK_NAME);
269
+ const deadline = Date.now() + 5000;
270
+ for (;;) {
271
+ try {
272
+ fs.mkdirSync(lockPath);
273
+ break;
274
+ } catch (error) {
275
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
276
+ if (Date.now() >= deadline) {
277
+ throw Object.assign(new Error('registry lock timeout after 5000ms'), {
278
+ code: 'SHORT_ID_LOCK_TIMEOUT'
279
+ });
280
+ }
281
+ }
282
+ }
283
+ try {
284
+ return operation();
285
+ } finally {
286
+ fs.rmdirSync(lockPath);
287
+ }
288
+ }
289
+
290
+ function writeRegistry(registryPath: string, registry: RegistrySchema): void {
291
+ const temporary = `${registryPath}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;
292
+ fs.writeFileSync(temporary, `${JSON.stringify(registry, null, 2)}\n`, { flag: 'wx' });
293
+ try {
294
+ fs.renameSync(temporary, registryPath);
295
+ } catch (error) {
296
+ try { fs.unlinkSync(temporary); } catch { /* best effort temp cleanup */ }
297
+ throw error;
298
+ }
299
+ }
300
+
301
+ function mutateShortIdRegistry(
302
+ repoRoot: string,
303
+ taskId: string,
304
+ requested: ShortIdMutationEffect
305
+ ): ShortIdMutationResult {
306
+ const activeDir = path.join(repoRoot, '.agents', 'workspace', 'active');
307
+ return mutateShortIdRegistryAt(activeDir, configuredShortIdLength(repoRoot), taskId, requested);
308
+ }
309
+
310
+ type ShortIdCommandRequest = {
311
+ operation: 'alloc' | 'release' | 'resolve' | 'list';
312
+ argument?: string;
313
+ activeDir: string;
314
+ shortIdLength: number;
315
+ verify?: boolean;
316
+ };
317
+ type ShortIdCommandResult = {
318
+ status: 'applied' | 'no-op' | 'failed';
319
+ changed: boolean;
320
+ output: string;
321
+ error: { code: string; message: string } | null;
322
+ };
323
+
324
+ function mutateShortIdRegistryAt(
325
+ activeDir: string,
326
+ width: number,
327
+ taskId: string,
328
+ requested: ShortIdMutationEffect
329
+ ): ShortIdMutationResult {
330
+ const registryPath = path.join(activeDir, REGISTRY_NAME);
331
+ return withRegistryLock(activeDir, () => {
332
+ const registry = readRegistryStrict(registryPath, width);
333
+ const original = JSON.stringify(registry.ids);
334
+ for (const [key, candidate] of Object.entries(registry.ids)) {
335
+ if (candidate !== taskId && !fs.existsSync(path.join(activeDir, candidate, 'task.md'))) delete registry.ids[key];
336
+ }
337
+ const existing = Object.entries(registry.ids).find(([, candidate]) => candidate === taskId);
338
+ let result: ShortIdMutationResult;
339
+ if (requested === 'alloc') {
340
+ if (!fs.existsSync(path.join(activeDir, taskId, 'task.md'))) {
341
+ throw Object.assign(new Error(`task ${taskId} not found in ${activeDir}`), { code: 'SHORT_ID_TASK_NOT_ACTIVE' });
342
+ }
343
+ if (existing) result = { effect: 'unchanged', shortId: existing[0], changed: false };
344
+ else {
345
+ let key: string | null = null;
346
+ for (let value = 1; value < 10 ** width; value += 1) {
347
+ const candidate = String(value).padStart(width, '0');
348
+ if (!registry.ids[candidate]) { key = candidate; break; }
349
+ }
350
+ if (!key) throw Object.assign(new Error(`short id width exhausted (current shortIdLength=${width})`), { code: 'SHORT_ID_CAPACITY_EXCEEDED' });
351
+ registry.ids[key] = taskId;
352
+ result = { effect: 'allocated', shortId: key, changed: true };
353
+ }
354
+ } else if (requested === 'release') {
355
+ if (!existing) result = { effect: 'unchanged', shortId: null, changed: false };
356
+ else { delete registry.ids[existing[0]]; result = { effect: 'released', shortId: existing[0], changed: true }; }
357
+ } else result = { effect: 'unchanged', shortId: existing ? existing[0] : null, changed: false };
358
+ const changed = original !== JSON.stringify(registry.ids);
359
+ if (changed) writeRegistry(registryPath, registry);
360
+ return { ...result, changed };
361
+ });
362
+ }
363
+
364
+ function executeShortIdCommand(request: ShortIdCommandRequest): ShortIdCommandResult {
365
+ try {
366
+ if (!Number.isInteger(request.shortIdLength) || request.shortIdLength < 1) {
367
+ throw Object.assign(new Error('short-id-length must be a positive integer'), { code: 'SHORT_ID_PAYLOAD_INVALID' });
368
+ }
369
+ if (request.operation === 'alloc' || request.operation === 'release') {
370
+ if (!request.argument || !/^TASK-\d{8}-\d{6}$/.test(request.argument)) {
371
+ throw Object.assign(new Error(`${request.operation} requires a full TASK-id`), { code: 'SHORT_ID_PAYLOAD_INVALID' });
372
+ }
373
+ const result = mutateShortIdRegistryAt(request.activeDir, request.shortIdLength, request.argument, request.operation);
374
+ return { status: result.changed ? 'applied' : 'no-op', changed: result.changed, output: result.shortId ?? '', error: null };
375
+ }
376
+ const registryPath = path.join(request.activeDir, REGISTRY_NAME);
377
+ if (request.operation === 'resolve') {
378
+ if (!request.argument) throw Object.assign(new Error('resolve requires a short id'), { code: 'SHORT_ID_PAYLOAD_INVALID' });
379
+ const normalized = normalizeShortIdInput(request.argument, { shortIdLength: request.shortIdLength });
380
+ if (normalized.kind === 'error') throw Object.assign(new Error(normalized.message), { code: normalized.code });
381
+ if (normalized.kind !== 'shortId') {
382
+ throw Object.assign(new Error(`invalid short id format '${request.argument}'`), { code: 'SHORT_ID_FORMAT_INVALID' });
383
+ }
384
+ return withRegistryLock(request.activeDir, () => {
385
+ const registry = readRegistryStrict(registryPath, request.shortIdLength);
386
+ let changed = false;
387
+ for (const [key, taskId] of Object.entries(registry.ids)) {
388
+ if (!fs.existsSync(path.join(request.activeDir, taskId, 'task.md'))) { delete registry.ids[key]; changed = true; }
389
+ }
390
+ if (changed) writeRegistry(registryPath, registry);
391
+ const taskId = registry.ids[normalized.value];
392
+ if (!taskId) throw Object.assign(new Error(`short id '${normalized.value}' not found in active task registry`), { code: 'SHORT_ID_NOT_FOUND' });
393
+ return { status: changed ? 'applied' : 'no-op', changed, output: taskId, error: null };
394
+ });
395
+ }
396
+ const registry = readRegistryStrict(registryPath, request.shortIdLength);
397
+ if (request.verify) {
398
+ const active = fs.existsSync(request.activeDir)
399
+ ? fs.readdirSync(request.activeDir).filter((entry) => /^TASK-\d{8}-\d{6}$/.test(entry) && fs.existsSync(path.join(request.activeDir, entry, 'task.md')))
400
+ : [];
401
+ const registered = new Map<string, string[]>();
402
+ for (const [key, taskId] of Object.entries(registry.ids)) registered.set(taskId, [...(registered.get(taskId) ?? []), key]);
403
+ const diff = {
404
+ missing_in_registry: active.filter((taskId) => !registered.has(taskId)).map((taskId) => ({ taskId })),
405
+ orphans_in_registry: Object.entries(registry.ids).filter(([, taskId]) => !active.includes(taskId)).map(([key, taskId]) => ({ key, taskId })),
406
+ duplicate_registry_keys: [...registered.entries()].filter(([, keys]) => keys.length > 1).map(([taskId, keys]) => ({ taskId, keys }))
407
+ };
408
+ const clean = Object.values(diff).every((items) => items.length === 0);
409
+ return { status: clean ? 'no-op' : 'failed', changed: false, output: clean ? '' : JSON.stringify(diff), error: clean ? null : { code: 'SHORT_ID_VERIFY_FAILED', message: 'registry differs from active tasks' } };
410
+ }
411
+ return { status: 'no-op', changed: false, output: JSON.stringify(registry, null, 2), error: null };
412
+ } catch (error) {
413
+ return { status: 'failed', changed: false, output: '', error: { code: (error as { code?: string }).code ?? 'SHORT_ID_OPERATION_FAILED', message: error instanceof Error ? error.message : String(error) } };
414
+ }
415
+ }
416
+
41
417
  function readRegistry(repoRoot: string): RegistrySchema | null {
42
418
  const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
43
419
  if (!fs.existsSync(registryPath)) return null;
@@ -65,13 +441,13 @@ function loadShortIdByTaskId(repoRoot: string): Map<string, string> {
65
441
  const map = new Map<string, string>();
66
442
  if (!registry) return map;
67
443
  for (const [key, taskId] of Object.entries(registry.ids)) {
68
- map.set(taskId, `#${key}`);
444
+ map.set(taskId, key);
69
445
  }
70
446
  return map;
71
447
  }
72
448
 
73
449
  /**
74
- * Resolve a branch to its active-task short id (`#NN`), or `null` when no
450
+ * Resolve a branch to its active-task short id (`NN`), or `null` when no
75
451
  * active task is bound to that branch.
76
452
  *
77
453
  * Two-state semantics: this only consults the active registry
@@ -91,7 +467,7 @@ function lookupShortIdByBranch(
91
467
  for (const [key, taskId] of Object.entries(registry.ids)) {
92
468
  const taskBranch = readBranchFromTaskMd(repoRoot, taskId);
93
469
  if (taskBranch && taskBranch === branch) {
94
- matches.push(`#${key}`);
470
+ matches.push(key);
95
471
  }
96
472
  }
97
473
  if (matches.length === 0) return null;
@@ -103,5 +479,23 @@ function lookupShortIdByBranch(
103
479
  return matches[0]!;
104
480
  }
105
481
 
106
- export { normalizeShortIdInput, lookupShortIdByBranch, loadShortIdByTaskId };
107
- export type { NormalizeResult, NormalizeOpts };
482
+ export {
483
+ normalizeShortIdInput,
484
+ isRemovedHashShortIdInput,
485
+ resolveShortIdReadOnly,
486
+ lookupShortIdByBranch,
487
+ loadShortIdByTaskId,
488
+ configuredShortIdLength,
489
+ mutateShortIdRegistry,
490
+ executeShortIdCommand
491
+ };
492
+ export type {
493
+ NormalizeResult,
494
+ NormalizeOpts,
495
+ ResolveShortIdErrorCode,
496
+ ResolveShortIdResult,
497
+ ShortIdMutationEffect,
498
+ ShortIdMutationResult,
499
+ ShortIdCommandRequest,
500
+ ShortIdCommandResult
501
+ };
@@ -0,0 +1,143 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+
5
+ import { resolveTaskRef } from './resolve-ref.ts';
6
+ import type { ResolveTaskRefErrorCode, TaskWorkspaceState } from './resolve-ref.ts';
7
+
8
+ type SnapshotObservationName = 'git' | 'task-directory' | 'task-tail';
9
+ type SnapshotObservation = {
10
+ name: SnapshotObservationName;
11
+ status: 'ready' | 'failed';
12
+ command: string;
13
+ output: string | null;
14
+ error: string | null;
15
+ };
16
+ type SnapshotErrorCode = ResolveTaskRefErrorCode
17
+ | 'SNAPSHOT_GIT_FAILED'
18
+ | 'SNAPSHOT_DIRECTORY_READ_FAILED'
19
+ | 'SNAPSHOT_TASK_READ_FAILED';
20
+ type TaskSnapshotResult = {
21
+ status: 'ready' | 'failed';
22
+ changed: false;
23
+ requestRef: string;
24
+ taskId: string | null;
25
+ taskDir: string | null;
26
+ taskState: TaskWorkspaceState | null;
27
+ observations: readonly SnapshotObservation[];
28
+ evidence: string | null;
29
+ error: { code: SnapshotErrorCode; message: string } | null;
30
+ };
31
+ type SnapshotOptions = {
32
+ repoRoot?: string;
33
+ gitStatus?: (repoRoot: string) => string;
34
+ readDirectory?: (taskDir: string) => fs.Dirent[];
35
+ lstat?: (entryPath: string) => fs.Stats;
36
+ readTask?: (taskMdPath: string) => string;
37
+ };
38
+
39
+ function relativeDisplay(repoRoot: string, target: string): string {
40
+ return path.relative(repoRoot, target).split(path.sep).join('/');
41
+ }
42
+
43
+ function stripOneTrailingNewline(value: string): string {
44
+ return value.endsWith('\r\n') ? value.slice(0, -2) : value.endsWith('\n') ? value.slice(0, -1) : value;
45
+ }
46
+
47
+ function defaultGitStatus(repoRoot: string): string {
48
+ return execFileSync('git', ['-c', 'core.quotePath=true', 'status', '--short', '--untracked-files=all'], {
49
+ cwd: repoRoot,
50
+ encoding: 'utf8',
51
+ stdio: ['pipe', 'pipe', 'pipe']
52
+ });
53
+ }
54
+
55
+ function displayName(name: string): string {
56
+ return /[\t\r\n]/.test(name) ? JSON.stringify(name) : name;
57
+ }
58
+
59
+ function renderDirectory(entries: fs.Dirent[], taskDir: string, lstat: (entryPath: string) => fs.Stats): string {
60
+ return [...entries]
61
+ .sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)
62
+ .map((entry) => {
63
+ const stat = lstat(path.join(taskDir, entry.name));
64
+ const type = stat.isSymbolicLink() ? 'l' : stat.isDirectory() ? 'd' : stat.isFile() ? 'f' : 'o';
65
+ const bytes = type === 'f' ? String(stat.size) : '-';
66
+ return `${type}\t${bytes}\t${displayName(entry.name)}`;
67
+ })
68
+ .join('\n');
69
+ }
70
+
71
+ function renderTail(content: string): string {
72
+ const normalized = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
73
+ if (normalized.length === 0) return '';
74
+ const lines = normalized.endsWith('\n') ? normalized.slice(0, -1).split('\n') : normalized.split('\n');
75
+ return lines.slice(-10).join('\n');
76
+ }
77
+
78
+ function renderTaskSnapshot(observations: readonly SnapshotObservation[]): string {
79
+ return observations.map((observation) => {
80
+ const output = observation.output === '' ? '(empty)' : observation.output;
81
+ return `${observation.command}\n${output}`;
82
+ }).join('\n');
83
+ }
84
+
85
+ function collectTaskSnapshot(taskRef: string, options: SnapshotOptions = {}): TaskSnapshotResult {
86
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
87
+ if (!resolved.ok) {
88
+ return {
89
+ status: 'failed', changed: false, requestRef: taskRef, taskId: resolved.taskId,
90
+ taskDir: null, taskState: null, observations: [], evidence: null,
91
+ error: { code: resolved.code, message: resolved.message }
92
+ };
93
+ }
94
+
95
+ const taskPath = relativeDisplay(resolved.repoRoot, resolved.taskMdPath);
96
+ const taskDirPath = relativeDisplay(resolved.repoRoot, resolved.taskDir);
97
+ const observations: SnapshotObservation[] = [];
98
+ try {
99
+ const output = stripOneTrailingNewline((options.gitStatus ?? defaultGitStatus)(resolved.repoRoot));
100
+ observations.push({ name: 'git', status: 'ready', command: '$ git status -s', output, error: null });
101
+ } catch (error) {
102
+ return failedSnapshot(resolved, taskRef, observations, 'git', '$ git status -s', 'SNAPSHOT_GIT_FAILED', error);
103
+ }
104
+ try {
105
+ const entries = (options.readDirectory ?? ((dir) => fs.readdirSync(dir, { withFileTypes: true })))(resolved.taskDir);
106
+ const output = renderDirectory(entries, resolved.taskDir, options.lstat ?? fs.lstatSync);
107
+ observations.push({ name: 'task-directory', status: 'ready', command: `$ ls -la ${taskDirPath}/`, output, error: null });
108
+ } catch (error) {
109
+ return failedSnapshot(resolved, taskRef, observations, 'task-directory', `$ ls -la ${taskDirPath}/`, 'SNAPSHOT_DIRECTORY_READ_FAILED', error);
110
+ }
111
+ try {
112
+ const content = (options.readTask ?? ((file) => fs.readFileSync(file, 'utf8')))(resolved.taskMdPath);
113
+ observations.push({ name: 'task-tail', status: 'ready', command: `$ tail ${taskPath}`, output: renderTail(content), error: null });
114
+ } catch (error) {
115
+ return failedSnapshot(resolved, taskRef, observations, 'task-tail', `$ tail ${taskPath}`, 'SNAPSHOT_TASK_READ_FAILED', error);
116
+ }
117
+ return {
118
+ status: 'ready', changed: false, requestRef: taskRef, taskId: resolved.taskId,
119
+ taskDir: resolved.taskDir, taskState: resolved.state, observations,
120
+ evidence: renderTaskSnapshot(observations), error: null
121
+ };
122
+ }
123
+
124
+ function failedSnapshot(
125
+ resolved: Extract<ReturnType<typeof resolveTaskRef>, { ok: true }>,
126
+ taskRef: string,
127
+ observations: SnapshotObservation[],
128
+ name: SnapshotObservationName,
129
+ command: string,
130
+ code: SnapshotErrorCode,
131
+ error: unknown
132
+ ): TaskSnapshotResult {
133
+ const message = error instanceof Error ? error.message : String(error);
134
+ observations.push({ name, status: 'failed', command, output: null, error: message });
135
+ return {
136
+ status: 'failed', changed: false, requestRef: taskRef, taskId: resolved.taskId,
137
+ taskDir: resolved.taskDir, taskState: resolved.state, observations,
138
+ evidence: null, error: { code, message }
139
+ };
140
+ }
141
+
142
+ export { collectTaskSnapshot, renderTaskSnapshot };
143
+ export type { SnapshotErrorCode, SnapshotObservation, SnapshotOptions, TaskSnapshotResult };
@@ -0,0 +1,9 @@
1
+ const LOCAL_VERIFICATION_CHECKS = [
2
+ 'task-meta', 'artifact', 'implementation-input', 'activity-log', 'completion-checklist'
3
+ ] as const;
4
+
5
+ function isLocalVerificationCheck(value: string): value is typeof LOCAL_VERIFICATION_CHECKS[number] {
6
+ return (LOCAL_VERIFICATION_CHECKS as readonly string[]).includes(value);
7
+ }
8
+
9
+ export { LOCAL_VERIFICATION_CHECKS, isLocalVerificationCheck };
@@ -0,0 +1,20 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ type VerificationConfig = {
5
+ skill?: string;
6
+ checks: Record<string, Record<string, unknown> | null>;
7
+ };
8
+
9
+ function loadVerificationConfig(repositoryRoot: string, skillName: string): VerificationConfig {
10
+ const verifyPath = path.join(repositoryRoot, '.agents', 'skills', skillName, 'config', 'verify.json');
11
+ if (!fs.existsSync(verifyPath)) throw new Error(`config/verify.json not found for skill '${skillName}'`);
12
+ const parsed = JSON.parse(fs.readFileSync(verifyPath, 'utf8')) as Partial<VerificationConfig>;
13
+ if (!parsed.checks || typeof parsed.checks !== 'object' || Array.isArray(parsed.checks)) {
14
+ throw new Error(`config/verify.json has invalid checks for skill '${skillName}'`);
15
+ }
16
+ return { ...(parsed.skill ? { skill: parsed.skill } : {}), checks: parsed.checks };
17
+ }
18
+
19
+ export { loadVerificationConfig };
20
+ export type { VerificationConfig };