@fitlab-ai/agent-infra 0.9.13 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/cli.ts +26 -9
  4. package/bin/internal-cli.sh +45 -0
  5. package/dist/bin/cli.js +173 -157
  6. package/dist/bin/internal-cli.js +126 -42
  7. package/dist/lib/agent-client.js +5 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
  10. package/dist/lib/defaults.json +103 -103
  11. package/dist/lib/fs/durable-write.js +37 -0
  12. package/dist/lib/fs/file-lock.js +111 -0
  13. package/dist/lib/host-control/audit.js +19 -0
  14. package/dist/lib/host-control/client.js +142 -0
  15. package/dist/lib/host-control/command.js +49 -0
  16. package/dist/lib/host-control/path.js +160 -0
  17. package/dist/lib/host-control/secure-fs.js +140 -0
  18. package/dist/lib/host-control/server.js +159 -0
  19. package/dist/lib/host-control/service.js +112 -0
  20. package/dist/lib/init.js +11 -2
  21. package/dist/lib/internal/agent-client.js +5 -2
  22. package/dist/lib/internal/cli-route-inventory.js +154 -0
  23. package/dist/lib/internal/codex-lifecycle.js +15 -12
  24. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  25. package/dist/lib/internal/demo-promotion.js +322 -0
  26. package/dist/lib/internal/demo-transcript.js +454 -0
  27. package/dist/lib/internal/git-workflow.js +10 -6
  28. package/dist/lib/internal/host-control.js +28 -0
  29. package/dist/lib/internal/manual-validation.js +322 -0
  30. package/dist/lib/internal/platform-checks.js +16 -4
  31. package/dist/lib/internal/platform-comment.js +16 -4
  32. package/dist/lib/internal/platform-context.js +4 -1
  33. package/dist/lib/internal/platform-issue.js +12 -4
  34. package/dist/lib/internal/platform-metadata.js +88 -0
  35. package/dist/lib/internal/platform-pr-review.js +16 -3
  36. package/dist/lib/internal/platform-pr.js +42 -14
  37. package/dist/lib/internal/platform-release-notes.js +6 -3
  38. package/dist/lib/internal/platform-security.js +93 -0
  39. package/dist/lib/internal/pr-review-grade.js +14 -3
  40. package/dist/lib/internal/release-workflow.js +82 -89
  41. package/dist/lib/internal/sandbox-control.js +171 -7
  42. package/dist/lib/internal/task-activity.js +13 -4
  43. package/dist/lib/internal/task-artifact.js +19 -107
  44. package/dist/lib/internal/task-context.js +4 -1
  45. package/dist/lib/internal/task-create.js +48 -14
  46. package/dist/lib/internal/task-delivery.js +4 -1
  47. package/dist/lib/internal/task-event.js +38 -35
  48. package/dist/lib/internal/task-finalization.js +4 -1
  49. package/dist/lib/internal/task-invalidation.js +4 -1
  50. package/dist/lib/internal/task-ledger.js +12 -1
  51. package/dist/lib/internal/task-lifecycle.js +4 -1
  52. package/dist/lib/internal/task-operation-registry.js +519 -0
  53. package/dist/lib/internal/task-orchestration.js +12 -0
  54. package/dist/lib/internal/task-override.js +10 -3
  55. package/dist/lib/internal/task-qualification.js +90 -0
  56. package/dist/lib/internal/task-review.js +10 -52
  57. package/dist/lib/internal/task-short-id.js +11 -1
  58. package/dist/lib/internal/task-snapshot.js +4 -1
  59. package/dist/lib/internal/task-validate.js +37 -12
  60. package/dist/lib/internal/task-verify.js +5 -1
  61. package/dist/lib/internal/task-warning.js +8 -1
  62. package/dist/lib/owned-path.js +33 -0
  63. package/dist/lib/platform/check-status.js +11 -0
  64. package/dist/lib/platform/comment-safety.js +229 -0
  65. package/dist/lib/platform/completion-backfill.js +1 -1
  66. package/dist/lib/platform/github-data.js +241 -0
  67. package/dist/lib/platform/github-provider.js +248 -26
  68. package/dist/lib/platform/issue-comments.js +146 -34
  69. package/dist/lib/platform/issues.js +1 -179
  70. package/dist/lib/platform/pr-change-report.js +6 -12
  71. package/dist/lib/platform/pr-checks.js +12 -65
  72. package/dist/lib/platform/pr-summary.js +83 -10
  73. package/dist/lib/platform/provider-contract.d.ts +67 -1
  74. package/dist/lib/platform/provider-contract.js +6 -2
  75. package/dist/lib/platform/provider-validation.js +76 -3
  76. package/dist/lib/platform/pull-requests.js +117 -275
  77. package/dist/lib/platform/repository-metadata.js +377 -0
  78. package/dist/lib/platform/security-alerts.js +155 -0
  79. package/dist/lib/platform/snapshots.js +2 -0
  80. package/dist/lib/platform/verification-sync.js +154 -162
  81. package/dist/lib/process-data/index.js +7 -0
  82. package/dist/lib/release/workflow.js +1 -1
  83. package/dist/lib/run/index.js +5 -0
  84. package/dist/lib/sandbox/commands/control-status.js +22 -0
  85. package/dist/lib/sandbox/commands/create.js +39 -8
  86. package/dist/lib/sandbox/commands/ls.js +5 -0
  87. package/dist/lib/sandbox/commands/rm.js +3 -807
  88. package/dist/lib/sandbox/commands/show.js +16 -0
  89. package/dist/lib/sandbox/control/audit.js +203 -0
  90. package/dist/lib/sandbox/control/client.js +125 -12
  91. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  92. package/dist/lib/sandbox/control/container-identity.js +28 -31
  93. package/dist/lib/sandbox/control/executor.js +233 -34
  94. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  95. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  96. package/dist/lib/sandbox/control/lifecycle.js +656 -128
  97. package/dist/lib/sandbox/control/native-file-lock.js +85 -0
  98. package/dist/lib/sandbox/control/protocol.js +55 -4
  99. package/dist/lib/sandbox/control/server.js +720 -79
  100. package/dist/lib/sandbox/control/state.js +63 -3
  101. package/dist/lib/sandbox/control/task-view.js +183 -0
  102. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  103. package/dist/lib/sandbox/control/workflow-executor.js +99 -0
  104. package/dist/lib/sandbox/engines/authority.js +289 -0
  105. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  106. package/dist/lib/sandbox/index.js +7 -2
  107. package/dist/lib/sandbox/recovery.js +49 -5
  108. package/dist/lib/sandbox/removal.js +1717 -0
  109. package/dist/lib/sandbox/task-cleanup.js +217 -0
  110. package/dist/lib/sandbox/workspace-view.js +15 -15
  111. package/dist/lib/sandbox/worktree-safety.js +4 -1
  112. package/dist/lib/server/index.js +8 -0
  113. package/dist/lib/task/activity-intent.js +2 -1
  114. package/dist/lib/task/activity-log.js +30 -24
  115. package/dist/lib/task/artifact-command.js +101 -0
  116. package/dist/lib/task/artifact-lifecycle.js +71 -40
  117. package/dist/lib/task/artifact-name.js +36 -0
  118. package/dist/lib/task/artifact-operations.js +474 -0
  119. package/dist/lib/task/artifact-receipts.js +3 -15
  120. package/dist/lib/task/artifact-repair-intent.js +130 -0
  121. package/dist/lib/task/artifact-schema.js +127 -0
  122. package/dist/lib/task/capabilities.js +83 -19
  123. package/dist/lib/task/codex-orchestration.js +71 -25
  124. package/dist/lib/task/commit-identity.js +28 -0
  125. package/dist/lib/task/commit-operation.js +2 -16
  126. package/dist/lib/task/control-authority.js +375 -5
  127. package/dist/lib/task/control-recovery.js +128 -0
  128. package/dist/lib/task/create-service.js +103 -4
  129. package/dist/lib/task/create.js +80 -2
  130. package/dist/lib/task/decision-details.js +2 -46
  131. package/dist/lib/task/events.js +306 -76
  132. package/dist/lib/task/finalization-state.js +9 -0
  133. package/dist/lib/task/human-override.js +3 -6
  134. package/dist/lib/task/implementation-inputs.js +3 -3
  135. package/dist/lib/task/index.js +11 -3
  136. package/dist/lib/task/intermediate-cleanup.js +383 -0
  137. package/dist/lib/task/invalidation.js +18 -65
  138. package/dist/lib/task/ledger-intents.js +7 -22
  139. package/dist/lib/task/ledger.js +1 -3
  140. package/dist/lib/task/lifecycle.js +19 -1
  141. package/dist/lib/task/local-artifact-finalization.js +190 -290
  142. package/dist/lib/task/manual-validation-completion.js +26 -0
  143. package/dist/lib/task/manual-validation-evidence.js +130 -0
  144. package/dist/lib/task/manual-validation-receipt.js +101 -0
  145. package/dist/lib/task/manual-validation-shared.js +40 -0
  146. package/dist/lib/task/manual-validation-transaction.js +243 -0
  147. package/dist/lib/task/markdown.js +47 -0
  148. package/dist/lib/task/orchestration.js +206 -69
  149. package/dist/lib/task/qualification-audit.js +476 -0
  150. package/dist/lib/task/qualification-confirmation.js +109 -0
  151. package/dist/lib/task/qualification-intents.js +148 -0
  152. package/dist/lib/task/review-artifacts.js +23 -40
  153. package/dist/lib/task/review-command.js +25 -0
  154. package/dist/lib/task/review-finalization.js +146 -97
  155. package/dist/lib/task/review-fingerprint.js +2 -2
  156. package/dist/lib/task/sections.js +34 -54
  157. package/dist/lib/task/verification-config.js +11 -0
  158. package/dist/lib/task/verification-engine.js +170 -327
  159. package/dist/lib/task/verification.js +1 -1
  160. package/dist/lib/task/workflow-command.js +17 -0
  161. package/dist/lib/task/workflow-warning-intents.js +0 -16
  162. package/dist/lib/task/workflow-warnings.js +28 -2
  163. package/dist/lib/update.js +2 -0
  164. package/dist/lifecycle-build-manifest.json +3 -3
  165. package/lib/agent-client.ts +9 -0
  166. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  167. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
  168. package/lib/fs/durable-write.ts +29 -0
  169. package/lib/fs/file-lock.ts +113 -0
  170. package/lib/host-control/audit.ts +22 -0
  171. package/lib/host-control/client.ts +172 -0
  172. package/lib/host-control/command.ts +60 -0
  173. package/lib/host-control/path.ts +167 -0
  174. package/lib/host-control/secure-fs.ts +135 -0
  175. package/lib/host-control/server.ts +180 -0
  176. package/lib/host-control/service.ts +133 -0
  177. package/lib/init.ts +15 -2
  178. package/lib/internal/agent-client.ts +4 -2
  179. package/lib/internal/cli-route-inventory.ts +142 -0
  180. package/lib/internal/codex-lifecycle.ts +14 -12
  181. package/lib/internal/codex-sandbox-controller.ts +7 -2
  182. package/lib/internal/demo-promotion.ts +354 -0
  183. package/lib/internal/demo-transcript.ts +419 -0
  184. package/lib/internal/git-workflow.ts +9 -6
  185. package/lib/internal/host-control.ts +28 -0
  186. package/lib/internal/manual-validation.ts +306 -0
  187. package/lib/internal/platform-checks.ts +12 -4
  188. package/lib/internal/platform-comment.ts +12 -4
  189. package/lib/internal/platform-context.ts +3 -1
  190. package/lib/internal/platform-issue.ts +11 -4
  191. package/lib/internal/platform-metadata.ts +70 -0
  192. package/lib/internal/platform-pr-review.ts +14 -3
  193. package/lib/internal/platform-pr.ts +38 -14
  194. package/lib/internal/platform-release-notes.ts +5 -3
  195. package/lib/internal/platform-security.ts +83 -0
  196. package/lib/internal/pr-review-grade.ts +10 -3
  197. package/lib/internal/release-workflow.ts +91 -87
  198. package/lib/internal/sandbox-control.ts +181 -6
  199. package/lib/internal/task-activity.ts +12 -4
  200. package/lib/internal/task-artifact.ts +15 -79
  201. package/lib/internal/task-context.ts +3 -1
  202. package/lib/internal/task-create.ts +76 -15
  203. package/lib/internal/task-delivery.ts +3 -1
  204. package/lib/internal/task-event.ts +21 -10
  205. package/lib/internal/task-finalization.ts +3 -1
  206. package/lib/internal/task-invalidation.ts +3 -1
  207. package/lib/internal/task-ledger.ts +11 -1
  208. package/lib/internal/task-lifecycle.ts +3 -1
  209. package/lib/internal/task-operation-registry.ts +590 -0
  210. package/lib/internal/task-orchestration.ts +12 -0
  211. package/lib/internal/task-override.ts +9 -3
  212. package/lib/internal/task-qualification.ts +61 -0
  213. package/lib/internal/task-review.ts +7 -50
  214. package/lib/internal/task-short-id.ts +10 -1
  215. package/lib/internal/task-snapshot.ts +3 -1
  216. package/lib/internal/task-validate.ts +32 -12
  217. package/lib/internal/task-verify.ts +4 -1
  218. package/lib/internal/task-warning.ts +7 -1
  219. package/lib/owned-path.ts +26 -0
  220. package/lib/platform/check-status.ts +9 -0
  221. package/lib/platform/comment-safety.ts +255 -0
  222. package/lib/platform/completion-backfill.ts +1 -1
  223. package/lib/platform/github-data.ts +322 -0
  224. package/lib/platform/github-provider.ts +244 -27
  225. package/lib/platform/issue-comments.ts +159 -35
  226. package/lib/platform/issues.ts +4 -245
  227. package/lib/platform/pr-change-report.ts +6 -12
  228. package/lib/platform/pr-checks.ts +13 -77
  229. package/lib/platform/pr-summary.ts +88 -11
  230. package/lib/platform/provider-contract.ts +78 -3
  231. package/lib/platform/provider-validation.ts +85 -3
  232. package/lib/platform/pull-requests.ts +129 -348
  233. package/lib/platform/repository-metadata.ts +453 -0
  234. package/lib/platform/security-alerts.ts +191 -0
  235. package/lib/platform/snapshots.ts +53 -0
  236. package/lib/platform/verification-sync.ts +171 -177
  237. package/lib/process-data/index.ts +7 -0
  238. package/lib/release/workflow.ts +3 -3
  239. package/lib/run/index.ts +5 -0
  240. package/lib/sandbox/commands/control-status.ts +26 -0
  241. package/lib/sandbox/commands/create.ts +53 -12
  242. package/lib/sandbox/commands/ls.ts +7 -0
  243. package/lib/sandbox/commands/rm.ts +3 -996
  244. package/lib/sandbox/commands/show.ts +16 -0
  245. package/lib/sandbox/control/audit.ts +253 -0
  246. package/lib/sandbox/control/client.ts +150 -13
  247. package/lib/sandbox/control/completed-reentry.ts +98 -0
  248. package/lib/sandbox/control/container-identity.ts +27 -43
  249. package/lib/sandbox/control/executor.ts +262 -37
  250. package/lib/sandbox/control/finalization-response.ts +29 -0
  251. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  252. package/lib/sandbox/control/lifecycle.ts +672 -18
  253. package/lib/sandbox/control/native-file-lock.ts +108 -0
  254. package/lib/sandbox/control/protocol.ts +80 -8
  255. package/lib/sandbox/control/server.ts +779 -82
  256. package/lib/sandbox/control/state.ts +84 -3
  257. package/lib/sandbox/control/task-view.ts +240 -0
  258. package/lib/sandbox/control/task-workflow.ts +95 -0
  259. package/lib/sandbox/control/workflow-executor.ts +102 -0
  260. package/lib/sandbox/engines/authority.ts +365 -0
  261. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  262. package/lib/sandbox/index.ts +9 -2
  263. package/lib/sandbox/recovery.ts +49 -6
  264. package/lib/sandbox/removal.ts +2144 -0
  265. package/lib/sandbox/task-cleanup.ts +209 -0
  266. package/lib/sandbox/workspace-view.ts +26 -18
  267. package/lib/sandbox/worktree-safety.ts +4 -1
  268. package/lib/server/index.ts +10 -0
  269. package/lib/task/activity-intent.ts +2 -2
  270. package/lib/task/activity-log.ts +27 -19
  271. package/lib/task/artifact-command.ts +104 -0
  272. package/lib/task/artifact-lifecycle.ts +66 -39
  273. package/lib/task/artifact-name.ts +55 -0
  274. package/lib/task/artifact-operations.ts +580 -0
  275. package/lib/task/artifact-receipts.ts +3 -14
  276. package/lib/task/artifact-repair-intent.ts +152 -0
  277. package/lib/task/artifact-schema.ts +163 -0
  278. package/lib/task/capabilities.ts +82 -22
  279. package/lib/task/codex-orchestration.ts +85 -24
  280. package/lib/task/commit-identity.ts +31 -0
  281. package/lib/task/commit-operation.ts +2 -16
  282. package/lib/task/control-authority.ts +513 -6
  283. package/lib/task/control-recovery.ts +174 -0
  284. package/lib/task/create-service.ts +131 -6
  285. package/lib/task/create.ts +83 -1
  286. package/lib/task/decision-details.ts +3 -71
  287. package/lib/task/events.ts +292 -75
  288. package/lib/task/finalization-state.ts +11 -0
  289. package/lib/task/human-override.ts +3 -8
  290. package/lib/task/implementation-inputs.ts +3 -3
  291. package/lib/task/index.ts +16 -3
  292. package/lib/task/intermediate-cleanup.ts +455 -0
  293. package/lib/task/invalidation.ts +18 -62
  294. package/lib/task/ledger-intents.ts +7 -24
  295. package/lib/task/ledger.ts +1 -3
  296. package/lib/task/lifecycle.ts +17 -1
  297. package/lib/task/local-artifact-finalization.ts +223 -388
  298. package/lib/task/manual-validation-completion.ts +40 -0
  299. package/lib/task/manual-validation-evidence.ts +209 -0
  300. package/lib/task/manual-validation-receipt.ts +152 -0
  301. package/lib/task/manual-validation-shared.ts +50 -0
  302. package/lib/task/manual-validation-transaction.ts +304 -0
  303. package/lib/task/markdown.ts +70 -0
  304. package/lib/task/orchestration.ts +191 -68
  305. package/lib/task/qualification-audit.ts +588 -0
  306. package/lib/task/qualification-confirmation.ts +117 -0
  307. package/lib/task/qualification-intents.ts +150 -0
  308. package/lib/task/review-artifacts.ts +21 -41
  309. package/lib/task/review-command.ts +23 -0
  310. package/lib/task/review-finalization.ts +154 -153
  311. package/lib/task/review-fingerprint.ts +2 -2
  312. package/lib/task/sections.ts +33 -52
  313. package/lib/task/verification-config.ts +12 -0
  314. package/lib/task/verification-engine.ts +165 -370
  315. package/lib/task/verification-types.ts +17 -0
  316. package/lib/task/verification.ts +1 -1
  317. package/lib/task/workflow-command.ts +18 -0
  318. package/lib/task/workflow-warning-intents.ts +0 -13
  319. package/lib/task/workflow-warnings.ts +21 -2
  320. package/lib/update.ts +6 -0
  321. package/package.json +7 -2
  322. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  323. package/templates/.agents/rules/README.en.md +2 -0
  324. package/templates/.agents/rules/README.zh-CN.md +2 -0
  325. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  326. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  327. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  328. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  329. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  330. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  331. package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
  332. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
  333. package/templates/.agents/rules/security-alerts.en.md +8 -8
  334. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  335. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  336. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  337. package/templates/.agents/scripts/package.json +3 -0
  338. package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
  339. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
  340. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  341. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  342. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  343. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  344. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  345. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  346. package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
  347. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
  348. package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
  349. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
  350. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  351. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  352. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  353. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  354. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  355. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  356. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  357. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  358. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
  359. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
  360. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  361. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  362. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
  363. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
  364. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  365. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  366. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
  367. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
  368. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  369. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  370. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  371. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  372. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  373. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  374. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  375. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  376. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  377. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  378. package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
  379. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
  380. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  381. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  382. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  383. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  384. package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
  385. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
  386. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  387. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  388. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  389. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  390. package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
  391. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
  392. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  393. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  394. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  395. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  396. package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
  397. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
  398. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  399. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  400. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  401. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  402. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  403. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  404. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  405. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  406. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
  407. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
  408. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  409. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  410. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
  411. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
  412. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  413. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  414. package/templates/.agents/skills/test/SKILL.en.md +29 -7
  415. package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
  416. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  417. package/templates/.agents/templates/task.en.md +6 -0
  418. package/templates/.agents/templates/task.zh-CN.md +6 -0
  419. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  420. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  421. package/dist/lib/platform/adapters.js +0 -56
  422. package/lib/platform/adapters.ts +0 -197
  423. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  424. package/templates/.agents/scripts/security-alerts.sh +0 -31
  425. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  426. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  427. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  428. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -7,6 +7,7 @@ import { platformResult } from './types.js';
