@fitlab-ai/agent-infra 0.9.12 → 0.9.14

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 (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -18,8 +18,12 @@ function computeInLabels(changedFiles, mapping, repositoryLabels) {
18
18
  return Object.entries(mapping).flatMap(([name, rawPrefixes]) => {
19
19
  if (!Array.isArray(rawPrefixes))
20
20
  return [];
21
- const matches = rawPrefixes.some((prefix) => typeof prefix === 'string' && prefix.length > 0
22
- && changedFiles.some((file) => file === prefix.replace(/\/$/, '') || file.startsWith(prefix)));
21
+ const matches = rawPrefixes.some((prefix) => {
22
+ if (typeof prefix !== 'string' || prefix.trim().length === 0)
23
+ return false;
24
+ const normalized = prefix.trim().replace(/\/+$/, '');
25
+ return changedFiles.some((file) => file === normalized || file.startsWith(`${normalized}/`));
26
+ });
23
27
  const label = `in: ${name}`;
24
28
  return matches && repositoryLabels.has(label) ? [label] : [];
25
29
  }).sort();
@@ -0,0 +1,28 @@
1
+ function createNoneProvider(input) {
2
+ return {
3
+ type: input.providerType,
4
+ contractVersion: 1,
5
+ context: {
6
+ async resolve() {
7
+ return {
8
+ ok: true,
9
+ value: {
10
+ type: input.providerType,
11
+ scope: { id: input.repositoryRoot },
12
+ currentUser: null,
13
+ capabilities: {
14
+ authenticated: false,
15
+ comment: false,
16
+ triage: false,
17
+ push: false,
18
+ admin: false
19
+ },
20
+ authenticated: false
21
+ }
22
+ };
23
+ }
24
+ }
25
+ };
26
+ }
27
+ export { createNoneProvider };
28
+ //# sourceMappingURL=none-provider.js.map
@@ -0,0 +1,545 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createHash, randomUUID } from 'node:crypto';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { escapeHtmlText } from './comment-safety.js';
6
+ const REPORT_FILE_NAME = 'pr-change-report.json';
7
+ const REPORT_VERSION = 1;
8
+ const CANONICAL_REPORT_PLACEHOLDER = '<!-- canonical-pr-change-report -->';
9
+ const CANONICAL_REPORT_HEADING = '### PR 代码增减';
10
+ const PRECHECK_IDS = [
11
+ 'target-alignment',
12
+ 'change-composition',
13
+ 'compatibility-policy',
14
+ 'legacy-path-cleanup',
15
+ 'redundancy',
16
+ 'scope-discipline'
17
+ ];
18
+ const PRECHECK_LABELS = {
19
+ 'target-alignment': '目标对应',
20
+ 'change-composition': '变更构成',
21
+ 'compatibility-policy': '兼容性策略',
22
+ 'legacy-path-cleanup': '旧路径清理',
23
+ redundancy: '冗余检查',
24
+ 'scope-discipline': '范围纪律'
25
+ };
26
+ function invalid(message, code = 'PR_CHANGE_REPORT_INVALID') {
27
+ return { ok: false, error: { code, message } };
28
+ }
29
+ function isRecord(value) {
30
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
31
+ }
32
+ function isSha(value) {
33
+ return typeof value === 'string' && /^[0-9a-f]{40,64}$/i.test(value);
34
+ }
35
+ function isNonEmptyString(value) {
36
+ return typeof value === 'string' && value.trim().length > 0;
37
+ }
38
+ function containsControlMarker(value) {
39
+ return /<!--\s*(?:canonical-pr-change-report\b|sync-pr:|last-commit:)/i.test(value);
40
+ }
41
+ function isSafeRenderedText(value) {
42
+ return isNonEmptyString(value) && !containsControlMarker(value);
43
+ }
44
+ function isIntegerOrNull(value) {
45
+ return value === null || (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0);
46
+ }
47
+ function parseChangeFile(value, index) {
48
+ if (!isRecord(value))
49
+ return invalid(`diff.files[${index}] must be an object`);
50
+ const pathValue = value.oldPath ?? value.newPath;
51
+ if (!isNonEmptyString(pathValue))
52
+ return invalid(`diff.files[${index}] must have a path`);
53
+ if (!isSafeRenderedText(value.status))
54
+ return invalid(`diff.files[${index}].status is invalid`);
55
+ if (!(value.oldPath === null || isSafeRenderedText(value.oldPath)))
56
+ return invalid(`diff.files[${index}].oldPath is invalid`);
57
+ if (!(value.newPath === null || isSafeRenderedText(value.newPath)))
58
+ return invalid(`diff.files[${index}].newPath is invalid`);
59
+ if (!isIntegerOrNull(value.additions) || !isIntegerOrNull(value.deletions))
60
+ return invalid(`diff.files[${index}] line counts are invalid`);
61
+ if ((value.additions === null) !== (value.deletions === null))
62
+ return invalid(`diff.files[${index}] line counts must both be null or integers`);
63
+ for (const field of ['oldBytes', 'newBytes', 'netBytes']) {
64
+ const number = value[field];
65
+ if (typeof number !== 'number' || !Number.isSafeInteger(number) || (field !== 'netBytes' && number < 0)) {
66
+ return invalid(`diff.files[${index}].${field} is invalid`);
67
+ }
68
+ }
69
+ if (value.netBytes !== value.newBytes - value.oldBytes)
70
+ return invalid(`diff.files[${index}].netBytes is inconsistent`);
71
+ return {
72
+ ok: true,
73
+ value: {
74
+ status: value.status,
75
+ oldPath: value.oldPath,
76
+ newPath: value.newPath,
77
+ additions: value.additions,
78
+ deletions: value.deletions,
79
+ oldBytes: value.oldBytes,
80
+ newBytes: value.newBytes,
81
+ netBytes: value.netBytes
82
+ }
83
+ };
84
+ }
85
+ function parseTotals(value) {
86
+ if (!isRecord(value))
87
+ return invalid('diff.totals must be an object');
88
+ const nonNegativeFields = ['files', 'textFiles', 'binaryFiles', 'additions', 'deletions', 'oldBytes', 'newBytes'];
89
+ for (const field of [...nonNegativeFields, 'netBytes']) {
90
+ const number = value[field];
91
+ const invalidNumber = typeof number !== 'number' || !Number.isSafeInteger(number) || (nonNegativeFields.includes(field) && number < 0);
92
+ if (invalidNumber)
93
+ return invalid(`diff.totals.${field} is invalid`);
94
+ }
95
+ const fields = [...nonNegativeFields, 'netBytes'];
96
+ return {
97
+ ok: true,
98
+ value: Object.fromEntries(fields.map((field) => [field, value[field]]))
99
+ };
100
+ }
101
+ function totalsMatchFiles(totals, files) {
102
+ const expected = files.reduce((result, file) => {
103
+ result.files += 1;
104
+ result.oldBytes += file.oldBytes;
105
+ result.newBytes += file.newBytes;
106
+ result.netBytes += file.netBytes;
107
+ if (file.additions === null)
108
+ result.binaryFiles += 1;
109
+ else {
110
+ result.textFiles += 1;
111
+ result.additions += file.additions;
112
+ result.deletions += file.deletions;
113
+ }
114
+ return result;
115
+ }, { files: 0, textFiles: 0, binaryFiles: 0, additions: 0, deletions: 0, oldBytes: 0, newBytes: 0, netBytes: 0 });
116
+ return JSON.stringify(totals) === JSON.stringify(expected);
117
+ }
118
+ function parseEvidence(value, checkId, index) {
119
+ if (!isRecord(value))
120
+ return invalid(`precheck.checks.${checkId}.evidence[${index}] must be an object`);
121
+ if (!isSafeRenderedText(value.path) || !isSafeRenderedText(value.detail))
122
+ return invalid(`precheck.checks.${checkId}.evidence[${index}] path/detail is required`);
123
+ const startLine = value.startLine;
124
+ const endLine = value.endLine;
125
+ if (!(startLine === null || (typeof startLine === 'number' && Number.isSafeInteger(startLine) && startLine > 0)))
126
+ return invalid(`precheck.checks.${checkId}.evidence[${index}].startLine is invalid`);
127
+ if (!(endLine === null || (typeof endLine === 'number' && Number.isSafeInteger(endLine) && endLine > 0)))
128
+ return invalid(`precheck.checks.${checkId}.evidence[${index}].endLine is invalid`);
129
+ if (startLine !== null && endLine !== null && endLine < startLine)
130
+ return invalid(`precheck.checks.${checkId}.evidence[${index}] line range is invalid`);
131
+ return { ok: true, value: { path: value.path, startLine, endLine, detail: value.detail } };
132
+ }
133
+ function parseChecks(value, prefix = 'precheck.checks') {
134
+ if (!Array.isArray(value) || value.length !== PRECHECK_IDS.length)
135
+ return invalid(`${prefix} must contain exactly six checks`);
136
+ const checks = [];
137
+ for (let index = 0; index < value.length; index += 1) {
138
+ const raw = value[index];
139
+ if (!isRecord(raw))
140
+ return invalid(`${prefix}[${index}] must be an object`);
141
+ const expectedId = PRECHECK_IDS[index];
142
+ if (raw.id !== expectedId)
143
+ return invalid(`${prefix}[${index}].id must be '${expectedId}'`);
144
+ if (raw.verdict !== 'pass' && raw.verdict !== 'needs-review')
145
+ return invalid(`${prefix}.${expectedId}.verdict is invalid`);
146
+ if (!Array.isArray(raw.evidence) || raw.evidence.length === 0)
147
+ return invalid(`${prefix}.${expectedId}.evidence must not be empty`);
148
+ const evidence = [];
149
+ for (let evidenceIndex = 0; evidenceIndex < raw.evidence.length; evidenceIndex += 1) {
150
+ const parsed = parseEvidence(raw.evidence[evidenceIndex], expectedId, evidenceIndex);
151
+ if (!parsed.ok)
152
+ return parsed;
153
+ evidence.push(parsed.value);
154
+ }
155
+ if (!isSafeRenderedText(raw.rationale))
156
+ return invalid(`${prefix}.${expectedId}.rationale is required`);
157
+ checks.push({ id: expectedId, verdict: raw.verdict, evidence, rationale: raw.rationale });
158
+ }
159
+ return { ok: true, value: checks };
160
+ }
161
+ function validateMechanicalReport(value) {
162
+ if (!isRecord(value))
163
+ return invalid('mechanical report must be an object', 'PR_CHANGE_REPORT_MECHANICAL_INVALID');
164
+ if (value.version !== 1 || !isSha(value.base) || !isSha(value.head) || !isSha(value.mergeBase) || !isSha(value.patchSha256)) {
165
+ return invalid('mechanical report version, commit SHA, or patch SHA is invalid', 'PR_CHANGE_REPORT_MECHANICAL_INVALID');
166
+ }
167
+ if (!Array.isArray(value.files))
168
+ return invalid('mechanical report files must be an array', 'PR_CHANGE_REPORT_MECHANICAL_INVALID');
169
+ const files = [];
170
+ for (let index = 0; index < value.files.length; index += 1) {
171
+ const parsed = parseChangeFile(value.files[index], index);
172
+ if (!parsed.ok)
173
+ return { ...parsed, error: { ...parsed.error, code: 'PR_CHANGE_REPORT_MECHANICAL_INVALID' } };
174
+ files.push(parsed.value);
175
+ }
176
+ const totals = parseTotals(value.totals);
177
+ if (!totals.ok)
178
+ return { ...totals, error: { ...totals.error, code: 'PR_CHANGE_REPORT_MECHANICAL_INVALID' } };
179
+ if (!totalsMatchFiles(totals.value, files))
180
+ return invalid('mechanical report totals do not match files', 'PR_CHANGE_REPORT_MECHANICAL_INVALID');
181
+ return {
182
+ ok: true,
183
+ value: {
184
+ version: 1,
185
+ base: value.base,
186
+ head: value.head,
187
+ mergeBase: value.mergeBase,
188
+ patchSha256: value.patchSha256,
189
+ files,
190
+ totals: totals.value
191
+ }
192
+ };
193
+ }
194
+ function validatePrecheckCandidate(value) {
195
+ if (!isRecord(value))
196
+ return invalid('precheck candidate must be an object', 'PR_CHANGE_REPORT_PRECHECK_INVALID');
197
+ const inputs = isRecord(value.inputs) ? value.inputs : null;
198
+ const taskIntentSha256 = inputs?.taskIntentSha256 ?? value.taskIntentSha256;
199
+ if (!isSha(taskIntentSha256))
200
+ return invalid('precheck candidate taskIntentSha256 is invalid', 'PR_CHANGE_REPORT_PRECHECK_INVALID');
201
+ const parsed = parseChecks(isRecord(value.precheck) ? value.precheck.checks : value.checks, 'checks');
202
+ if (!parsed.ok)
203
+ return { ...parsed, error: { ...parsed.error, code: 'PR_CHANGE_REPORT_PRECHECK_INVALID' } };
204
+ return { ok: true, value: { taskIntentSha256, checks: parsed.value } };
205
+ }
206
+ function validatePrChangeReport(value) {
207
+ if (!isRecord(value))
208
+ return invalid('change report must be an object');
209
+ if (value.version !== REPORT_VERSION || !isRecord(value.identity) || !isRecord(value.inputs) || !isRecord(value.diff) || !isRecord(value.precheck)) {
210
+ return invalid('change report has an invalid top-level shape');
211
+ }
212
+ const identity = value.identity;
213
+ const identityRepository = identity.repository;
214
+ const identityNumber = identity.number;
215
+ if (!isNonEmptyString(identityRepository) || typeof identityNumber !== 'number' || !Number.isSafeInteger(identityNumber) || identityNumber <= 0)
216
+ return invalid('change report identity is invalid');
217
+ const parseIdentityPart = (part, name) => {
218
+ if (!isRecord(part) || !isNonEmptyString(part.repository) || !isNonEmptyString(part.ref) || !isSha(part.sha))
219
+ return invalid(`change report identity.${name} is invalid`);
220
+ return { ok: true, value: { repository: part.repository, ref: part.ref, sha: part.sha } };
221
+ };
222
+ const base = parseIdentityPart(identity.base, 'base');
223
+ const head = parseIdentityPart(identity.head, 'head');
224
+ if (!base.ok)
225
+ return base;
226
+ if (!head.ok)
227
+ return head;
228
+ const inputTaskIntentSha256 = value.inputs.taskIntentSha256;
229
+ if (!isSha(inputTaskIntentSha256))
230
+ return invalid('change report taskIntentSha256 is invalid');
231
+ const diff = value.diff;
232
+ if (!isSha(diff.mergeBase) || !isSha(diff.patchSha256) || !Array.isArray(diff.files))
233
+ return invalid('change report diff is invalid');
234
+ const files = [];
235
+ for (let index = 0; index < diff.files.length; index += 1) {
236
+ const parsed = parseChangeFile(diff.files[index], index);
237
+ if (!parsed.ok)
238
+ return parsed;
239
+ files.push(parsed.value);
240
+ }
241
+ const totals = parseTotals(diff.totals);
242
+ if (!totals.ok)
243
+ return totals;
244
+ if (!totalsMatchFiles(totals.value, files))
245
+ return invalid('change report totals do not match files');
246
+ if (value.precheck.formalReview !== false || (value.precheck.verdict !== 'clear' && value.precheck.verdict !== 'needs-review') ||
247
+ (value.precheck.route !== 'watch-pr' && value.precheck.route !== 'review-code'))
248
+ return invalid('change report precheck envelope is invalid');
249
+ const checks = parseChecks(value.precheck.checks);
250
+ if (!checks.ok)
251
+ return checks;
252
+ const derivedVerdict = checks.value.every((check) => check.verdict === 'pass') ? 'clear' : 'needs-review';
253
+ const derivedRoute = derivedVerdict === 'clear' ? 'watch-pr' : 'review-code';
254
+ if (value.precheck.verdict !== derivedVerdict || value.precheck.route !== derivedRoute)
255
+ return invalid('change report precheck verdict/route is not derived from checks');
256
+ return {
257
+ ok: true,
258
+ value: {
259
+ version: REPORT_VERSION,
260
+ identity: {
261
+ repository: identityRepository,
262
+ number: identityNumber,
263
+ base: base.value,
264
+ head: head.value
265
+ },
266
+ inputs: { taskIntentSha256: inputTaskIntentSha256 },
267
+ diff: { mergeBase: diff.mergeBase, patchSha256: diff.patchSha256, files, totals: totals.value },
268
+ precheck: { verdict: value.precheck.verdict, formalReview: false, route: value.precheck.route, checks: checks.value }
269
+ }
270
+ };
271
+ }
272
+ function taskIntentProjection(taskContent) {
273
+ const normalized = taskContent.replace(/\r\n?/g, '\n');
274
+ const lines = normalized.split('\n');
275
+ const start = lines.findIndex((line) => /^#\s+(?:任务(?::|:)?|Task\s*:?)\s*.*$/i.test(line.trim()));
276
+ const end = lines.findIndex((line, index) => index > start && /^##\s+(?:上下文|Context)\s*$/i.test(line.trim()));
277
+ if (start < 0 || end < 0 || end <= start)
278
+ return invalid('task semantic section must have # 任务/# Task and ## 上下文/## Context boundaries', 'TASK_SEMANTIC_INPUT_INVALID');
279
+ return { ok: true, value: lines.slice(start, end).map((line) => line.replace(/[ \t]+$/g, '')).join('\n').trim() };
280
+ }
281
+ function taskIntentDigest(taskContent) {
282
+ const projection = taskIntentProjection(taskContent);
283
+ if (!projection.ok)
284
+ return projection;
285
+ const value = `task-intent-v1\n${projection.value}\n`;
286
+ return { ok: true, value: { sha256: createHash('sha256').update(value, 'utf8').digest('hex'), projection: projection.value } };
287
+ }
288
+ function derivePrecheck(checks) {
289
+ const clear = checks.every((check) => check.verdict === 'pass');
290
+ return { verdict: clear ? 'clear' : 'needs-review', route: clear ? 'watch-pr' : 'review-code', formalReview: false };
291
+ }
292
+ function buildPrChangeReport(identity, taskIntentSha256, mechanical, candidate) {
293
+ if (!isSha(taskIntentSha256) || candidate.taskIntentSha256 !== taskIntentSha256)
294
+ return invalid('task intent digest does not match the precheck candidate', 'PR_CHANGE_REPORT_TASK_INTENT_MISMATCH');
295
+ if (mechanical.base !== identity.base.sha || mechanical.head !== identity.head.sha)
296
+ return invalid('mechanical report does not match the pull request base/head', 'PR_CHANGE_REPORT_IDENTITY_MISMATCH');
297
+ const precheck = { ...derivePrecheck(candidate.checks), checks: candidate.checks };
298
+ return validatePrChangeReport({
299
+ version: REPORT_VERSION,
300
+ identity,
301
+ inputs: { taskIntentSha256 },
302
+ diff: {
303
+ mergeBase: mechanical.mergeBase,
304
+ patchSha256: mechanical.patchSha256,
305
+ files: mechanical.files,
306
+ totals: mechanical.totals
307
+ },
308
+ precheck
309
+ });
310
+ }
311
+ function reportFilePath(taskDir) {
312
+ return path.join(taskDir, REPORT_FILE_NAME);
313
+ }
314
+ function readPrChangeReport(file) {
315
+ try {
316
+ const stat = fs.lstatSync(file);
317
+ if (stat.isSymbolicLink() || !stat.isFile())
318
+ return invalid('change report must be a regular file', 'PR_CHANGE_REPORT_INVALID');
319
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
320
+ return validatePrChangeReport(parsed);
321
+ }
322
+ catch (error) {
323
+ const code = error.code;
324
+ if (code === 'ENOENT')
325
+ return invalid('change report is missing', 'PR_CHANGE_REPORT_MISSING');
326
+ if (error instanceof SyntaxError)
327
+ return invalid('change report is not valid JSON', 'PR_CHANGE_REPORT_INVALID');
328
+ return invalid(error instanceof Error ? error.message : String(error), 'PR_CHANGE_REPORT_INVALID');
329
+ }
330
+ }
331
+ function writePrChangeReportAtomic(file, report) {
332
+ const directory = path.dirname(file);
333
+ fs.mkdirSync(directory, { recursive: true });
334
+ const temporary = path.join(directory, `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
335
+ let descriptor = null;
336
+ try {
337
+ descriptor = fs.openSync(temporary, 'wx', 0o600);
338
+ fs.writeFileSync(descriptor, `${JSON.stringify(report, null, 2)}\n`);
339
+ fs.fsyncSync(descriptor);
340
+ fs.closeSync(descriptor);
341
+ descriptor = null;
342
+ fs.renameSync(temporary, file);
343
+ try {
344
+ const directoryDescriptor = fs.openSync(directory, 'r');
345
+ try {
346
+ fs.fsyncSync(directoryDescriptor);
347
+ }
348
+ finally {
349
+ fs.closeSync(directoryDescriptor);
350
+ }
351
+ }
352
+ catch {
353
+ // Directory fsync is not available on every supported platform.
354
+ }
355
+ }
356
+ finally {
357
+ if (descriptor !== null)
358
+ fs.closeSync(descriptor);
359
+ try {
360
+ fs.unlinkSync(temporary);
361
+ }
362
+ catch (error) {
363
+ if (error.code !== 'ENOENT')
364
+ throw error;
365
+ }
366
+ }
367
+ }
368
+ function runMechanicalChangeReport(repoRoot, baseSha, headSha) {
369
+ const script = path.join(repoRoot, '.agents', 'skills', 'create-pr', 'scripts', 'change-report.mjs');
370
+ const output = execFileSync(process.execPath, [script, '--base', baseSha, '--head', headSha, '--cwd', repoRoot], {
371
+ cwd: repoRoot,
372
+ encoding: 'utf8',
373
+ maxBuffer: 64 * 1024 * 1024
374
+ });
375
+ const parsed = JSON.parse(output);
376
+ const validated = validateMechanicalReport(parsed);
377
+ if (!validated.ok)
378
+ throw new Error(`${validated.error.code}: ${validated.error.message}`);
379
+ return validated.value;
380
+ }
381
+ const CHANGE_CATEGORIES = [
382
+ { label: '运行时代码', prefixes: ['bin/', 'lib/', 'src/', 'scripts/'] },
383
+ { label: '测试与校验', prefixes: ['test/', 'tests/'] },
384
+ { label: '模板与生成内容', prefixes: ['templates/'] },
385
+ { label: '技能与协作配置', prefixes: ['.agents/'] },
386
+ { label: '文档与其他', prefixes: [] }
387
+ ];
388
+ function emptyChangeTotals() {
389
+ return { files: 0, textFiles: 0, binaryFiles: 0, additions: 0, deletions: 0, oldBytes: 0, newBytes: 0, netBytes: 0 };
390
+ }
391
+ function categoryForChangeFile(file) {
392
+ const filePath = file.newPath || file.oldPath || '';
393
+ return CHANGE_CATEGORIES.find((category) => category.prefixes.some((prefix) => filePath.startsWith(prefix))) || CHANGE_CATEGORIES[CHANGE_CATEGORIES.length - 1];
394
+ }
395
+ function summarizeChangeCategories(files) {
396
+ const summaries = new Map();
397
+ for (const file of files) {
398
+ const category = categoryForChangeFile(file);
399
+ const totals = summaries.get(category.label) || emptyChangeTotals();
400
+ totals.files += 1;
401
+ totals.oldBytes += file.oldBytes;
402
+ totals.newBytes += file.newBytes;
403
+ totals.netBytes += file.netBytes;
404
+ if (file.additions === null)
405
+ totals.binaryFiles += 1;
406
+ else {
407
+ totals.textFiles += 1;
408
+ totals.additions += file.additions;
409
+ totals.deletions += file.deletions;
410
+ }
411
+ summaries.set(category.label, totals);
412
+ }
413
+ const result = [];
414
+ for (const category of CHANGE_CATEGORIES) {
415
+ const totals = summaries.get(category.label);
416
+ if (totals)
417
+ result.push({ label: category.label, totals });
418
+ }
419
+ return result;
420
+ }
421
+ function signedNumber(value) {
422
+ return `${value >= 0 ? '+' : ''}${value}`;
423
+ }
424
+ function renderLineCounts(totals) {
425
+ if (totals.textFiles === 0)
426
+ return ['—', '—', '—'];
427
+ return [String(totals.additions), String(totals.deletions), signedNumber(totals.additions - totals.deletions)];
428
+ }
429
+ const MAX_REPRESENTATIVE_FILES = 3;
430
+ function representativePath(file) {
431
+ return file.newPath || file.oldPath || '';
432
+ }
433
+ function escapeReportText(value) {
434
+ return escapeHtmlText(value).replaceAll('\r', '\\r').replaceAll('\n', '\\n');
435
+ }
436
+ function renderRepresentativePath(file) {
437
+ const paths = file.oldPath && file.newPath && file.oldPath !== file.newPath
438
+ ? [file.oldPath, file.newPath]
439
+ : [representativePath(file)];
440
+ return paths.map((filePath) => `<code>${escapeReportText(filePath)}</code>`).join(' → ');
441
+ }
442
+ function representativeScore(file, metric) {
443
+ return metric === 'lines' ? file.additions + file.deletions : Math.abs(file.netBytes);
444
+ }
445
+ function representativeFiles(files, metric) {
446
+ return files
447
+ .filter((file) => file.additions !== null && file.deletions !== null)
448
+ .slice()
449
+ .sort((left, right) => {
450
+ const scoreDifference = representativeScore(right, metric) - representativeScore(left, metric);
451
+ if (scoreDifference !== 0)
452
+ return scoreDifference;
453
+ const leftPath = representativePath(left);
454
+ const rightPath = representativePath(right);
455
+ return leftPath < rightPath ? -1 : leftPath > rightPath ? 1 : 0;
456
+ })
457
+ .slice(0, MAX_REPRESENTATIVE_FILES);
458
+ }
459
+ function renderRepresentativeFile(file, metric) {
460
+ const category = categoryForChangeFile(file).label;
461
+ const pathValue = renderRepresentativePath(file);
462
+ if (metric === 'lines') {
463
+ const additions = file.additions;
464
+ const deletions = file.deletions;
465
+ return ` - ${pathValue}(${category}):新增 ${additions} 行、删除 ${deletions} 行,共变更 ${additions + deletions} 行。`;
466
+ }
467
+ return ` - ${pathValue}(${category}):净字节 ${signedNumber(file.netBytes)},绝对变化 ${Math.abs(file.netBytes)}。`;
468
+ }
469
+ function renderRepresentativeFiles(files) {
470
+ const lineFiles = representativeFiles(files, 'lines');
471
+ const byteFiles = representativeFiles(files, 'bytes');
472
+ return [
473
+ '#### 代表性变更文件',
474
+ '',
475
+ '- 行数变化最大(仅文本文件,按新增行+删除行,最多展示 3 个):',
476
+ ...(lineFiles.length > 0 ? lineFiles.map((file) => renderRepresentativeFile(file, 'lines')) : [' - 无可比较的文本文件。']),
477
+ '- 绝对净字节变化最大(仅文本文件,最多展示 3 个):',
478
+ ...(byteFiles.length > 0 ? byteFiles.map((file) => renderRepresentativeFile(file, 'bytes')) : [' - 无可比较的文本文件。'])
479
+ ];
480
+ }
481
+ function renderEvidence(evidence) {
482
+ const location = evidence.startLine === null && evidence.endLine === null
483
+ ? ''
484
+ : evidence.startLine !== null && evidence.endLine !== null
485
+ ? evidence.endLine === evidence.startLine
486
+ ? `:${evidence.startLine}`
487
+ : `:${evidence.startLine}-${evidence.endLine}`
488
+ : `:${evidence.startLine ?? evidence.endLine}`;
489
+ return ` - 证据:<code>${escapeReportText(evidence.path)}</code>${location}:${escapeReportText(evidence.detail)}`;
490
+ }
491
+ function renderPrechecks(checks) {
492
+ return checks.flatMap((check) => [
493
+ `- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${escapeReportText(check.rationale)}`,
494
+ ...check.evidence.slice(0, 1).map(renderEvidence)
495
+ ]);
496
+ }
497
+ function renderCanonicalChangeReport(report) {
498
+ const totals = report.diff.totals;
499
+ const categories = summarizeChangeCategories(report.diff.files);
500
+ const rows = categories.map(({ label, totals: categoryTotals }) => {
501
+ const [additions, deletions, netLines] = renderLineCounts(categoryTotals);
502
+ return `| ${label} | ${categoryTotals.files} | ${additions} | ${deletions} | ${netLines} | ${categoryTotals.oldBytes} | ${categoryTotals.newBytes} | ${signedNumber(categoryTotals.netBytes)} | ${categoryTotals.textFiles} / ${categoryTotals.binaryFiles} |`;
503
+ });
504
+ const [additions, deletions, netLines] = renderLineCounts(totals);
505
+ const passedChecks = report.precheck.checks.filter((check) => check.verdict === 'pass').length;
506
+ const needsReviewChecks = report.precheck.checks.length - passedChecks;
507
+ const precheckSummary = report.precheck.verdict === 'clear'
508
+ ? `**通过**(${passedChecks}/${report.precheck.checks.length} 项通过)`
509
+ : `**需复核**(${passedChecks} 项通过,${needsReviewChecks} 项需复核)`;
510
+ const route = report.precheck.route === 'watch-pr' ? '继续监控 PR' : '转入代码审查';
511
+ return [
512
+ CANONICAL_REPORT_HEADING,
513
+ '',
514
+ '| 变更类别 | 文件数 | 新增行 | 删除行 | 净增行 | 旧字节 | 新字节 | 净字节 | 文本 / 二进制 |',
515
+ '| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |',
516
+ ...rows,
517
+ `| **合计** | ${totals.files} | ${additions} | ${deletions} | ${netLines} | ${totals.oldBytes} | ${totals.newBytes} | ${signedNumber(totals.netBytes)} | ${totals.textFiles} / ${totals.binaryFiles} |`,
518
+ '',
519
+ `- 总体统计:新增 ${totals.additions} 行、删除 ${totals.deletions} 行;旧字节 ${totals.oldBytes},新字节 ${totals.newBytes}。`,
520
+ `- 变更明细按高层类别聚合展示;完整逐文件事实保留在结构化报告中供审计。`,
521
+ `- 补丁摘要:\`${report.diff.patchSha256}\`。`,
522
+ '',
523
+ ...renderRepresentativeFiles(report.diff.files),
524
+ '',
525
+ '#### 适宜性预检',
526
+ `- 结论:${precheckSummary};${route};正式审查:否。`,
527
+ ...renderPrechecks(report.precheck.checks)
528
+ ].join('\n');
529
+ }
530
+ function replaceCanonicalReportPlaceholder(body, report) {
531
+ const matches = body.split(CANONICAL_REPORT_PLACEHOLDER).length - 1;
532
+ if (matches !== 1 || body.includes('<!-- sync-pr:') || /<!--\s*last-commit:/i.test(body) || body.includes(CANONICAL_REPORT_HEADING) ||
533
+ body.includes(REPORT_FILE_NAME) || /"(?:identity|precheck|diff)"\s*:\s*\{/.test(body)) {
534
+ return invalid('summary body must contain exactly one canonical report placeholder and no report bypass content', 'PR_SUMMARY_BODY_CONTRACT_INVALID');
535
+ }
536
+ const rendered = renderCanonicalChangeReport(report);
537
+ if (containsControlMarker(rendered))
538
+ return invalid('canonical report contains a reserved control marker', 'PR_SUMMARY_RENDER_INVALID');
539
+ const value = body.replace(CANONICAL_REPORT_PLACEHOLDER, rendered);
540
+ if (containsControlMarker(value))
541
+ return invalid('summary contains a reserved control marker', 'PR_SUMMARY_RENDER_INVALID');
542
+ return { ok: true, value };
543
+ }
544
+ export { CANONICAL_REPORT_HEADING, CANONICAL_REPORT_PLACEHOLDER, PRECHECK_IDS, REPORT_FILE_NAME, REPORT_VERSION, buildPrChangeReport, readPrChangeReport, renderCanonicalChangeReport, replaceCanonicalReportPlaceholder, reportFilePath, runMechanicalChangeReport, taskIntentDigest, taskIntentProjection, validateMechanicalReport, validatePrecheckCandidate, validatePrChangeReport, writePrChangeReportAtomic };
545
+ //# sourceMappingURL=pr-change-report.js.map