@fitlab-ai/agent-infra 0.8.5 → 0.9.0

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 (425) hide show
  1. package/bin/cli.ts +2 -2
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/bin/internal-cli.js +98 -0
  4. package/dist/lib/decide.js +81 -90
  5. package/dist/lib/defaults.json +1 -0
  6. package/dist/lib/git/review-snapshot.js +79 -0
  7. package/dist/lib/git/workflow.js +101 -0
  8. package/dist/lib/internal/git-workflow.js +42 -0
  9. package/dist/lib/internal/platform-checks.js +119 -0
  10. package/dist/lib/internal/platform-comment.js +129 -0
  11. package/dist/lib/internal/platform-context.js +46 -0
  12. package/dist/lib/internal/platform-issue.js +142 -0
  13. package/dist/lib/internal/platform-pr.js +146 -0
  14. package/dist/lib/internal/release-workflow.js +217 -0
  15. package/dist/lib/internal/task-artifact.js +67 -0
  16. package/dist/lib/internal/task-context.js +43 -0
  17. package/dist/lib/internal/task-event.js +70 -0
  18. package/dist/lib/internal/task-ledger.js +114 -0
  19. package/dist/lib/internal/task-lifecycle.js +58 -0
  20. package/dist/lib/internal/task-short-id.js +83 -0
  21. package/dist/lib/internal/task-snapshot.js +47 -0
  22. package/dist/lib/internal/task-verify.js +50 -0
  23. package/dist/lib/internal/task-warning.js +74 -0
  24. package/dist/lib/platform/adapters.js +14 -0
  25. package/dist/lib/platform/context.js +146 -0
  26. package/dist/lib/platform/github-client.js +124 -0
  27. package/dist/lib/platform/issue-comments.js +409 -0
  28. package/dist/lib/platform/issue-metadata.js +183 -0
  29. package/dist/lib/platform/issues.js +617 -0
  30. package/dist/lib/platform/metadata-labels.js +28 -0
  31. package/dist/lib/platform/pr-checks.js +216 -0
  32. package/dist/lib/platform/pr-summary.js +88 -0
  33. package/dist/lib/platform/pull-request-metadata.js +38 -0
  34. package/dist/lib/platform/pull-requests.js +338 -0
  35. package/dist/lib/platform/releases.js +82 -0
  36. package/dist/lib/platform/types.js +22 -0
  37. package/dist/lib/platform/verification-required.js +78 -0
  38. package/dist/lib/platform/verification-sync.js +1014 -0
  39. package/dist/lib/platform/verification.js +6 -0
  40. package/dist/lib/release/channels.js +31 -0
  41. package/dist/lib/release/workflow.js +32 -0
  42. package/dist/lib/render.js +3 -2
  43. package/dist/lib/run/index.js +24 -7
  44. package/dist/lib/sandbox/capture.js +25 -3
  45. package/dist/lib/sandbox/commands/create.js +36 -22
  46. package/dist/lib/sandbox/commands/enter.js +34 -11
  47. package/dist/lib/sandbox/commands/list-running.js +10 -8
  48. package/dist/lib/sandbox/commands/show.js +2 -2
  49. package/dist/lib/sandbox/commands/start.js +53 -15
  50. package/dist/lib/sandbox/index.js +6 -6
  51. package/dist/lib/sandbox/mounts.js +36 -0
  52. package/dist/lib/sandbox/recovery.js +562 -0
  53. package/dist/lib/sandbox/task-resolver.js +5 -1
  54. package/dist/lib/sandbox/tools.js +19 -0
  55. package/dist/lib/server/protocol.js +5 -5
  56. package/dist/lib/task/activity-log.js +61 -0
  57. package/dist/lib/task/artifact-lifecycle.js +427 -0
  58. package/dist/lib/task/command-options.js +30 -0
  59. package/dist/lib/task/commands/cat.js +36 -6
  60. package/dist/lib/task/commands/decisions.js +80 -46
  61. package/dist/lib/task/commands/files.js +21 -7
  62. package/dist/lib/task/commands/grep.js +55 -7
  63. package/dist/lib/task/commands/issue-body.js +23 -14
  64. package/dist/lib/task/commands/log.js +27 -70
  65. package/dist/lib/task/commands/show.js +20 -7
  66. package/dist/lib/task/commands/status.js +18 -8
  67. package/dist/lib/task/decision-intents.js +154 -0
  68. package/dist/lib/task/decision-items.js +53 -0
  69. package/dist/lib/task/events.js +318 -0
  70. package/dist/lib/task/frontmatter.js +159 -1
  71. package/dist/lib/task/implementation-inputs.js +117 -0
  72. package/dist/lib/task/index.js +12 -9
  73. package/dist/lib/task/issue-form.js +19 -6
  74. package/dist/lib/task/ledger-intents.js +185 -0
  75. package/dist/lib/task/ledger.js +65 -35
  76. package/dist/lib/task/lifecycle.js +484 -0
  77. package/dist/lib/task/resolve-ref.js +152 -32
  78. package/dist/lib/task/review-artifacts.js +101 -0
  79. package/dist/lib/task/review-fingerprint.js +46 -0
  80. package/dist/lib/task/sections.js +358 -4
  81. package/dist/lib/task/short-id.js +292 -7
  82. package/dist/lib/task/snapshot.js +95 -0
  83. package/dist/lib/task/verification-checks.js +8 -0
  84. package/dist/lib/task/verification-config.js +14 -0
  85. package/dist/lib/task/verification-engine.js +906 -0
  86. package/dist/lib/task/verification-review.js +3 -0
  87. package/dist/lib/task/verification-types.js +2 -0
  88. package/dist/lib/task/verification.js +113 -0
  89. package/dist/lib/task/workflow-warning-intents.js +131 -0
  90. package/dist/lib/task/workflow-warnings.js +10 -78
  91. package/dist/lib/task/write.js +241 -0
  92. package/lib/decide.ts +57 -97
  93. package/lib/defaults.json +1 -0
  94. package/lib/git/review-snapshot.ts +73 -0
  95. package/lib/git/workflow.ts +101 -0
  96. package/lib/internal/git-workflow.ts +37 -0
  97. package/lib/internal/platform-checks.ts +101 -0
  98. package/lib/internal/platform-comment.ts +99 -0
  99. package/lib/internal/platform-context.ts +33 -0
  100. package/lib/internal/platform-issue.ts +116 -0
  101. package/lib/internal/platform-pr.ts +119 -0
  102. package/lib/internal/release-workflow.ts +186 -0
  103. package/lib/internal/task-artifact.ts +47 -0
  104. package/lib/internal/task-context.ts +35 -0
  105. package/lib/internal/task-event.ts +51 -0
  106. package/lib/internal/task-ledger.ts +86 -0
  107. package/lib/internal/task-lifecycle.ts +41 -0
  108. package/lib/internal/task-short-id.ts +55 -0
  109. package/lib/internal/task-snapshot.ts +32 -0
  110. package/lib/internal/task-verify.ts +33 -0
  111. package/lib/internal/task-warning.ts +50 -0
  112. package/lib/platform/adapters.ts +30 -0
  113. package/lib/platform/context.ts +164 -0
  114. package/lib/platform/github-client.ts +146 -0
  115. package/lib/platform/issue-comments.ts +479 -0
  116. package/lib/platform/issue-metadata.ts +250 -0
  117. package/lib/platform/issues.ts +691 -0
  118. package/lib/platform/metadata-labels.ts +33 -0
  119. package/lib/platform/pr-checks.ts +246 -0
  120. package/lib/platform/pr-summary.ts +90 -0
  121. package/lib/platform/pull-request-metadata.ts +69 -0
  122. package/lib/platform/pull-requests.ts +380 -0
  123. package/lib/platform/releases.ts +71 -0
  124. package/lib/platform/types.ts +74 -0
  125. package/lib/platform/verification-required.ts +83 -0
  126. package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
  127. package/lib/platform/verification.ts +11 -0
  128. package/lib/release/channels.ts +30 -0
  129. package/lib/release/workflow.ts +31 -0
  130. package/lib/render.ts +3 -2
  131. package/lib/run/index.ts +25 -7
  132. package/lib/sandbox/capture.ts +29 -3
  133. package/lib/sandbox/commands/create.ts +43 -25
  134. package/lib/sandbox/commands/enter.ts +38 -11
  135. package/lib/sandbox/commands/list-running.ts +10 -8
  136. package/lib/sandbox/commands/show.ts +2 -2
  137. package/lib/sandbox/commands/start.ts +50 -16
  138. package/lib/sandbox/index.ts +6 -6
  139. package/lib/sandbox/mounts.ts +55 -0
  140. package/lib/sandbox/recovery.ts +828 -0
  141. package/lib/sandbox/task-resolver.ts +5 -1
  142. package/lib/sandbox/tools.ts +31 -0
  143. package/lib/server/protocol.ts +5 -5
  144. package/lib/task/activity-log.ts +62 -0
  145. package/lib/task/artifact-lifecycle.ts +484 -0
  146. package/lib/task/command-options.ts +32 -0
  147. package/lib/task/commands/cat.ts +22 -9
  148. package/lib/task/commands/decisions.ts +49 -47
  149. package/lib/task/commands/files.ts +14 -6
  150. package/lib/task/commands/grep.ts +34 -7
  151. package/lib/task/commands/issue-body.ts +16 -16
  152. package/lib/task/commands/log.ts +17 -70
  153. package/lib/task/commands/show.ts +14 -6
  154. package/lib/task/commands/status.ts +17 -7
  155. package/lib/task/decision-intents.ts +163 -0
  156. package/lib/task/decision-items.ts +64 -0
  157. package/lib/task/events.ts +320 -0
  158. package/lib/task/frontmatter.ts +202 -2
  159. package/lib/task/implementation-inputs.ts +137 -0
  160. package/lib/task/index.ts +12 -9
  161. package/lib/task/issue-form.ts +20 -6
  162. package/lib/task/ledger-intents.ts +201 -0
  163. package/lib/task/ledger.ts +77 -31
  164. package/lib/task/lifecycle.ts +458 -0
  165. package/lib/task/resolve-ref.ts +197 -36
  166. package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
  167. package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +17 -12
  168. package/lib/task/sections.ts +486 -4
  169. package/lib/task/short-id.ts +403 -9
  170. package/lib/task/snapshot.ts +143 -0
  171. package/lib/task/verification-checks.ts +9 -0
  172. package/lib/task/verification-config.ts +20 -0
  173. package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +199 -406
  174. package/lib/task/verification-review.ts +9 -0
  175. package/lib/task/verification-types.ts +29 -0
  176. package/lib/task/verification.ts +156 -0
  177. package/lib/task/workflow-warning-intents.ts +142 -0
  178. package/lib/task/workflow-warnings.ts +10 -78
  179. package/lib/task/write.ts +468 -0
  180. package/package.json +4 -2
  181. package/templates/.agents/README.en.md +4 -3
  182. package/templates/.agents/README.zh-CN.md +4 -3
  183. package/templates/.agents/rules/README.en.md +6 -5
  184. package/templates/.agents/rules/README.zh-CN.md +6 -5
  185. package/templates/.agents/rules/create-issue.en.md +1 -1
  186. package/templates/.agents/rules/create-issue.github.en.md +5 -184
  187. package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
  188. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  189. package/templates/.agents/rules/human-decision-context.en.md +36 -0
  190. package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
  191. package/templates/.agents/rules/issue-fields.github.en.md +4 -148
  192. package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
  193. package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
  194. package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
  195. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
  196. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
  197. package/templates/.agents/rules/issue-sync.en.md +1 -1
  198. package/templates/.agents/rules/issue-sync.github.en.md +14 -301
  199. package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
  200. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  201. package/templates/.agents/rules/milestone-inference.en.md +1 -1
  202. package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
  203. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
  204. package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
  205. package/templates/.agents/rules/next-step-output.en.md +12 -11
  206. package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
  207. package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
  208. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
  209. package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
  210. package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
  211. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
  212. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
  213. package/templates/.agents/rules/pr-sync.en.md +30 -3
  214. package/templates/.agents/rules/pr-sync.github.en.md +12 -115
  215. package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
  216. package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
  217. package/templates/.agents/rules/review-handshake.en.md +8 -5
  218. package/templates/.agents/rules/review-handshake.zh-CN.md +8 -5
  219. package/templates/.agents/rules/task-management.en.md +11 -2
  220. package/templates/.agents/rules/task-management.zh-CN.md +11 -3
  221. package/templates/.agents/rules/task-short-id.en.md +25 -29
  222. package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
  223. package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
  224. package/templates/.agents/scripts/task-short-id.js +71 -533
  225. package/templates/.agents/skills/analyze-task/SKILL.en.md +22 -55
  226. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +26 -59
  227. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
  228. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
  229. package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
  230. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
  231. package/templates/.agents/skills/block-task/config/verify.json +1 -2
  232. package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
  233. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
  234. package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
  235. package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
  236. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
  237. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
  238. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
  239. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
  240. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
  241. package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
  242. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
  243. package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
  244. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
  245. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
  246. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
  247. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
  248. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
  249. package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
  250. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
  251. package/templates/.agents/skills/commit/SKILL.en.md +13 -11
  252. package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
  253. package/templates/.agents/skills/commit/config/verify.json +1 -2
  254. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
  255. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
  256. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
  257. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
  258. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
  259. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
  260. package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
  261. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
  262. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
  263. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
  264. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
  265. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
  266. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
  267. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
  268. package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
  269. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
  270. package/templates/.agents/skills/complete-task/config/verify.en.json +11 -7
  271. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +11 -7
  272. package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
  273. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
  274. package/templates/.agents/skills/create-pr/config/verify.json +1 -2
  275. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
  276. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
  277. package/templates/.agents/skills/create-task/SKILL.en.md +12 -13
  278. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +12 -13
  279. package/templates/.agents/skills/create-task/config/verify.json +1 -2
  280. package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
  281. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
  282. package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
  283. package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
  284. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
  285. package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
  286. package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
  287. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
  288. package/templates/.agents/skills/import-issue/config/verify.json +1 -2
  289. package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
  290. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
  291. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
  292. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
  293. package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
  294. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
  295. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  296. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  297. package/templates/.agents/skills/release/SKILL.en.md +16 -163
  298. package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
  299. package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
  300. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
  301. package/templates/.agents/skills/restore-task/config/verify.json +1 -2
  302. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
  303. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
  304. package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
  305. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
  306. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
  307. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
  308. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
  309. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
  310. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
  311. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
  312. package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
  313. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
  314. package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
  315. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
  316. package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
  317. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
  318. package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
  319. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
  320. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
  321. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
  322. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
  323. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
  324. package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
  325. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
  326. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
  327. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
  328. package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
  329. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
  330. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
  331. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
  332. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
  333. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
  334. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
  335. package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
  336. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
  337. package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
  338. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  339. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  340. package/templates/.agents/templates/task.en.md +6 -1
  341. package/templates/.agents/templates/task.zh-CN.md +6 -1
  342. package/templates/.claude/commands/analyze-task.en.md +1 -1
  343. package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
  344. package/templates/.claude/commands/block-task.en.md +1 -1
  345. package/templates/.claude/commands/block-task.zh-CN.md +1 -1
  346. package/templates/.claude/commands/cancel-task.en.md +1 -1
  347. package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
  348. package/templates/.claude/commands/check-task.en.md +1 -1
  349. package/templates/.claude/commands/check-task.zh-CN.md +1 -1
  350. package/templates/.claude/commands/code-task.en.md +1 -1
  351. package/templates/.claude/commands/code-task.zh-CN.md +1 -1
  352. package/templates/.claude/commands/commit.en.md +1 -0
  353. package/templates/.claude/commands/commit.zh-CN.md +1 -0
  354. package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
  355. package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
  356. package/templates/.claude/commands/complete-task.en.md +1 -1
  357. package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
  358. package/templates/.claude/commands/create-pr.en.md +1 -1
  359. package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
  360. package/templates/.claude/commands/plan-task.en.md +1 -1
  361. package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
  362. package/templates/.claude/commands/review-analysis.en.md +1 -1
  363. package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
  364. package/templates/.claude/commands/review-code.en.md +1 -1
  365. package/templates/.claude/commands/review-code.zh-CN.md +1 -1
  366. package/templates/.claude/commands/review-plan.en.md +1 -1
  367. package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
  368. package/templates/.claude/commands/watch-pr.en.md +1 -1
  369. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  370. package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
  371. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
  372. package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
  373. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
  374. package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
  375. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
  376. package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
  377. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
  378. package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
  379. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
  380. package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
  381. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
  382. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
  383. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
  384. package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
  385. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
  386. package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
  387. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
  388. package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
  389. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
  390. package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
  391. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
  392. package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
  393. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
  394. package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
  395. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
  396. package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
  397. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
  398. package/templates/.git-hooks/check-large-files.cjs +92 -0
  399. package/templates/.git-hooks/check-version-format.sh +5 -1
  400. package/templates/.git-hooks/pre-commit +1 -0
  401. package/templates/.opencode/commands/analyze-task.en.md +1 -1
  402. package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
  403. package/templates/.opencode/commands/check-task.en.md +1 -1
  404. package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
  405. package/templates/.opencode/commands/code-task.en.md +1 -1
  406. package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
  407. package/templates/.opencode/commands/commit.en.md +2 -0
  408. package/templates/.opencode/commands/commit.zh-CN.md +2 -0
  409. package/templates/.opencode/commands/complete-task.en.md +1 -1
  410. package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
  411. package/templates/.opencode/commands/plan-task.en.md +1 -1
  412. package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
  413. package/templates/.opencode/commands/review-analysis.en.md +1 -1
  414. package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
  415. package/templates/.opencode/commands/review-code.en.md +1 -1
  416. package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
  417. package/templates/.opencode/commands/review-plan.en.md +1 -1
  418. package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
  419. package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
  420. package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
  421. package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
  422. package/templates/.agents/scripts/workflow-warnings.js +0 -290
  423. package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
  424. package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
  425. package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