7
7
  import { providerError, providerOperationContext, providerStatus, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
8
8
  import { resourceIdentityNumber } from './resource-identity.js';
9
9
  import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
10
+ import { canonicalizeCommentBody, escapeHtmlText, fenceRanges, renderSafeCodeFence } from './comment-safety.js';
10
11
  function providerCommentId(id, provider) {
11
12
  return provider.identity?.comment === 'number' && /^\d+$/.test(id) ? Number(id) : id;
12
13
  }
@@ -37,14 +38,21 @@ function splitFrontmatter(content) {
37
38
  return { frontmatter: null, body: content };
38
39
  return { frontmatter: match[1], body: content.slice(match[0].length).replace(/^\r?\n/, '') };
39
40
  }
41
+ function sanitizeCommentBody(value, label) {
42
+ const result = canonicalizeCommentBody(value);
43
+ if (!result.ok)
44
+ throw new Error(`${result.error.code}: ${label}: ${result.error.message} at offset ${result.error.offset}`);
45
+ return result.value;
46
+ }
40
47
  function footer(agent, taskId) {
41
48
  return `---\n*由 ${agent} 自动生成 · 内部追踪:${taskId}*`;
42
49
  }
43
50
  function renderTaskComment(content, taskId, agent) {
44
51
  const split = splitFrontmatter(content);
52
+ const safeBody = sanitizeCommentBody(split.body, 'task body');
45
53
  const taskBody = split.frontmatter === null
46
- ? split.body
47
- : `<details><summary>元数据 (frontmatter)</summary>\n\n\`\`\`yaml\n---\n${split.frontmatter}\n---\n\`\`\`\n\n</details>\n\n${split.body}`;
54
+ ? safeBody
55
+ : `<details><summary>元数据 (frontmatter)</summary>\n\n${renderSafeCodeFence(`---\n${split.frontmatter}\n---`, 'yaml')}\n\n</details>\n\n${safeBody}`;
48
56
  return normalizeCommentContent([
49
57
  MARKERS.task(taskId),
50
58
  '## 任务文件',
@@ -69,10 +77,11 @@ function chunkByUtf8(content, maxBytes) {
69
77
  if (maxBytes <= 0)
70
78
  throw new Error('comment byte limit is too small');
71
79
  const chunks = [];
72
- let remaining = content;
73
- while (remaining) {
80
+ let start = 0;
81
+ while (start < content.length) {
82
+ const remaining = content.slice(start);
74
83
  if (Buffer.byteLength(remaining, 'utf8') <= maxBytes) {
75
- chunks.push(remaining);
84
+ chunks.push({ content: remaining, start, end: content.length });
76
85
  break;
77
86
  }
78
87
  let bytes = 0;
@@ -90,12 +99,109 @@ function chunkByUtf8(content, maxBytes) {
90
99
  const cut = newlineIndex > 0 ? newlineIndex : index;
91
100
  if (cut === 0)
92
101
  throw new Error('comment byte limit cannot fit one Unicode code point');
93
- chunks.push(remaining.slice(0, cut));
94
- remaining = remaining.slice(cut);
102
+ chunks.push({ content: remaining.slice(0, cut), start, end: start + cut });
103
+ start += cut;
104
+ }
105
+ return chunks.length > 0 ? chunks : [{ content: '', start: 0, end: 0 }];
106
+ }
107
+ function longestFenceLineRun(content, character) {
108
+ const pattern = new RegExp(`^ {0,3}(${character}+)[ \\t]*(?:\\n|$)`, 'gm');
109
+ let longest = 0;
110
+ for (const match of content.matchAll(pattern))
111
+ longest = Math.max(longest, match[1].length);
112
+ return longest;
113
+ }
114
+ function boundedFence(content, sourceCharacter, maxBytes) {
115
+ const candidates = sourceCharacter === '`' ? ['~', '`'] : ['`', '~'];
116
+ for (const character of candidates) {
117
+ const length = Math.max(3, longestFenceLineRun(content, character) + 1);
118
+ const delimiter = character.repeat(length);
119
+ if (Buffer.byteLength(delimiter, 'utf8') * 2 + 2 <= maxBytes)
120
+ return { opening: `${delimiter}\n`, closing: `${delimiter}\n` };
95
121
  }
96
- return chunks.length > 0 ? chunks : [''];
122
+ return null;
123
+ }
124
+ function sourceSlice(piece, start, end) {
125
+ return piece.content.slice(Math.max(0, start - piece.start), Math.max(0, end - piece.start));
97
126
  }
98
- function buildArtifactChunk(taskId, stem, title, agent, content, part, total, chunked, backfill) {
127
+ function renderOversizedFenceChunk(piece, fences, maxBytes) {
128
+ const insertions = new Map();
129
+ const omitted = [];
130
+ const insert = (position, value, ensureLineStart = false) => {
131
+ const values = insertions.get(position) || [];
132
+ values.push({ value, ensureLineStart });
133
+ insertions.set(position, values);
134
+ };
135
+ for (const fence of fences) {
136
+ if (piece.end <= fence.start || piece.start >= fence.end)
137
+ continue;
138
+ const oversized = Buffer.byteLength(fence.opening, 'utf8') > maxBytes
139
+ || Buffer.byteLength(fence.closing, 'utf8') > maxBytes;
140
+ if (!oversized) {
141
+ if (piece.start > fence.start && piece.start < fence.end)
142
+ insert(piece.start, fence.opening);
143
+ if (piece.end > fence.start && piece.end < fence.end)
144
+ insert(piece.end, fence.closing, true);
145
+ continue;
146
+ }
147
+ const code = sourceSlice(piece, Math.max(piece.start, fence.openingEnd), Math.min(piece.end, fence.closingStart));
148
+ const delimiter = boundedFence(code, fence.character, maxBytes);
149
+ if (!delimiter)
150
+ return escapeHtmlText(piece.content);
151
+ insert(Math.max(piece.start, fence.start), delimiter.opening);
152
+ insert(Math.min(piece.end, fence.end), delimiter.closing, true);
153
+ const openingStart = Math.max(piece.start, fence.start);
154
+ const openingEnd = Math.min(piece.end, fence.openingEnd);
155
+ if (openingStart < openingEnd)
156
+ omitted.push({ start: openingStart, end: openingEnd });
157
+ const closingStart = Math.max(piece.start, fence.closingStart);
158
+ const closingEnd = Math.min(piece.end, fence.end);
159
+ if (closingStart < closingEnd)
160
+ omitted.push({ start: closingStart, end: closingEnd });
161
+ }
162
+ const boundaries = new Set([piece.start, piece.end]);
163
+ for (const position of insertions.keys())
164
+ boundaries.add(position);
165
+ for (const range of omitted) {
166
+ boundaries.add(range.start);
167
+ boundaries.add(range.end);
168
+ }
169
+ const points = [...boundaries].sort((left, right) => left - right);
170
+ let content = '';
171
+ for (let index = 0; index < points.length; index += 1) {
172
+ const point = points[index];
173
+ for (const insertion of insertions.get(point) || []) {
174
+ if (insertion.ensureLineStart && content.length > 0 && !content.endsWith('\n'))
175
+ content += '\n';
176
+ content += insertion.value;
177
+ }
178
+ const next = points[index + 1];
179
+ if (next === undefined)
180
+ continue;
181
+ const skipped = omitted.some((range) => range.start <= point && next <= range.end);
182
+ if (!skipped)
183
+ content += sourceSlice(piece, point, next);
184
+ }
185
+ return content;
186
+ }
187
+ function independentChunkContent(piece, fences, maxBytes) {
188
+ const oversizedFence = fences.some((fence) => piece.end > fence.start && piece.start < fence.end
189
+ && (Buffer.byteLength(fence.opening, 'utf8') > maxBytes || Buffer.byteLength(fence.closing, 'utf8') > maxBytes));
190
+ if (oversizedFence)
191
+ return renderOversizedFenceChunk(piece, fences, maxBytes);
192
+ const openingFence = fences.find((fence) => piece.start > fence.start && piece.start < fence.end);
193
+ const closingFence = fences.find((fence) => piece.end > fence.start && piece.end < fence.end);
194
+ let content = piece.content;
195
+ if (openingFence)
196
+ content = openingFence.opening + content;
197
+ if (closingFence) {
198
+ if (!content.endsWith('\n'))
199
+ content += '\n';
200
+ content += closingFence.closing;
201
+ }
202
+ return content;
203
+ }
204
+ function buildArtifactChunk(taskId, stem, title, agent, content, part, total, chunked, backfill, renderedContent = content) {
99
205
  const marker = chunked ? MARKERS.artifactChunk(taskId, stem, part, total) : MARKERS.artifact(taskId, stem);
100
206
  const heading = chunked ? `## ${title}(${part}/${total})` : `## ${title}`;
101
207
  const timelineHint = backfill ? '> 历史产物补发' : null;
@@ -106,7 +212,7 @@ function buildArtifactChunk(taskId, stem, title, agent, content, part, total, ch
106
212
  '',
107
213
  `> **${agent}** · ${taskId}`,
108
214
  '',
109
- content,
215
+ renderedContent,
110
216
  '',
111
217
  footer(agent, taskId)
112
218
  ].join('\n'));
@@ -115,25 +221,32 @@ function buildArtifactChunk(taskId, stem, title, agent, content, part, total, ch
115
221
  function chunkArtifactComment(input) {
116
222
  const byteLimit = input.byteLimit || 60_000;
117
223
  const identity = artifactIdentity(input.artifact);
118
- const single = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, input.body, 1, 1, false, Boolean(input.backfill));
224
+ const safeBody = sanitizeCommentBody(input.body, 'artifact body');
225
+ const single = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, safeBody, 1, 1, false, Boolean(input.backfill));
119
226
  if (Buffer.byteLength(single.body, 'utf8') <= byteLimit)
120
227
  return [single];
121
228
  let total = 2;
122
- let pieces = [];
229
+ let payloadLimit = Number.POSITIVE_INFINITY;
230
+ const ranges = fenceRanges(safeBody);
231
+ if (!ranges.ok)
232
+ throw new Error(`${ranges.error.code}: artifact body: ${ranges.error.message} at offset ${ranges.error.offset}`);
123
233
  for (;;) {
124
234
  const probe = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, '', total, total, true, Boolean(input.backfill));
125
235
  const available = byteLimit - Buffer.byteLength(probe.body, 'utf8');
126
- pieces = chunkByUtf8(input.body, available);
127
- if (pieces.length === total)
128
- break;
129
- total = pieces.length;
236
+ const sourceLimit = Math.min(available, payloadLimit);
237
+ if (sourceLimit <= 0)
238
+ throw new Error('comment byte limit is too small for an artifact chunk');
239
+ const pieces = chunkByUtf8(safeBody, sourceLimit);
240
+ if (pieces.length !== total) {
241
+ total = pieces.length;
242
+ continue;
243
+ }
244
+ const chunks = pieces.map((piece, index) => buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, piece.content, index + 1, total, true, Boolean(input.backfill), independentChunkContent(piece, ranges.value, sourceLimit)));
245
+ const overflow = Math.max(...chunks.map((chunk) => Buffer.byteLength(chunk.body, 'utf8') - byteLimit));
246
+ if (overflow <= 0)
247
+ return chunks;
248
+ payloadLimit = sourceLimit - overflow;
130
249
  }
131
- return pieces.map((content, index) => {
132
- const chunk = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, content, index + 1, total, true, Boolean(input.backfill));
133
- if (Buffer.byteLength(chunk.body, 'utf8') > byteLimit)
134
- throw new Error('rendered comment exceeds byte limit');
135
- return chunk;
136
- });
137
250
  }
138
251
  function findMarkerComments(comments, marker) {
139
252
  return comments.filter((comment) => normalizeCommentContent(String(comment.body || '')).split('\n', 1)[0] === marker);
@@ -166,7 +279,7 @@ function hasResolvedPlatformContext(context) {
166
279
  }
167
280
  function bodyEnvelope(marker, title, taskId, agent, body) {
168
281
  return normalizeCommentContent([
169
- marker, `## ${title}`, '', `> **${agent}** · ${taskId}`, '', body.replace(/\n+$/, ''), '', footer(agent, taskId)
282
+ marker, `## ${title}`, '', `> **${agent}** · ${taskId}`, '', sanitizeCommentBody(body, `${title} body`).replace(/\n+$/, ''), '', footer(agent, taskId)
170
283
  ].join('\n'));
171
284
  }
172
285
  function resolveArtifactBody(taskDir, artifact) {
@@ -271,6 +384,16 @@ async function syncPlatformComment(taskRef, options) {
271
384
  error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid issue_number', retryable: false }
272
385
  });
273
386
  }
387
+ let desired;
388
+ try {
389
+ desired = expectedComments(resolved.taskId, taskContent, resolved.taskDir, options);
390
+ }
391
+ catch (error) {
392
+ return platformResult('failed', {
393
+ resource: { kind: 'issue', number: resourceIdentityNumber(issueIdentityFromTask) },
394
+ error: { code: 'COMMENT_PAYLOAD_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
395
+ });
396
+ }
274
397
  const loaded = await resolvePlatformProviderContext({ cwd: resolved.repoRoot, client: options.client });
275
398
  const context = loaded.ok ? loaded.value.context : loaded.context;
276
399
  if (!hasResolvedPlatformContext(context) || !loaded.ok)
@@ -293,17 +416,6 @@ async function syncPlatformComment(taskRef, options) {
293
416
  ...contextFields(context), resource: { kind: 'issue', number: issue }, error: listed.error
294
417
  });
295
418
  }
296
- let desired;
297
- try {
298
- desired = expectedComments(resolved.taskId, taskContent, resolved.taskDir, options);
299
- }
300
- catch (error) {
301
- return platformResult('failed', {
302
- ...contextFields(context),
303
- resource: { kind: 'issue', number: issue },
304
- error: { code: 'COMMENT_PAYLOAD_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
305
- });
306
- }
307
419
  const existing = relatedComments(listed.value, markerPrefix(resolved.taskId, options));
308
420
  if (!validateRelatedMarkerSet(existing, markerPrefix(resolved.taskId, options)).ok) {
309
421
  return platformResult('failed', {
@@ -14,8 +14,6 @@ import { labelDelta, planInLabelUpdate, syncLabelDelta, validateInLabelMapping,
14
14
  import { providerError, providerOperationContext, providerStatus, providerResourceIdentity, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
15
15
  import { resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, serializeResourceIdentity } from './resource-identity.js';
16
16
  import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
17
- const ISSUE_TYPES_QUERY = `query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}`;
18
- const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
19
17
  function result(status, taskId, issueNumber, overrides = {}) {
20
18
  return {
21
19
  ...platformResult(status),
@@ -133,115 +131,6 @@ async function inspectExternalIssue(base, issueIdentity) {
133
131
  error: null
134
132
  });
135
133
  }
136
- function normalizeIssue(remote, repository, fallbackNumber) {
137
- const number = Number.isInteger(remote.number) && Number(remote.number) > 0
138
- ? Number(remote.number)
139
- : fallbackNumber;
140
- if (!number || !Number.isSafeInteger(number) || remote.pull_request)
141
- return null;
142
- return {
143
- repository,
144
- number,
145
- databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
146
- nodeId: remote.node_id || `issue-${number}`,
147
- url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
148
- state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
149
- title: remote.title || '',
150
- body: remote.body || '',
151
- labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
152
- assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
153
- milestone: remote.milestone?.title || null,
154
- issueType: remote.type?.name || null,
155
- fields: {}
156
- };
157
- }
158
- function fieldKind(value) {
159
- if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue')
160
- return 'single-select';
161
- if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue')
162
- return 'date';
163
- if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue')
164
- return 'text';
165
- if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue')
166
- return 'number';
167
- return null;
168
- }
169
- function normalizeFieldSchemas(value) {
170
- if (!Array.isArray(value))
171
- return [];
172
- return value.flatMap((raw) => {
173
- const item = raw;
174
- const kind = fieldKind(item);
175
- return item.id && item.name && kind ? [{
176
- id: item.id,
177
- name: item.name,
178
- kind,
179
- options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
180
- }] : [];
181
- });
182
- }
183
- function normalizeIssueTypes(value) {
184
- const nodes = value?.data?.organization?.issueTypes?.nodes;
185
- return (nodes || []).flatMap((raw) => {
186
- const item = raw;
187
- return item.id && item.name ? [{ id: item.id, name: item.name, fields: normalizeFieldSchemas(item.pinnedFields) }] : [];
188
- });
189
- }
190
- function normalizeCurrentFields(value) {
191
- const issue = value?.data?.repository?.issue;
192
- const type = issue?.issueType?.name ? {
193
- id: issue.issueType.id || issue.issueType.name,
194
- name: issue.issueType.name,
195
- fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
196
- } : null;
197
- const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
198
- const item = raw;
199
- const kind = fieldKind(item);
200
- const value = kind === 'single-select' ? item.name : item.value;
201
- return item.field?.name && kind && value !== undefined
202
- ? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
203
- : [];
204
- });
205
- return { issueId: issue?.id || null, type, values };
206
- }
207
- function graphState(client, repository, issue, cwd) {
208
- const [owner, name] = repository.split('/');
209
- if (!owner || !name)
210
- return null;
211
- const current = client.json([
212
- 'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
213
- ], { cwd });
214
- if (!current.ok)
215
- return null;
216
- return normalizeCurrentFields(current.value);
217
- }
218
- function fetchIssue(client, repository, issue, cwd) {
219
- return client.json(['api', `repos/${repository}/issues/${issue}`], { cwd });
220
- }
221
- function inspectGitHubIssue(client, repository, issue, cwd) {
222
- const fetched = fetchIssue(client, repository, issue, cwd);
223
- if (!fetched.ok)
224
- return fetched;
225
- const snapshot = normalizeIssue(fetched.value, repository, issue);
226
- return snapshot
227
- ? { ok: true, value: snapshot }
228
- : { ok: false, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
229
- }
230
- function inspectGitHubIssueMetadata(client, repository, issue, cwd) {
231
- const fetched = fetchIssue(client, repository, issue, cwd);
232
- if (!fetched.ok)
233
- return fetched;
234
- const remote = fetched.value;
235
- return {
236
- ok: true,
237
- value: {
238
- state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
239
- labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
240
- body: remote.body || '',
241
- milestone: remote.milestone?.title || null
242
- }
243
- };
244
- }
245
134
  async function inspectPlatformIssue(taskRef, options = {}) {
246
135
  const base = await resolvedContext(taskRef, options);
247
136
  if (!base.ok)
@@ -450,12 +339,6 @@ function requirementsFromTask(content) {
450
339
  checked: match[1].toLowerCase() === 'x', text: match[2]
451
340
  }));
452
341
  }
453
- function flattenPages(value) {
454
- return Array.isArray(value) ? value.flatMap((item) => Array.isArray(item) ? item : [item]) : [];
455
- }
456
- function listNames(value) {
457
- return flattenPages(value).map((item) => typeof item === 'string' ? item : String(item.name || '')).filter(Boolean);
458
- }
459
342
  function milestoneBasis(repoRoot, current) {
460
343
  if (!current || !/^\d+\.\d+\.x$/.test(current))
461
344
  return current;
@@ -552,67 +435,6 @@ function desiredFieldValues(frontmatter, fields) {
552
435
  }
553
436
  return desired;
554
437
  }
555
- function planGraphMetadata(client, repository, issue, cwd, frontmatter, options, capabilities) {
556
- if (!options.issueType && !options.fields)
557
- return { operations: [], issueId: null };
558
- if (!capabilities.push)
559
- return {
560
- operations: [
561
- ...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : []),
562
- ...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : [])
563
- ], issueId: null
564
- };
565
- const [owner] = repository.split('/');
566
- const typesResult = client.json(['api', 'graphql', '-f', `query=${ISSUE_TYPES_QUERY}`, '-F', `owner=${owner}`], { cwd });
567
- if (!typesResult.ok)
568
- return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: typesResult.error.code }], issueId: null };
569
- const types = normalizeIssueTypes(typesResult.value);
570
- if (types.length === 0)
571
- return {
572
- operations: [
573
- ...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : []),
574
- ...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : [])
575
- ], issueId: null
576
- };
577
- const current = graphState(client, repository, issue, cwd);
578
- if (!current?.issueId)
579
- return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: 'ISSUE_GRAPH_IDENTITY_INVALID' }], issueId: null };
580
- const target = types.find((type) => type.name === desiredIssueType(frontmatter.type || ''));
581
- if (!target)
582
- return { operations: [{ name: 'issue-type', status: 'failed', reasonCode: 'ISSUE_TYPE_NOT_FOUND' }], issueId: current.issueId };
583
- const operations = [];
584
- if (options.issueType)
585
- operations.push(current.type?.id === target.id
586
- ? { name: 'issue-type', status: 'no-op', reasonCode: null }
587
- : { name: 'issue-type', status: 'planned', reasonCode: null, value: { issueTypeId: target.id } });
588
- if (options.fields) {
589
- const desired = desiredFieldValues(frontmatter, target.fields);
590
- const inputs = desired.filter((field) => current.values.find((value) => value.name === field.name)?.value !== field.value).map((field) => field.input);
591
- if (current.type?.id !== target.id) {
592
- const targetNames = new Set(target.fields.map((field) => field.name));
593
- for (const old of current.values)
594
- if (!targetNames.has(old.name))
595
- inputs.push({ fieldId: old.id, delete: true });
596
- }
597
- operations.push(inputs.length === 0
598
- ? { name: 'fields', status: 'no-op', reasonCode: null }
599
- : { name: 'fields', status: 'planned', reasonCode: null, value: inputs });
600
- }
601
- return { operations, issueId: current.issueId };
602
- }
603
- function executeGraphOperation(client, cwd, issueId, operation) {
604
- if (operation.name === 'issue-type') {
605
- const query = 'mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}';
606
- const typeId = operation.value.issueTypeId;
607
- return client.json(['api', 'graphql', '--input', '-'], {
608
- cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueTypeId: typeId } })
609
- });
610
- }
611
- const query = 'mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}';
612
- return client.json(['api', 'graphql', '--input', '-'], {
613
- cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueFields: operation.value } })
614
- });
615
- }
616
438
  async function syncPlatformIssue(taskRef, options) {
617
439
  const base = await resolvedContext(taskRef, options);
618
440
  if (!base.ok)
@@ -761,5 +583,5 @@ async function syncPlatformIssue(taskRef, options) {
761
583
  operations: plan.operations.map((operation) => operation.status === 'planned' ? { ...operation, status: 'applied' } : operation), error: null
762
584
  });