@@ -1,7 +1,469 @@
1
+ import type { FrontmatterScalar } from './frontmatter.ts';
2
+
1
3
  function escapeRegExp(value: string): string {
2
4
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3
5
  }
4
6
 
7
+ type SectionMutationInput = {
8
+ aliases: readonly string[];
9
+ heading: string;
10
+ body: string;
11
+ };
12
+
13
+ type TableRowBase = {
14
+ kind: 'table-row';
15
+ sectionAliases: readonly string[];
16
+ columns: readonly string[];
17
+ keyColumn: string;
18
+ key: string;
19
+ };
20
+
21
+ type TableRowUpsertMutation = TableRowBase & {
22
+ action: 'upsert';
23
+ values: Readonly<Record<string, FrontmatterScalar>>;
24
+ };
25
+
26
+ type TableRowDeleteMutation = TableRowBase & { action: 'delete' };
27
+ type TableRowMutation = TableRowUpsertMutation | TableRowDeleteMutation;
28
+
29
+ type SectionMutationResult = {
30
+ content: string;
31
+ heading: string;
32
+ operation: 'create' | 'update';
33
+ };
34
+
35
+ type TableMutationResult = {
36
+ content: string;
37
+ section: string;
38
+ operation: 'insert' | 'update' | 'delete';
39
+ };
40
+
41
+ type ParsedTableRow = {
42
+ values: Readonly<Record<string, string>>;
43
+ sourceLine: number;
44
+ };
45
+
46
+ type ParsedTable = {
47
+ heading: string;
48
+ rows: readonly ParsedTableRow[];
49
+ };
50
+
51
+ type DocumentMutationErrorCode =
52
+ | 'TASK_DOCUMENT_INVALID'
53
+ | 'MUTATION_INVALID'
54
+ | 'TABLE_NOT_FOUND'
55
+ | 'TABLE_AMBIGUOUS'
56
+ | 'TABLE_DUPLICATE_KEY'
57
+ | 'TABLE_UNKNOWN_COLUMN'
58
+ | 'TABLE_KEY_COLUMN_IN_VALUES'
59
+ | 'TABLE_KEY_CONFLICT'
60
+ | 'TABLE_MISSING_COLUMN'
61
+ | 'TABLE_DELETE_VALUES_FORBIDDEN'
62
+ | 'TABLE_CELL_INVALID';
63
+
64
+ class DocumentMutationError extends Error {
65
+ code: DocumentMutationErrorCode;
66
+
67
+ constructor(code: DocumentMutationErrorCode, message: string) {
68
+ super(message);
69
+ this.name = 'DocumentMutationError';
70
+ this.code = code;
71
+ }
72
+ }
73
+
74
+ function parseTable(
75
+ content: string,
76
+ input: { sectionAliases: readonly string[]; columns: readonly string[] }
77
+ ): ParsedTable | null {
78
+ validateAliases(input.sectionAliases, 'table section aliases');
79
+ if (
80
+ !Array.isArray(input.columns) || input.columns.length === 0 ||
81
+ input.columns.some((column) => !column || /[\r\n|]/.test(column)) ||
82
+ new Set(input.columns).size !== input.columns.length
83
+ ) {
84
+ throw new DocumentMutationError('MUTATION_INVALID', 'table columns are invalid');
85
+ }
86
+ const sections = matchingSections(content, input.sectionAliases);
87
+ if (sections.length === 0) return null;
88
+ if (sections.length > 1) {
89
+ throw new DocumentMutationError('TASK_DOCUMENT_INVALID', 'table section is ambiguous');
90
+ }
91
+ const section = sections[0]!;
92
+ const sectionLines = linesOf(content).filter(
93
+ (line) => line.start >= section.bodyStart && line.start < section.end
94
+ );
95
+ const firstContent = sectionLines.findIndex((line) => line.text.trim() !== '');
96
+ const tables: number[] = [];
97
+ for (let index = 0; index + 1 < sectionLines.length; index += 1) {
98
+ const header = splitTableCells(sectionLines[index]!.text);
99
+ const separator = splitTableCells(sectionLines[index + 1]!.text);
100
+ if (!header || !separator || header.cells.length !== input.columns.length) continue;
101
+ const names = header.cells.map((cell) => decodeCell(cell).trim());
102
+ if (!names.every((name, column) => name === input.columns[column])) continue;
103
+ if (
104
+ separator.cells.length === input.columns.length &&
105
+ separator.cells.every((cell) => /^\s*:?-{3,}:?\s*$/.test(cell))
106
+ ) tables.push(index);
107
+ }
108
+ if (tables.length === 0) {
109
+ throw new DocumentMutationError('TABLE_NOT_FOUND', 'matching table not found');
110
+ }
111
+ if (tables.length > 1) {
112
+ throw new DocumentMutationError('TABLE_AMBIGUOUS', 'matching table appears more than once');
113
+ }
114
+ const rows: ParsedTableRow[] = [];
115
+ const seen = new Set<string>();
116
+ for (let index = tables[0]! + 2; index < sectionLines.length; index += 1) {
117
+ const line = sectionLines[index]!;
118
+ if (!line.text.trim()) break;
119
+ const parsed = splitTableCells(line.text);
120
+ if (!parsed) break;
121
+ if (parsed.cells.length !== input.columns.length) {
122
+ throw new DocumentMutationError('TASK_DOCUMENT_INVALID', 'table row has the wrong column count');
123
+ }
124
+ const values = Object.fromEntries(input.columns.map((column, columnIndex) => [
125
+ column,
126
+ decodeCell(parsed.cells[columnIndex]!).trim()
127
+ ]));
128
+ const key = values[input.columns[0]!]!;
129
+ if (seen.has(key)) {
130
+ throw new DocumentMutationError('TABLE_DUPLICATE_KEY', `duplicate table key '${key}'`);
131
+ }
132
+ seen.add(key);
133
+ rows.push({ values, sourceLine: index - Math.max(firstContent, 0) });
134
+ }
135
+ return { heading: section.heading, rows };
136
+ }
137
+
138
+ type Line = {
139
+ start: number;
140
+ contentEnd: number;
141
+ end: number;
142
+ text: string;
143
+ eol: string;
144
+ };
145
+
146
+ function linesOf(content: string): Line[] {
147
+ const lines: Line[] = [];
148
+ let start = 0;
149
+ while (start < content.length) {
150
+ const newline = content.indexOf('\n', start);
151
+ const end = newline === -1 ? content.length : newline + 1;
152
+ const hasCr = newline !== -1 && content[newline - 1] === '\r';
153
+ const contentEnd = newline === -1 ? content.length : newline - (hasCr ? 1 : 0);
154
+ lines.push({
155
+ start,
156
+ contentEnd,
157
+ end,
158
+ text: content.slice(start, contentEnd),
159
+ eol: newline === -1 ? '' : hasCr ? '\r\n' : '\n'
160
+ });
161
+ start = end;
162
+ }
163
+ return lines;
164
+ }
165
+
166
+ function documentEol(content: string): '\n' | '\r\n' {
167
+ return content.includes('\r\n') ? '\r\n' : '\n';
168
+ }
169
+
170
+ function matchingSections(content: string, aliases: readonly string[]) {
171
+ const allowed = new Set(aliases);
172
+ return linesOf(content)
173
+ .map((line, index, lines) => {
174
+ const match = /^##\s+(.+?)\s*$/.exec(line.text);
175
+ if (!match?.[1] || !allowed.has(match[1])) return null;
176
+ let end = content.length;
177
+ for (let i = index + 1; i < lines.length; i += 1) {
178
+ if (/^##\s+/.test(lines[i]!.text)) {
179
+ end = lines[i]!.start;
180
+ break;
181
+ }
182
+ }
183
+ return { heading: match[1], line, bodyStart: line.end, end };
184
+ })
185
+ .filter((match): match is NonNullable<typeof match> => match !== null);
186
+ }
187
+
188
+ function validateAliases(aliases: readonly string[], name: string): void {
189
+ if (!Array.isArray(aliases) || aliases.length === 0 || aliases.some((alias) => !alias || /[\r\n]/.test(alias))) {
190
+ throw new DocumentMutationError('MUTATION_INVALID', `${name} must contain headings`);
191
+ }
192
+ if (new Set(aliases).size !== aliases.length) {
193
+ throw new DocumentMutationError('MUTATION_INVALID', `${name} must be unique`);
194
+ }
195
+ }
196
+
197
+ function upsertSection(content: string, input: SectionMutationInput): SectionMutationResult {
198
+ validateAliases(input.aliases, 'section aliases');
199
+ if (!input.heading || /[\r\n]/.test(input.heading) || typeof input.body !== 'string') {
200
+ throw new DocumentMutationError('MUTATION_INVALID', 'section heading and body are invalid');
201
+ }
202
+ const matches = matchingSections(content, input.aliases);
203
+ if (matches.length > 1) {
204
+ throw new DocumentMutationError('TASK_DOCUMENT_INVALID', 'section aliases match more than once');
205
+ }
206
+ const eol = documentEol(content);
207
+ const normalizedBody = input.body.replace(/\r?\n/g, eol).replace(/(?:\r?\n)+$/, '');
208
+ if (matches.length === 0) {
209
+ const separator = content.length === 0
210
+ ? ''
211
+ : content.endsWith(`${eol}${eol}`)
212
+ ? ''
213
+ : content.endsWith(eol)
214
+ ? eol
215
+ : `${eol}${eol}`;
216
+ const body = normalizedBody ? `${eol}${eol}${normalizedBody}` : '';
217
+ return {
218
+ content: `${content}${separator}## ${input.heading}${body}${eol}`,
219
+ heading: input.heading,
220
+ operation: 'create'
221
+ };
222
+ }
223
+ const match = matches[0]!;
224
+ const existingBody = content
225
+ .slice(match.bodyStart, match.end)
226
+ .replace(/^(?:\r?\n)+/, '')
227
+ .replace(/(?:\r?\n)+$/, '')
228
+ .replace(/\r?\n/g, eol);
229
+ if (existingBody === normalizedBody) {
230
+ return { content, heading: match.heading, operation: 'update' };
231
+ }
232
+ const body = normalizedBody ? `${eol}${normalizedBody}${eol}${eol}` : eol;
233
+ return {
234
+ content: content.slice(0, match.bodyStart) + body + content.slice(match.end),
235
+ heading: match.heading,
236
+ operation: 'update'
237
+ };
238
+ }
239
+
240
+ function splitTableCells(line: string): { prefix: string; suffix: string; cells: string[] } | null {
241
+ const first = line.indexOf('|');
242
+ const last = line.lastIndexOf('|');
243
+ if (first === -1 || first === last || line.slice(0, first).trim() || line.slice(last + 1).trim()) {
244
+ return null;
245
+ }
246
+ const inner = line.slice(first + 1, last);
247
+ const cells: string[] = [];
248
+ let start = 0;
249
+ let backslashes = 0;
250
+ for (let i = 0; i < inner.length; i += 1) {
251
+ const char = inner[i]!;
252
+ if (char === '\\') {
253
+ backslashes += 1;
254
+ continue;
255
+ }
256
+ if (char === '|' && backslashes % 2 === 0) {
257
+ cells.push(inner.slice(start, i));
258
+ start = i + 1;
259
+ }
260
+ backslashes = 0;
261
+ }
262
+ if (backslashes % 2 === 1) {
263
+ throw new DocumentMutationError('TASK_DOCUMENT_INVALID', 'table cell has an unclosed escape');
264
+ }
265
+ cells.push(inner.slice(start));
266
+ return { prefix: line.slice(0, first), suffix: line.slice(last + 1), cells };
267
+ }
268
+
269
+ function decodeCell(raw: string): string {
270
+ let result = '';
271
+ for (let i = 0; i < raw.length; i += 1) {
272
+ if (raw[i] === '\\' && (raw[i + 1] === '\\' || raw[i + 1] === '|')) {
273
+ result += raw[i + 1];
274
+ i += 1;
275
+ } else {
276
+ result += raw[i];
277
+ }
278
+ }
279
+ return result;
280
+ }
281
+
282
+ function scalarCell(value: FrontmatterScalar): string {
283
+ if (typeof value === 'number' && !Number.isFinite(value)) {
284
+ throw new DocumentMutationError('TABLE_CELL_INVALID', 'table numbers must be finite');
285
+ }
286
+ if (
287
+ value !== null &&
288
+ typeof value !== 'string' &&
289
+ typeof value !== 'number' &&
290
+ typeof value !== 'boolean'
291
+ ) {
292
+ throw new DocumentMutationError('TABLE_CELL_INVALID', 'table cells must be scalar');
293
+ }
294
+ const raw = value === null ? '' : String(value);
295
+ if (/[\r\n]/.test(raw)) {
296
+ throw new DocumentMutationError('TABLE_CELL_INVALID', 'table cells cannot contain newlines');
297
+ }
298
+ return raw.replace(/\\/g, '\\\\').replace(/\|/g, '\\|');
299
+ }
300
+
301
+ function replaceCellToken(raw: string, value: string): string {
302
+ const firstContent = raw.search(/\S/);
303
+ if (firstContent === -1) {
304
+ const boundary = Math.floor(raw.length / 2);
305
+ return `${raw.slice(0, boundary)}${value}${raw.slice(boundary)}`;
306
+ }
307
+ let lastContent = raw.length - 1;
308
+ while (/\s/.test(raw[lastContent]!)) lastContent -= 1;
309
+ return `${raw.slice(0, firstContent)}${value}${raw.slice(lastContent + 1)}`;
310
+ }
311
+
312
+ function mutateTableRow(content: string, mutation: TableRowMutation): TableMutationResult {
313
+ validateAliases(mutation.sectionAliases, 'table section aliases');
314
+ if (
315
+ !Array.isArray(mutation.columns) ||
316
+ mutation.columns.length === 0 ||
317
+ mutation.columns.some((column) => !column || /[\r\n|]/.test(column)) ||
318
+ new Set(mutation.columns).size !== mutation.columns.length ||
319
+ !mutation.columns.includes(mutation.keyColumn) ||
320
+ typeof mutation.key !== 'string' ||
321
+ !mutation.key.trim() ||
322
+ /[\r\n]/.test(mutation.key)
323
+ ) {
324
+ throw new DocumentMutationError('MUTATION_INVALID', 'table mutation shape is invalid');
325
+ }
326
+ const normalizedKey = mutation.key.trim();
327
+ if (mutation.action !== 'upsert' && mutation.action !== 'delete') {
328
+ throw new DocumentMutationError('MUTATION_INVALID', 'table action is invalid');
329
+ }
330
+ if (mutation.action === 'delete' && 'values' in mutation) {
331
+ throw new DocumentMutationError('TABLE_DELETE_VALUES_FORBIDDEN', 'delete cannot include values');
332
+ }
333
+ if (
334
+ mutation.action === 'upsert' &&
335
+ (!mutation.values || typeof mutation.values !== 'object' || Array.isArray(mutation.values))
336
+ ) {
337
+ throw new DocumentMutationError('MUTATION_INVALID', 'upsert values must be an object');
338
+ }
339
+
340
+ const sections = matchingSections(content, mutation.sectionAliases);
341
+ if (sections.length !== 1) {
342
+ throw new DocumentMutationError(
343
+ sections.length === 0 ? 'TABLE_NOT_FOUND' : 'TASK_DOCUMENT_INVALID',
344
+ sections.length === 0 ? 'table section not found' : 'table section is ambiguous'
345
+ );
346
+ }
347
+ const section = sections[0]!;
348
+ const sectionLines = linesOf(content).filter(
349
+ (line) => line.start >= section.bodyStart && line.start < section.end
350
+ );
351
+ const tables: { headerIndex: number; cells: string[] }[] = [];
352
+ for (let i = 0; i + 1 < sectionLines.length; i += 1) {
353
+ const header = splitTableCells(sectionLines[i]!.text);
354
+ const separator = splitTableCells(sectionLines[i + 1]!.text);
355
+ if (!header || !separator || header.cells.length !== mutation.columns.length) continue;
356
+ const names = header.cells.map((cell) => decodeCell(cell).trim());
357
+ if (!names.every((name, index) => name === mutation.columns[index])) continue;
358
+ if (
359
+ separator.cells.length !== mutation.columns.length ||
360
+ !separator.cells.every((cell) => /^\s*:?-{3,}:?\s*$/.test(cell))
361
+ ) continue;
362
+ tables.push({ headerIndex: i, cells: header.cells });
363
+ }
364
+ if (tables.length === 0) {
365
+ throw new DocumentMutationError('TABLE_NOT_FOUND', 'matching table not found');
366
+ }
367
+ if (tables.length > 1) {
368
+ throw new DocumentMutationError('TABLE_AMBIGUOUS', 'matching table appears more than once');
369
+ }
370
+
371
+ const table = tables[0]!;
372
+ const keyIndex = mutation.columns.indexOf(mutation.keyColumn);
373
+ let rowIndex = table.headerIndex + 2;
374
+ const rows: { line: Line; parsed: NonNullable<ReturnType<typeof splitTableCells>> }[] = [];
375
+ while (rowIndex < sectionLines.length) {
376
+ const line = sectionLines[rowIndex]!;
377
+ const parsed = splitTableCells(line.text);
378
+ if (!parsed) break;
379
+ if (parsed.cells.length !== mutation.columns.length) {
380
+ throw new DocumentMutationError('TASK_DOCUMENT_INVALID', 'table row has the wrong column count');
381
+ }
382
+ rows.push({ line, parsed });
383
+ rowIndex += 1;
384
+ }
385
+ const matches = rows.filter(
386
+ (row) => decodeCell(row.parsed.cells[keyIndex]!).trim() === normalizedKey
387
+ );
388
+ if (matches.length > 1) {
389
+ throw new DocumentMutationError('TABLE_DUPLICATE_KEY', `duplicate table key '${normalizedKey}'`);
390
+ }
391
+
392
+ if (mutation.action === 'delete') {
393
+ if (matches.length === 0) return { content, section: section.heading, operation: 'delete' };
394
+ const line = matches[0]!.line;
395
+ return {
396
+ content: content.slice(0, line.start) + content.slice(line.end),
397
+ section: section.heading,
398
+ operation: 'delete'
399
+ };
400
+ }
401
+
402
+ const values = mutation.values;
403
+ for (const [column, value] of Object.entries(values)) {
404
+ if (!mutation.columns.includes(column)) {
405
+ throw new DocumentMutationError('TABLE_UNKNOWN_COLUMN', `unknown table column '${column}'`);
406
+ }
407
+ if (column === mutation.keyColumn) {
408
+ const serialized = scalarCell(value);
409
+ throw new DocumentMutationError(
410
+ decodeCell(serialized).trim() === normalizedKey
411
+ ? 'TABLE_KEY_COLUMN_IN_VALUES'
412
+ : 'TABLE_KEY_CONFLICT',
413
+ `key column '${column}' must not appear in values`
414
+ );
415
+ }
416
+ scalarCell(value);
417
+ }
418
+
419
+ if (matches.length === 1) {
420
+ const row = matches[0]!;
421
+ const cells = [...row.parsed.cells];
422
+ for (const [column, value] of Object.entries(values)) {
423
+ const index = mutation.columns.indexOf(column);
424
+ cells[index] = replaceCellToken(cells[index]!, scalarCell(value));
425
+ }
426
+ const rebuilt = `${row.parsed.prefix}|${cells.join('|')}|${row.parsed.suffix}`;
427
+ return {
428
+ content:
429
+ content.slice(0, row.line.start) +
430
+ rebuilt +
431
+ row.line.eol +
432
+ content.slice(row.line.end),
433
+ section: section.heading,
434
+ operation: 'update'
435
+ };
436
+ }
437
+
438
+ const missing = mutation.columns.filter(
439
+ (column) => column !== mutation.keyColumn && !Object.hasOwn(values, column)
440
+ );
441
+ if (missing.length > 0) {
442
+ throw new DocumentMutationError(
443
+ 'TABLE_MISSING_COLUMN',
444
+ `new table row is missing columns: ${missing.join(', ')}`
445
+ );
446
+ }
447
+ const newCells = mutation.columns.map((column) =>
448
+ column === mutation.keyColumn ? scalarCell(normalizedKey) : scalarCell(values[column]!)
449
+ );
450
+ const newLine = `| ${newCells.join(' | ')} |`;
451
+ const separatorLine = sectionLines[table.headerIndex + 1]!;
452
+ const lastLine = rows.at(-1)?.line ?? separatorLine;
453
+ const eol = lastLine.eol || documentEol(content);
454
+ const needsLeadingEol = lastLine.eol === '';
455
+ return {
456
+ content:
457
+ content.slice(0, lastLine.end) +
458
+ (needsLeadingEol ? eol : '') +
459
+ newLine +
460
+ eol +
461
+ content.slice(lastLine.end),
462
+ section: section.heading,
463
+ operation: 'insert'
464
+ };
465
+ }
466
+
5
467
  /**
6
468
  * Return the body of the first `## {alias}` section (any alias matches), from
7
469
  * the heading line to the next `## ` heading or EOF. Lines are preserved
@@ -44,9 +506,9 @@ function findSectionHeading(content: string, aliases: string[]): string {
44
506
  /**
45
507
  * Return the body of the first `### {headingPrefix}` sub-section, from the
46
508
  * heading line (inclusive) to the next `### ` / `## ` heading or EOF. Used to
47
- * pull a single `### HD-N` human-decision detail block out of an artifact. The
48
- * prefix must be followed by a word boundary so `HD-1` does not match `HD-10`
49
- * (e.g. `### HD-1`, `### HD-1:标题`, `### HD-1 [needs-human-decision]`). Leading
509
+ * pull a single `### {ledger-id}` detail block out of an artifact. The prefix
510
+ * must be followed by a word boundary so `PL-1` does not match `PL-10`
511
+ * (e.g. `### PL-1`, `### PL-1:标题`, `### PL-1 [needs-human-decision]`). Leading
50
512
  * and trailing blank lines are trimmed. Returns '' when no match is present.
51
513
  */
52
514
  function extractSubSection(content: string, headingPrefix: string): string {
@@ -70,4 +532,24 @@ function extractSubSection(content: string, headingPrefix: string): string {
70
532
  return lines.slice(start, end).join('\n').replace(/^\n+/, '').replace(/\n+$/, '');
71
533
  }
72
534
 
73
- export { extractSection, findSectionHeading, extractSubSection };
535
+ export {
536
+ extractSection,
537
+ findSectionHeading,
538
+ extractSubSection,
539
+ parseTable,
540
+ upsertSection,
541
+ mutateTableRow,
542
+ DocumentMutationError
543
+ };
544
+ export type {
545
+ SectionMutationInput,
546
+ SectionMutationResult,
547
+ TableRowBase,
548
+ TableRowUpsertMutation,
549
+ TableRowDeleteMutation,
550
+ TableRowMutation,
551
+ TableMutationResult,
552
+ DocumentMutationErrorCode,
553
+ ParsedTableRow,
554
+ ParsedTable
555
+ };