763
585
  }
764
- export { bindPlatformIssue, createPlatformIssue, graphState, inspectGitHubIssue, inspectGitHubIssueMetadata, inspectPlatformIssue, normalizeIssue, requirementSectionAnchors, syncPlatformIssue };
586
+ export { bindPlatformIssue, createPlatformIssue, inspectPlatformIssue, requirementSectionAnchors, syncPlatformIssue };
765
587
  //# sourceMappingURL=issues.js.map
@@ -2,6 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { createHash, randomUUID } from 'node:crypto';
4
4
  import { execFileSync } from 'node:child_process';
5
+ import { escapeHtmlText } from './comment-safety.js';
5
6
  const REPORT_FILE_NAME = 'pr-change-report.json';
6
7
  const REPORT_VERSION = 1;
7
8
  const CANONICAL_REPORT_PLACEHOLDER = '<!-- canonical-pr-change-report -->';
@@ -429,21 +430,14 @@ const MAX_REPRESENTATIVE_FILES = 3;
429
430
  function representativePath(file) {
430
431
  return file.newPath || file.oldPath || '';
431
432
  }
432
- function escapeHtml(value) {
433
- return value
434
- .replaceAll('&', '&amp;')
435
- .replaceAll('<', '&lt;')
436
- .replaceAll('>', '&gt;')
437
- .replaceAll('"', '&quot;')
438
- .replaceAll("'", '&#39;')
439
- .replaceAll('\r', '\\r')
440
- .replaceAll('\n', '\\n');
433
+ function escapeReportText(value) {
434
+ return escapeHtmlText(value).replaceAll('\r', '\\r').replaceAll('\n', '\\n');
441
435
  }
442
436
  function renderRepresentativePath(file) {
443
437
  const paths = file.oldPath && file.newPath && file.oldPath !== file.newPath
444
438
  ? [file.oldPath, file.newPath]
445
439
  : [representativePath(file)];
446
- return paths.map((filePath) => `<code>${escapeHtml(filePath)}</code>`).join(' → ');
440
+ return paths.map((filePath) => `<code>${escapeReportText(filePath)}</code>`).join(' → ');
447
441
  }
448
442
  function representativeScore(file, metric) {
449
443
  return metric === 'lines' ? file.additions + file.deletions : Math.abs(file.netBytes);
@@ -492,11 +486,11 @@ function renderEvidence(evidence) {
492
486
  ? `:${evidence.startLine}`
493
487
  : `:${evidence.startLine}-${evidence.endLine}`
494
488
  : `:${evidence.startLine ?? evidence.endLine}`;
495
- return ` - 证据:<code>${escapeHtml(evidence.path)}</code>${location}:${escapeHtml(evidence.detail)}`;
489
+ return ` - 证据:<code>${escapeReportText(evidence.path)}</code>${location}:${escapeReportText(evidence.detail)}`;
496
490
  }
497
491
  function renderPrechecks(checks) {
498
492
  return checks.flatMap((check) => [
499
- `- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${escapeHtml(check.rationale)}`,
493
+ `- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${escapeReportText(check.rationale)}`,
500
494
  ...check.evidence.slice(0, 1).map(renderEvidence)
501
495
  ]);
502
496
  }
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
3
3
  import { resolveTaskRef } from '../task/resolve-ref.js';
4
+ import { checkStatusBucket } from './check-status.js';
4
5
  import { resolvePlatformProviderContext } from './context.js';
5
6
  import { inspectPlatformPullRequest } from './pull-requests.js';
6
7
  import { platformResult } from './types.js';
@@ -26,20 +27,6 @@ function classifyPullRequestReadiness(input) {
26
27
  return { state: 'pending', headSha: input.headSha };
27
28
  return { state: 'ready', headSha: input.headSha };
28
29
  }
29
- function parseRunJobIdentity(detailsUrl) {
30
- try {
31
- const url = new URL(detailsUrl);
32
- if (url.hostname !== 'github.com')
33
- return null;
34
- const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
35
- if (!match)
36
- return null;
37
- return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
38
- }
39
- catch {
40
- return null;
41
- }
42
- }
43
30
  function resolveRunCandidate(candidates, headSha, checkName) {
44
31
  const matches = candidates.filter((candidate) => candidate.headSha === headSha && candidate.name === checkName);
45
32
  if (matches.length === 1)
@@ -54,42 +41,6 @@ function checksResult(status, overrides = {}) {
54
41
  ...overrides
55
42
  };
56
43
  }
57
- function normalizeBucket(value) {
58
- const raw = String(value.bucket || value.status || value.conclusion || value.state || '').toLowerCase();
59
- if (['pass', 'success', 'successful', 'neutral'].includes(raw))
60
- return 'pass';
61
- if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(raw))
62
- return 'fail';
63
- if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(raw))
64
- return 'cancel';
65
- return 'pending';
66
- }
67
- function normalizeChecks(value) {
68
- if (!Array.isArray(value))
69
- return [];
70
- return value.flatMap((raw) => {
71
- const item = raw;
72
- const name = String(item.name || item.context || '');
73
- return name ? [{
74
- name,
75
- bucket: normalizeBucket(item),
76
- workflow: item.workflow ? String(item.workflow) : null,
77
- conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
78
- detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null,
79
- startedAt: item.startedAt ? String(item.startedAt) : null,
80
- completedAt: item.completedAt ? String(item.completedAt) : null
81
- }] : [];
82
- });
83
- }
84
- function inspectGitHubRequiredChecks(client, repository, number, cwd) {
85
- const inspected = client.json([
86
- 'pr', 'checks', String(number), '--repo', repository,
87
- '--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
88
- ], { cwd });
89
- return inspected.ok
90
- ? { ok: true, value: normalizeChecks(inspected.value) }
91
- : { ok: false, error: inspected.error };
92
- }
93
44
  async function resolvedTask(taskRef, options) {
94
45
  const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
95
46
  if (!resolved.ok)
@@ -117,10 +68,9 @@ async function inspectRequiredChecks(taskRef, options = {}) {
117
68
  const base = await resolvedTask(taskRef, options);
118
69
  if (!base.ok)
119
70
  return base.output;
120
- return inspectChecksForResolvedTask(base, options);
71
+ return inspectChecksForResolvedTask(base);
121
72
  }
122
- async function inspectChecksForResolvedTask(base, options) {
123
- const repository = base.context.platform.repository;
73
+ async function inspectChecksForResolvedTask(base) {
124
74
  {
125
75
  const inspected = base.provider.checks?.inspectRequired
126
76
  ? await base.provider.checks.inspectRequired({
@@ -137,7 +87,13 @@ async function inspectChecksForResolvedTask(base, options) {
137
87
  pullRequest: base.pullRequest,
138
88
  error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
139
89
  });
140
- const required = normalizeChecks(inspected.value);
90
+ const required = inspected.value.map((check) => ({
91
+ name: check.name,
92
+ bucket: checkStatusBucket(check.status),
93
+ conclusion: check.conclusion || null,
94
+ detailsUrl: check.detailsUrl || null,
95
+ workflow: null, startedAt: null, completedAt: null
96
+ }));
141
97
  const classified = classifyRequiredChecks(required);
142
98
  const status = classified.state === 'passed' || classified.state === 'no-required'
143
99
  ? 'no-op'
@@ -157,7 +113,7 @@ async function inspectPullRequestReadiness(taskRef, options = {}) {
157
113
  const base = await resolvedTask(taskRef, options);
158
114
  if (!base.ok)
159
115
  return base.output;
160
- const checked = await inspectChecksForResolvedTask(base, options);
116
+ const checked = await inspectChecksForResolvedTask(base);
161
117
  const classifiedCodes = new Set(['REQUIRED_CHECKS_PENDING', 'REQUIRED_CHECKS_FAILED', 'REQUIRED_CHECKS_CANCELLED']);
162
118
  if (checked.error && !classifiedCodes.has(checked.error.code))
163
119
  return checked;
@@ -242,15 +198,6 @@ async function resolvePlatformCheckRun(taskRef, options) {
242
198
  });
243
199
  }
244
200
  }
245
- function fetchCheckLogText(client, args, cwd) {
246
- if (!client.text)
247
- return { ok: false, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
248
- const fetched = client.text(args, { cwd });
249
- if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
250
- return fetched;
251
- }
252
- return client.text([...args, '--allow-escape-sequences'], { cwd });
253
- }
254
201
  async function fetchPlatformCheckLogs(taskRef, options) {
255
202
  const base = await resolvedTask(taskRef, options);
256
203
  if (!base.ok)
@@ -281,5 +228,5 @@ async function fetchPlatformCheckLogs(taskRef, options) {
281
228
  });
282
229
  }
283
230
  }
284
- export { classifyPullRequestReadiness, classifyRequiredChecks, fetchCheckLogText, fetchPlatformCheckLogs, inspectGitHubRequiredChecks, inspectRequiredChecks, inspectPullRequestReadiness, parseRunJobIdentity, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
231
+ export { classifyPullRequestReadiness, classifyRequiredChecks, fetchPlatformCheckLogs, inspectRequiredChecks, inspectPullRequestReadiness, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
285
232
  //# sourceMappingURL=pr-checks.js.map