agentplane 0.3.9 → 0.3.11

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 (404) hide show
  1. package/assets/AGENTS.md +4 -2
  2. package/assets/agents/CODER.json +1 -1
  3. package/assets/policy/dod.core.md +1 -1
  4. package/assets/policy/governance.md +5 -3
  5. package/assets/policy/incidents.md +19 -77
  6. package/assets/policy/workflow.branch_pr.md +2 -0
  7. package/assets/policy/workflow.direct.md +3 -1
  8. package/bin/agentplane.js +56 -1
  9. package/bin/runtime-watch.js +1 -0
  10. package/bin/stale-dist-policy.d.ts +1 -1
  11. package/bin/stale-dist-policy.js +13 -0
  12. package/dist/.build-manifest.json +462 -202
  13. package/dist/cli/bootstrap-guide.d.ts +1 -0
  14. package/dist/cli/bootstrap-guide.d.ts.map +1 -1
  15. package/dist/cli/bootstrap-guide.js +20 -1
  16. package/dist/cli/command-guide.d.ts.map +1 -1
  17. package/dist/cli/command-guide.js +2 -1
  18. package/dist/cli/command-invocations.d.ts.map +1 -1
  19. package/dist/cli/command-invocations.js +6 -1
  20. package/dist/cli/command-snippets.d.ts +2 -0
  21. package/dist/cli/command-snippets.d.ts.map +1 -1
  22. package/dist/cli/command-snippets.js +2 -0
  23. package/dist/cli/run-cli/command-catalog/core.d.ts +1 -1
  24. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
  25. package/dist/cli/run-cli/command-catalog/core.js +10 -0
  26. package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
  27. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
  28. package/dist/cli/run-cli/command-catalog/project.js +3 -1
  29. package/dist/cli/run-cli/command-catalog/task.d.ts +1 -1
  30. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
  31. package/dist/cli/run-cli/command-catalog/task.js +10 -0
  32. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  33. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  34. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  35. package/dist/cli/run-cli/commands/config.js +13 -0
  36. package/dist/cli/run-cli/commands/core/preflight.d.ts.map +1 -1
  37. package/dist/cli/run-cli/commands/core/preflight.js +44 -1
  38. package/dist/cli/run-cli.js +2 -2
  39. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  40. package/dist/cli/run-cli.test-helpers.js +12 -0
  41. package/dist/commands/backend.d.ts.map +1 -1
  42. package/dist/commands/backend.js +4 -0
  43. package/dist/commands/branch/cleanup-merged.d.ts +2 -0
  44. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
  45. package/dist/commands/branch/cleanup-merged.js +132 -28
  46. package/dist/commands/branch/work-start.d.ts.map +1 -1
  47. package/dist/commands/branch/work-start.js +60 -1
  48. package/dist/commands/cleanup/merged.command.d.ts +2 -0
  49. package/dist/commands/cleanup/merged.command.d.ts.map +1 -1
  50. package/dist/commands/cleanup/merged.command.js +24 -0
  51. package/dist/commands/doctor/branch-pr.d.ts +4 -0
  52. package/dist/commands/doctor/branch-pr.d.ts.map +1 -0
  53. package/dist/commands/doctor/branch-pr.js +96 -0
  54. package/dist/commands/doctor/fixes.d.ts +5 -0
  55. package/dist/commands/doctor/fixes.d.ts.map +1 -1
  56. package/dist/commands/doctor/fixes.js +70 -0
  57. package/dist/commands/doctor.run.d.ts.map +1 -1
  58. package/dist/commands/doctor.run.js +6 -1
  59. package/dist/commands/finish.run.d.ts.map +1 -1
  60. package/dist/commands/finish.run.js +11 -0
  61. package/dist/commands/finish.spec.d.ts +11 -0
  62. package/dist/commands/finish.spec.d.ts.map +1 -1
  63. package/dist/commands/finish.spec.js +51 -0
  64. package/dist/commands/guard/impl/close-message.d.ts.map +1 -1
  65. package/dist/commands/guard/impl/close-message.js +23 -6
  66. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  67. package/dist/commands/guard/impl/commands.js +24 -2
  68. package/dist/commands/guard/impl/env.d.ts +1 -0
  69. package/dist/commands/guard/impl/env.d.ts.map +1 -1
  70. package/dist/commands/guard/impl/env.js +1 -0
  71. package/dist/commands/hooks/index.d.ts.map +1 -1
  72. package/dist/commands/hooks/index.js +98 -1
  73. package/dist/commands/incidents/advise.command.d.ts +15 -0
  74. package/dist/commands/incidents/advise.command.d.ts.map +1 -0
  75. package/dist/commands/incidents/advise.command.js +139 -0
  76. package/dist/commands/incidents/collect.command.d.ts +11 -0
  77. package/dist/commands/incidents/collect.command.d.ts.map +1 -0
  78. package/dist/commands/incidents/collect.command.js +72 -0
  79. package/dist/commands/incidents/incidents.command.d.ts +5 -0
  80. package/dist/commands/incidents/incidents.command.d.ts.map +1 -0
  81. package/dist/commands/incidents/incidents.command.js +21 -0
  82. package/dist/commands/incidents/shared.d.ts +76 -0
  83. package/dist/commands/incidents/shared.d.ts.map +1 -0
  84. package/dist/commands/incidents/shared.js +261 -0
  85. package/dist/commands/pr/check.d.ts.map +1 -1
  86. package/dist/commands/pr/check.js +249 -75
  87. package/dist/commands/pr/close-superseded.d.ts +9 -0
  88. package/dist/commands/pr/close-superseded.d.ts.map +1 -0
  89. package/dist/commands/pr/close-superseded.js +129 -0
  90. package/dist/commands/pr/close.d.ts +11 -0
  91. package/dist/commands/pr/close.d.ts.map +1 -0
  92. package/dist/commands/pr/close.js +116 -0
  93. package/dist/commands/pr/index.d.ts +2 -0
  94. package/dist/commands/pr/index.d.ts.map +1 -1
  95. package/dist/commands/pr/index.js +2 -0
  96. package/dist/commands/pr/integrate/artifacts.d.ts +7 -0
  97. package/dist/commands/pr/integrate/artifacts.d.ts.map +1 -1
  98. package/dist/commands/pr/integrate/artifacts.js +66 -1
  99. package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
  100. package/dist/commands/pr/integrate/cmd.js +20 -0
  101. package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts +8 -0
  102. package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts.map +1 -0
  103. package/dist/commands/pr/integrate/internal/bootstrap-guidance.js +59 -0
  104. package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
  105. package/dist/commands/pr/integrate/internal/finalize.js +40 -12
  106. package/dist/commands/pr/integrate/internal/merge.d.ts +4 -0
  107. package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -1
  108. package/dist/commands/pr/integrate/internal/merge.js +59 -15
  109. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts +13 -0
  110. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts.map +1 -0
  111. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.js +25 -0
  112. package/dist/commands/pr/integrate/internal/prepare.d.ts +3 -2
  113. package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
  114. package/dist/commands/pr/integrate/internal/prepare.js +107 -19
  115. package/dist/commands/pr/internal/freshness.d.ts +20 -0
  116. package/dist/commands/pr/internal/freshness.d.ts.map +1 -0
  117. package/dist/commands/pr/internal/freshness.js +50 -0
  118. package/dist/commands/pr/internal/gh-api.d.ts +6 -0
  119. package/dist/commands/pr/internal/gh-api.d.ts.map +1 -0
  120. package/dist/commands/pr/internal/gh-api.js +80 -0
  121. package/dist/commands/pr/internal/note-store.d.ts +18 -0
  122. package/dist/commands/pr/internal/note-store.d.ts.map +1 -0
  123. package/dist/commands/pr/internal/note-store.js +66 -0
  124. package/dist/commands/pr/internal/pr-paths.d.ts +13 -0
  125. package/dist/commands/pr/internal/pr-paths.d.ts.map +1 -1
  126. package/dist/commands/pr/internal/pr-paths.js +13 -0
  127. package/dist/commands/pr/internal/review-template.d.ts +24 -4
  128. package/dist/commands/pr/internal/review-template.d.ts.map +1 -1
  129. package/dist/commands/pr/internal/review-template.js +221 -33
  130. package/dist/commands/pr/internal/sync.d.ts +41 -0
  131. package/dist/commands/pr/internal/sync.d.ts.map +1 -0
  132. package/dist/commands/pr/internal/sync.js +598 -0
  133. package/dist/commands/pr/note.d.ts.map +1 -1
  134. package/dist/commands/pr/note.js +37 -4
  135. package/dist/commands/pr/open.d.ts +1 -0
  136. package/dist/commands/pr/open.d.ts.map +1 -1
  137. package/dist/commands/pr/open.js +18 -54
  138. package/dist/commands/pr/pr.command.d.ts +15 -0
  139. package/dist/commands/pr/pr.command.d.ts.map +1 -1
  140. package/dist/commands/pr/pr.command.js +124 -5
  141. package/dist/commands/pr/update.d.ts.map +1 -1
  142. package/dist/commands/pr/update.js +58 -74
  143. package/dist/commands/recipes/impl/commands/cache-prune.d.ts.map +1 -1
  144. package/dist/commands/recipes/impl/commands/cache-prune.js +14 -0
  145. package/dist/commands/recipes/impl/commands/install.js +1 -1
  146. package/dist/commands/recipes/impl/commands/list-remote.d.ts.map +1 -1
  147. package/dist/commands/recipes/impl/commands/list-remote.js +1 -0
  148. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
  149. package/dist/commands/recipes/impl/commands/remove.js +9 -1
  150. package/dist/commands/release/apply.command.d.ts.map +1 -1
  151. package/dist/commands/release/apply.command.js +12 -17
  152. package/dist/commands/release/apply.preflight.d.ts.map +1 -1
  153. package/dist/commands/release/apply.preflight.js +1 -1
  154. package/dist/commands/shared/approval-requirements.d.ts +5 -7
  155. package/dist/commands/shared/approval-requirements.d.ts.map +1 -1
  156. package/dist/commands/shared/approval-requirements.js +3 -73
  157. package/dist/commands/shared/gh-transport.d.ts +16 -0
  158. package/dist/commands/shared/gh-transport.d.ts.map +1 -0
  159. package/dist/commands/shared/gh-transport.js +71 -0
  160. package/dist/commands/shared/git-diff.d.ts +3 -1
  161. package/dist/commands/shared/git-diff.d.ts.map +1 -1
  162. package/dist/commands/shared/git-diff.js +10 -2
  163. package/dist/commands/shared/git-ops.d.ts +1 -0
  164. package/dist/commands/shared/git-ops.d.ts.map +1 -1
  165. package/dist/commands/shared/git-ops.js +15 -0
  166. package/dist/commands/shared/git-worktree.d.ts +2 -0
  167. package/dist/commands/shared/git-worktree.d.ts.map +1 -1
  168. package/dist/commands/shared/git-worktree.js +22 -2
  169. package/dist/commands/shared/network-approval.d.ts +2 -0
  170. package/dist/commands/shared/network-approval.d.ts.map +1 -1
  171. package/dist/commands/shared/network-approval.js +1 -1
  172. package/dist/commands/shared/post-commit-pr-artifacts.d.ts +9 -0
  173. package/dist/commands/shared/post-commit-pr-artifacts.d.ts.map +1 -0
  174. package/dist/commands/shared/post-commit-pr-artifacts.js +22 -0
  175. package/dist/commands/shared/pr-meta.d.ts +29 -0
  176. package/dist/commands/shared/pr-meta.d.ts.map +1 -1
  177. package/dist/commands/shared/pr-meta.js +152 -3
  178. package/dist/commands/shared/task-backend.d.ts +9 -0
  179. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  180. package/dist/commands/shared/task-backend.js +34 -22
  181. package/dist/commands/shared/task-local-freshness.d.ts +13 -0
  182. package/dist/commands/shared/task-local-freshness.d.ts.map +1 -0
  183. package/dist/commands/shared/task-local-freshness.js +20 -0
  184. package/dist/commands/shared/task-mutation.d.ts +2 -0
  185. package/dist/commands/shared/task-mutation.d.ts.map +1 -1
  186. package/dist/commands/shared/task-mutation.js +7 -0
  187. package/dist/commands/task/block.d.ts.map +1 -1
  188. package/dist/commands/task/block.js +1 -0
  189. package/dist/commands/task/close-duplicate.d.ts.map +1 -1
  190. package/dist/commands/task/close-duplicate.js +34 -1
  191. package/dist/commands/task/close-shared.d.ts.map +1 -1
  192. package/dist/commands/task/close-shared.js +1 -0
  193. package/dist/commands/task/derive.js +1 -1
  194. package/dist/commands/task/doc-template.d.ts.map +1 -1
  195. package/dist/commands/task/doc-template.js +7 -11
  196. package/dist/commands/task/findings-add.command.d.ts +20 -0
  197. package/dist/commands/task/findings-add.command.d.ts.map +1 -0
  198. package/dist/commands/task/findings-add.command.js +165 -0
  199. package/dist/commands/task/findings.command.d.ts +7 -0
  200. package/dist/commands/task/findings.command.d.ts.map +1 -0
  201. package/dist/commands/task/findings.command.js +20 -0
  202. package/dist/commands/task/findings.d.ts +63 -0
  203. package/dist/commands/task/findings.d.ts.map +1 -0
  204. package/dist/commands/task/findings.js +188 -0
  205. package/dist/commands/task/finish-shared.d.ts +1 -0
  206. package/dist/commands/task/finish-shared.d.ts.map +1 -1
  207. package/dist/commands/task/finish-shared.js +60 -3
  208. package/dist/commands/task/finish.d.ts +10 -0
  209. package/dist/commands/task/finish.d.ts.map +1 -1
  210. package/dist/commands/task/finish.js +143 -0
  211. package/dist/commands/task/hosted-close-pr.command.d.ts +11 -0
  212. package/dist/commands/task/hosted-close-pr.command.d.ts.map +1 -0
  213. package/dist/commands/task/hosted-close-pr.command.js +414 -0
  214. package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
  215. package/dist/commands/task/hosted-close.command.js +49 -1
  216. package/dist/commands/task/hosted-merge-sync.d.ts +38 -0
  217. package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
  218. package/dist/commands/task/hosted-merge-sync.js +249 -17
  219. package/dist/commands/task/index.d.ts +1 -0
  220. package/dist/commands/task/index.d.ts.map +1 -1
  221. package/dist/commands/task/index.js +1 -0
  222. package/dist/commands/task/new.d.ts +1 -0
  223. package/dist/commands/task/new.d.ts.map +1 -1
  224. package/dist/commands/task/new.js +140 -30
  225. package/dist/commands/task/new.spec.d.ts.map +1 -1
  226. package/dist/commands/task/new.spec.js +7 -0
  227. package/dist/commands/task/normalize.command.d.ts +2 -0
  228. package/dist/commands/task/normalize.command.d.ts.map +1 -1
  229. package/dist/commands/task/normalize.command.js +45 -0
  230. package/dist/commands/task/normalize.d.ts +2 -0
  231. package/dist/commands/task/normalize.d.ts.map +1 -1
  232. package/dist/commands/task/normalize.js +85 -8
  233. package/dist/commands/task/plan.d.ts.map +1 -1
  234. package/dist/commands/task/plan.js +7 -10
  235. package/dist/commands/task/set-status.d.ts.map +1 -1
  236. package/dist/commands/task/set-status.js +1 -0
  237. package/dist/commands/task/shared/docs.d.ts +6 -0
  238. package/dist/commands/task/shared/docs.d.ts.map +1 -1
  239. package/dist/commands/task/shared/docs.js +14 -0
  240. package/dist/commands/task/shared/transition-command.d.ts +2 -0
  241. package/dist/commands/task/shared/transition-command.d.ts.map +1 -1
  242. package/dist/commands/task/shared/transition-command.js +1 -0
  243. package/dist/commands/task/shared/transitions.d.ts.map +1 -1
  244. package/dist/commands/task/shared/transitions.js +11 -1
  245. package/dist/commands/task/shared.d.ts +1 -1
  246. package/dist/commands/task/shared.d.ts.map +1 -1
  247. package/dist/commands/task/shared.js +1 -1
  248. package/dist/commands/task/start-ready.d.ts.map +1 -1
  249. package/dist/commands/task/start-ready.js +98 -1
  250. package/dist/commands/task/start.d.ts.map +1 -1
  251. package/dist/commands/task/start.js +18 -10
  252. package/dist/commands/task/task.command.d.ts.map +1 -1
  253. package/dist/commands/task/task.command.js +4 -0
  254. package/dist/commands/task/verify-command-shared.d.ts +19 -0
  255. package/dist/commands/task/verify-command-shared.d.ts.map +1 -1
  256. package/dist/commands/task/verify-command-shared.js +152 -1
  257. package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
  258. package/dist/commands/task/verify-ok.command.js +15 -2
  259. package/dist/commands/task/verify-record.d.ts +36 -0
  260. package/dist/commands/task/verify-record.d.ts.map +1 -1
  261. package/dist/commands/task/verify-record.js +193 -11
  262. package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
  263. package/dist/commands/task/verify-rework.command.js +15 -2
  264. package/dist/commands/task/verify-show.command.d.ts +1 -1
  265. package/dist/commands/task/verify-show.command.d.ts.map +1 -1
  266. package/dist/commands/task/verify-show.command.js +28 -1
  267. package/dist/commands/upgrade.d.ts.map +1 -1
  268. package/dist/commands/upgrade.js +6 -1
  269. package/dist/commands/verify.run.d.ts.map +1 -1
  270. package/dist/commands/verify.run.js +12 -0
  271. package/dist/commands/verify.spec.d.ts +2 -6
  272. package/dist/commands/verify.spec.d.ts.map +1 -1
  273. package/dist/commands/verify.spec.js +30 -3
  274. package/dist/policy/engine.d.ts +3 -1
  275. package/dist/policy/engine.d.ts.map +1 -1
  276. package/dist/policy/engine.js +5 -6
  277. package/dist/policy/taxonomy.d.ts +17 -0
  278. package/dist/policy/taxonomy.d.ts.map +1 -0
  279. package/dist/policy/taxonomy.js +302 -0
  280. package/dist/policy/types.d.ts +2 -1
  281. package/dist/policy/types.d.ts.map +1 -1
  282. package/dist/runner/artifacts.d.ts.map +1 -1
  283. package/dist/runner/artifacts.js +2 -0
  284. package/dist/runner/context/base-prompts.d.ts +25 -0
  285. package/dist/runner/context/base-prompts.d.ts.map +1 -1
  286. package/dist/runner/context/base-prompts.js +182 -54
  287. package/dist/runner/context/recipe-context.d.ts.map +1 -1
  288. package/dist/runner/context/recipe-context.js +5 -0
  289. package/dist/runner/types.d.ts +12 -0
  290. package/dist/runner/types.d.ts.map +1 -1
  291. package/dist/runner/usecases/scenario-materialize-task.d.ts.map +1 -1
  292. package/dist/runner/usecases/scenario-materialize-task.js +81 -11
  293. package/dist/runner/usecases/task-run-inspect.d.ts.map +1 -1
  294. package/dist/runner/usecases/task-run-inspect.js +9 -7
  295. package/dist/runner/usecases/task-run-lifecycle-shared.d.ts.map +1 -1
  296. package/dist/runner/usecases/task-run-lifecycle-shared.js +8 -6
  297. package/dist/runner/usecases/task-run.d.ts.map +1 -1
  298. package/dist/runner/usecases/task-run.js +59 -12
  299. package/dist/runtime/approvals/index.d.ts +3 -0
  300. package/dist/runtime/approvals/index.d.ts.map +1 -0
  301. package/dist/runtime/approvals/index.js +1 -0
  302. package/dist/runtime/approvals/runtime.d.ts +12 -0
  303. package/dist/runtime/approvals/runtime.d.ts.map +1 -0
  304. package/dist/runtime/approvals/runtime.js +154 -0
  305. package/dist/runtime/approvals/types.d.ts +31 -0
  306. package/dist/runtime/approvals/types.d.ts.map +1 -0
  307. package/dist/runtime/approvals/types.js +1 -0
  308. package/dist/runtime/behavior/index.d.ts +3 -0
  309. package/dist/runtime/behavior/index.d.ts.map +1 -0
  310. package/dist/runtime/behavior/index.js +1 -0
  311. package/dist/runtime/behavior/resolve.d.ts +7 -0
  312. package/dist/runtime/behavior/resolve.d.ts.map +1 -0
  313. package/dist/runtime/behavior/resolve.js +66 -0
  314. package/dist/runtime/behavior/types.d.ts +25 -0
  315. package/dist/runtime/behavior/types.d.ts.map +1 -0
  316. package/dist/runtime/behavior/types.js +1 -0
  317. package/dist/runtime/capabilities/backend.d.ts +7 -0
  318. package/dist/runtime/capabilities/backend.d.ts.map +1 -0
  319. package/dist/runtime/capabilities/backend.js +104 -0
  320. package/dist/runtime/capabilities/index.d.ts +6 -0
  321. package/dist/runtime/capabilities/index.d.ts.map +1 -0
  322. package/dist/runtime/capabilities/index.js +4 -0
  323. package/dist/runtime/capabilities/recipe.d.ts +10 -0
  324. package/dist/runtime/capabilities/recipe.d.ts.map +1 -0
  325. package/dist/runtime/capabilities/recipe.js +123 -0
  326. package/dist/runtime/capabilities/registry.d.ts +6 -0
  327. package/dist/runtime/capabilities/registry.d.ts.map +1 -0
  328. package/dist/runtime/capabilities/registry.js +69 -0
  329. package/dist/runtime/capabilities/runner.d.ts +8 -0
  330. package/dist/runtime/capabilities/runner.d.ts.map +1 -0
  331. package/dist/runtime/capabilities/runner.js +73 -0
  332. package/dist/runtime/capabilities/types.d.ts +28 -0
  333. package/dist/runtime/capabilities/types.d.ts.map +1 -0
  334. package/dist/runtime/capabilities/types.js +1 -0
  335. package/dist/runtime/execution-profile/index.d.ts +3 -0
  336. package/dist/runtime/execution-profile/index.d.ts.map +1 -0
  337. package/dist/runtime/execution-profile/index.js +1 -0
  338. package/dist/runtime/execution-profile/resolve.d.ts +9 -0
  339. package/dist/runtime/execution-profile/resolve.d.ts.map +1 -0
  340. package/dist/runtime/execution-profile/resolve.js +80 -0
  341. package/dist/runtime/execution-profile/types.d.ts +27 -0
  342. package/dist/runtime/execution-profile/types.d.ts.map +1 -0
  343. package/dist/runtime/execution-profile/types.js +1 -0
  344. package/dist/runtime/explain/index.d.ts +3 -0
  345. package/dist/runtime/explain/index.d.ts.map +1 -0
  346. package/dist/runtime/explain/index.js +1 -0
  347. package/dist/runtime/explain/resolve.d.ts +14 -0
  348. package/dist/runtime/explain/resolve.d.ts.map +1 -0
  349. package/dist/runtime/explain/resolve.js +50 -0
  350. package/dist/runtime/explain/types.d.ts +28 -0
  351. package/dist/runtime/explain/types.d.ts.map +1 -0
  352. package/dist/runtime/explain/types.js +1 -0
  353. package/dist/runtime/harness/index.d.ts +4 -0
  354. package/dist/runtime/harness/index.d.ts.map +1 -0
  355. package/dist/runtime/harness/index.js +2 -0
  356. package/dist/runtime/harness/resolve-from-command-context.d.ts +4 -0
  357. package/dist/runtime/harness/resolve-from-command-context.d.ts.map +1 -0
  358. package/dist/runtime/harness/resolve-from-command-context.js +11 -0
  359. package/dist/runtime/harness/resolve.d.ts +13 -0
  360. package/dist/runtime/harness/resolve.d.ts.map +1 -0
  361. package/dist/runtime/harness/resolve.js +146 -0
  362. package/dist/runtime/harness/types.d.ts +65 -0
  363. package/dist/runtime/harness/types.d.ts.map +1 -0
  364. package/dist/runtime/harness/types.js +1 -0
  365. package/dist/runtime/incidents/index.d.ts +3 -0
  366. package/dist/runtime/incidents/index.d.ts.map +1 -0
  367. package/dist/runtime/incidents/index.js +1 -0
  368. package/dist/runtime/incidents/resolve.d.ts +26 -0
  369. package/dist/runtime/incidents/resolve.d.ts.map +1 -0
  370. package/dist/runtime/incidents/resolve.js +683 -0
  371. package/dist/runtime/incidents/types.d.ts +84 -0
  372. package/dist/runtime/incidents/types.d.ts.map +1 -0
  373. package/dist/runtime/incidents/types.js +1 -0
  374. package/dist/runtime/protocol/index.d.ts +3 -0
  375. package/dist/runtime/protocol/index.d.ts.map +1 -0
  376. package/dist/runtime/protocol/index.js +2 -0
  377. package/dist/runtime/protocol/resolve.d.ts +16 -0
  378. package/dist/runtime/protocol/resolve.d.ts.map +1 -0
  379. package/dist/runtime/protocol/resolve.js +36 -0
  380. package/dist/runtime/protocol/types.d.ts +36 -0
  381. package/dist/runtime/protocol/types.d.ts.map +1 -0
  382. package/dist/runtime/protocol/types.js +1 -0
  383. package/dist/runtime/task-intake/index.d.ts +3 -0
  384. package/dist/runtime/task-intake/index.d.ts.map +1 -0
  385. package/dist/runtime/task-intake/index.js +1 -0
  386. package/dist/runtime/task-intake/resolve.d.ts +48 -0
  387. package/dist/runtime/task-intake/resolve.d.ts.map +1 -0
  388. package/dist/runtime/task-intake/resolve.js +316 -0
  389. package/dist/runtime/task-intake/types.d.ts +117 -0
  390. package/dist/runtime/task-intake/types.d.ts.map +1 -0
  391. package/dist/runtime/task-intake/types.js +1 -0
  392. package/dist/shared/env.d.ts +1 -0
  393. package/dist/shared/env.d.ts.map +1 -1
  394. package/dist/shared/env.js +22 -1
  395. package/dist/shared/protected-paths.d.ts +4 -0
  396. package/dist/shared/protected-paths.d.ts.map +1 -1
  397. package/dist/shared/protected-paths.js +8 -4
  398. package/dist/usecases/context/resolve-context.d.ts +55 -6
  399. package/dist/usecases/context/resolve-context.d.ts.map +1 -1
  400. package/dist/usecases/context/resolve-context.js +96 -6
  401. package/dist/usecases/task/task-list-usecase.d.ts.map +1 -1
  402. package/dist/usecases/task/task-list-usecase.js +8 -2
  403. package/dist/usecases/task/task-new-usecase.js +4 -4
  404. package/package.json +2 -2
@@ -0,0 +1,683 @@
1
+ const STRUCTURED_INCIDENTS_HEADER = [
2
+ "# Policy Incidents Log",
3
+ "",
4
+ "This is the single file for incident-derived and situational policy rules.",
5
+ ].join("\n");
6
+ const COMPACT_INCIDENTS_HEADER = [
7
+ "# Policy Incidents Log",
8
+ "- Append-only. Required fields: `id`, `date`, `scope`, `failure`, `rule`, `evidence`, `enforcement`, `state`; optional: `tags`, `match`, `advice`, `source_task`, `fixability`.",
9
+ ].join("\n");
10
+ function normalizeLines(text) {
11
+ return text.replaceAll("\r\n", "\n").split("\n");
12
+ }
13
+ function normalizeKey(key) {
14
+ return key
15
+ .trim()
16
+ .toLowerCase()
17
+ .replaceAll(/[\s_-]+/g, "");
18
+ }
19
+ function normalizeSearchText(text) {
20
+ return text
21
+ .toLowerCase()
22
+ .replaceAll(/[^a-z0-9]+/gi, " ")
23
+ .trim();
24
+ }
25
+ function tokenize(text) {
26
+ const normalized = normalizeSearchText(text);
27
+ if (!normalized)
28
+ return [];
29
+ return normalized
30
+ .split(/\s+/)
31
+ .map((token) => token.trim())
32
+ .filter((token) => token.length >= 3);
33
+ }
34
+ function dedupeCaseInsensitive(values) {
35
+ const seen = new Set();
36
+ const out = [];
37
+ for (const value of values) {
38
+ const trimmed = String(value ?? "").trim();
39
+ if (!trimmed)
40
+ continue;
41
+ const key = trimmed.toLowerCase();
42
+ if (seen.has(key))
43
+ continue;
44
+ seen.add(key);
45
+ out.push(trimmed);
46
+ }
47
+ return out;
48
+ }
49
+ function parseCsvList(value) {
50
+ if (!value)
51
+ return [];
52
+ return dedupeCaseInsensitive(value
53
+ .split(",")
54
+ .map((item) => item.trim())
55
+ .filter(Boolean));
56
+ }
57
+ function incidentField(key, value) {
58
+ return [key, value];
59
+ }
60
+ function parseBoolean(value) {
61
+ const normalized = String(value ?? "")
62
+ .trim()
63
+ .toLowerCase();
64
+ return normalized === "true" || normalized === "yes" || normalized === "y" || normalized === "1";
65
+ }
66
+ function parseFixability(value) {
67
+ const normalized = String(value ?? "")
68
+ .trim()
69
+ .toLowerCase()
70
+ .replaceAll(/[\s_-]+/g, "");
71
+ if (normalized === "external")
72
+ return "external";
73
+ if (normalized === "repofixable" || normalized === "internal")
74
+ return "repo-fixable";
75
+ return null;
76
+ }
77
+ function parseEntryState(value) {
78
+ return value === "open" || value === "promoted" ? value : "stabilized";
79
+ }
80
+ function appendFieldValue(record, key, value, joiner = " ") {
81
+ if (!record[key]) {
82
+ record[key] = value.trim();
83
+ return;
84
+ }
85
+ record[key] = `${record[key]}${joiner}${value.trim()}`.trim();
86
+ }
87
+ function deriveSourceTask(explicitSourceTask, evidence) {
88
+ const direct = String(explicitSourceTask ?? "").trim();
89
+ if (direct)
90
+ return direct;
91
+ const match = /\btasks?\s+([A-Za-z0-9-]+)/iu.exec(String(evidence ?? ""));
92
+ return match?.[1]?.trim() ?? null;
93
+ }
94
+ function buildIncidentSignature(entry) {
95
+ return [
96
+ normalizeSearchText(entry.scope),
97
+ normalizeSearchText(entry.failure),
98
+ normalizeSearchText(entry.rule),
99
+ ].join("|");
100
+ }
101
+ function buildIncidentFingerprint(entry) {
102
+ return [entry.sourceTask ?? "", buildIncidentSignature(entry)].join("|");
103
+ }
104
+ function buildMatchTerms(opts) {
105
+ const scopeTokens = tokenize(opts.scope);
106
+ const extraTokens = (opts.extraText ?? []).flatMap((value) => tokenize(value));
107
+ return dedupeCaseInsensitive([
108
+ ...opts.explicitMatch,
109
+ ...opts.tags,
110
+ ...scopeTokens,
111
+ ...extraTokens,
112
+ ]).slice(0, 16);
113
+ }
114
+ function parseDateOnly(value) {
115
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
116
+ return null;
117
+ const parsed = Date.parse(`${value}T00:00:00.000Z`);
118
+ return Number.isFinite(parsed) ? parsed : null;
119
+ }
120
+ function occursWithinDays(date, now, days) {
121
+ const timestamp = parseDateOnly(date);
122
+ if (timestamp === null)
123
+ return false;
124
+ const delta = now.getTime() - timestamp;
125
+ if (delta < 0)
126
+ return false;
127
+ return delta <= days * 24 * 60 * 60 * 1000;
128
+ }
129
+ function entryStateRank(state) {
130
+ if (state === "promoted")
131
+ return 2;
132
+ if (state === "stabilized")
133
+ return 1;
134
+ return 0;
135
+ }
136
+ function compareIncidentAdviceMatch(left, right) {
137
+ if (right.score !== left.score)
138
+ return right.score - left.score;
139
+ const rightState = entryStateRank(right.entry.state);
140
+ const leftState = entryStateRank(left.entry.state);
141
+ if (rightState !== leftState)
142
+ return rightState - leftState;
143
+ return right.entry.date.localeCompare(left.entry.date);
144
+ }
145
+ function summarizeTaskScope(scope, title) {
146
+ const lines = normalizeLines(scope ?? "");
147
+ for (const line of lines) {
148
+ const trimmed = line.trim();
149
+ if (!trimmed)
150
+ continue;
151
+ let candidate = trimmed.replace(/^-+\s*/, "");
152
+ candidate = candidate.replace(/^in scope:\s*/i, "").trim();
153
+ if (!candidate || /^out of scope:/i.test(candidate))
154
+ continue;
155
+ return candidate;
156
+ }
157
+ return title.trim();
158
+ }
159
+ function buildDerivedIncidentRule(scope) {
160
+ return `Analogous ${scope} work MUST review and apply the recorded external incident advice before retrying.`;
161
+ }
162
+ function resolveIncidentState(opts) {
163
+ const signature = buildIncidentSignature(opts.entry);
164
+ const similarEntries = opts.registry.entries.filter((candidate) => buildIncidentSignature(candidate) === signature);
165
+ if (similarEntries.some((candidate) => candidate.state === "promoted" ||
166
+ candidate.state === "stabilized" ||
167
+ occursWithinDays(candidate.date, opts.now, 30))) {
168
+ return "stabilized";
169
+ }
170
+ return "open";
171
+ }
172
+ export function createIncidentRegistrySkeleton() {
173
+ return [
174
+ STRUCTURED_INCIDENTS_HEADER,
175
+ "",
176
+ "## Entry contract",
177
+ "",
178
+ "- Add entries append-only.",
179
+ "- Every entry MUST include: `id`, `date`, `scope`, `failure`, `rule`, `evidence`, `enforcement`, `state`.",
180
+ "- New machine-matched entries SHOULD also include: `tags`, `match`, `advice`, `source_task`, `fixability`.",
181
+ "- `rule` MUST be concrete and testable (`MUST` / `MUST NOT`).",
182
+ "- `fixability: external` means the issue cannot be removed by changing only repository code and should stay as reusable operational advice.",
183
+ "- `fixability: repo-fixable` means the issue can be removed by repository code changes and should still be captured as reusable incident advice when explicitly marked.",
184
+ "- First auto-promoted reusable incidents normally enter as `open` and still participate in targeted advice lookup; recurring equivalent incidents can append later `stabilized` entries.",
185
+ "- `state` values: `open`, `stabilized`, `promoted`.",
186
+ "",
187
+ "## Entry template",
188
+ "",
189
+ "- id: `INC-YYYYMMDD-NN`",
190
+ "- date: `YYYY-MM-DD`",
191
+ "- scope: `<affected scope>`",
192
+ "- tags: `<comma-separated matching tags>`",
193
+ "- match: `<comma-separated lookup keywords>`",
194
+ "- failure: `<observed failure mode>`",
195
+ "- advice: `<reusable recovery or prevention guidance>`",
196
+ "- rule: `<new or refined MUST/MUST NOT>`",
197
+ "- evidence: `<task ids / logs / links>`",
198
+ "- enforcement: `<CI|test|lint|script|manual>`",
199
+ "- source_task: `<task id>`",
200
+ "- fixability: `<external|repo-fixable>`",
201
+ "- state: `<open|stabilized|promoted>`",
202
+ "",
203
+ "## Entries",
204
+ "",
205
+ ].join("\n");
206
+ }
207
+ export function parseIncidentRegistry(text) {
208
+ const lines = normalizeLines(text);
209
+ const entries = [];
210
+ let currentFields = null;
211
+ let currentLine = 0;
212
+ let currentKey = null;
213
+ const flush = () => {
214
+ if (!currentFields)
215
+ return;
216
+ const id = currentFields.id?.trim();
217
+ if (!id || !/^INC-\d{8}-\d+$/u.test(id)) {
218
+ currentFields = null;
219
+ currentKey = null;
220
+ currentLine = 0;
221
+ return;
222
+ }
223
+ const scope = currentFields.scope?.trim() ?? "";
224
+ const failure = currentFields.failure?.trim() ?? "";
225
+ const rule = currentFields.rule?.trim() ?? "";
226
+ const evidence = currentFields.evidence?.trim() ?? "";
227
+ const enforcement = currentFields.enforcement?.trim() ?? "manual";
228
+ const sourceTask = deriveSourceTask(currentFields.source_task, evidence);
229
+ entries.push({
230
+ id,
231
+ date: currentFields.date?.trim() ?? "",
232
+ scope,
233
+ failure,
234
+ rule,
235
+ evidence,
236
+ enforcement,
237
+ state: parseEntryState(currentFields.state),
238
+ tags: parseCsvList(currentFields.tags),
239
+ match: parseCsvList(currentFields.match),
240
+ advice: currentFields.advice?.trim() || null,
241
+ sourceTask,
242
+ fixability: parseFixability(currentFields.fixability),
243
+ rawFields: { ...currentFields },
244
+ line: currentLine,
245
+ });
246
+ currentFields = null;
247
+ currentKey = null;
248
+ currentLine = 0;
249
+ };
250
+ for (const [index, line] of lines.entries()) {
251
+ const trimmed = line.trim();
252
+ const inlineFields = parseInlineIncidentEntry(trimmed);
253
+ if (inlineFields) {
254
+ flush();
255
+ currentFields = { ...inlineFields };
256
+ const keys = Object.keys(inlineFields);
257
+ currentKey = keys.at(-1) ?? "id";
258
+ currentLine = index + 1;
259
+ continue;
260
+ }
261
+ if (!currentFields)
262
+ continue;
263
+ if (/^##\s+/.test(trimmed)) {
264
+ flush();
265
+ continue;
266
+ }
267
+ const fieldMatch = /^\s{2}([a-z_]+):\s*(.*?)\s*$/.exec(line);
268
+ if (fieldMatch) {
269
+ currentKey = String(fieldMatch[1] ?? "").trim();
270
+ currentFields[currentKey] = fieldMatch[2] ?? "";
271
+ continue;
272
+ }
273
+ if (currentKey && /^\s{4,}\S/.test(line)) {
274
+ appendFieldValue(currentFields, currentKey, line.trim(), "\n");
275
+ continue;
276
+ }
277
+ if (!trimmed) {
278
+ flush();
279
+ }
280
+ }
281
+ flush();
282
+ return { entries };
283
+ }
284
+ export function formatIncidentRegistryEntry(entry) {
285
+ return formatIncidentRegistryEntryForStyle(entry, "structured");
286
+ }
287
+ function parseInlineIncidentEntry(trimmedLine) {
288
+ if (!trimmedLine.startsWith("- "))
289
+ return null;
290
+ const body = trimmedLine.slice(2).trim();
291
+ if (!body)
292
+ return null;
293
+ const segments = body.split(/\s+\|\s+(?=[a-z_]+:\s*)/u);
294
+ const fields = {};
295
+ for (const segment of segments) {
296
+ const match = /^([a-z_]+):\s*(.*?)\s*$/.exec(segment.trim());
297
+ if (!match)
298
+ return null;
299
+ const key = String(match[1] ?? "").trim();
300
+ if (!key)
301
+ return null;
302
+ fields[key] = match[2] ?? "";
303
+ }
304
+ return fields.id ? fields : null;
305
+ }
306
+ function formatIncidentRegistryEntryForStyle(entry, style) {
307
+ const compactFields = [
308
+ incidentField("id", entry.id),
309
+ incidentField("date", entry.date),
310
+ incidentField("scope", entry.scope),
311
+ ...(entry.tags.length > 0 ? [incidentField("tags", entry.tags.join(", "))] : []),
312
+ ...(entry.match.length > 0 ? [incidentField("match", entry.match.join(", "))] : []),
313
+ incidentField("failure", entry.failure),
314
+ ...(entry.advice ? [incidentField("advice", entry.advice)] : []),
315
+ incidentField("rule", entry.rule),
316
+ incidentField("evidence", entry.evidence),
317
+ incidentField("enforcement", entry.enforcement),
318
+ ...(entry.fixability ? [incidentField("fixability", entry.fixability)] : []),
319
+ incidentField("state", entry.state),
320
+ ];
321
+ if (style === "compact") {
322
+ return `- ${compactFields.map(([key, value]) => `${key}: ${value}`).join(" | ")}`;
323
+ }
324
+ const structuredFields = [
325
+ incidentField("id", entry.id),
326
+ incidentField("date", entry.date),
327
+ incidentField("scope", entry.scope),
328
+ ...(entry.tags.length > 0 ? [incidentField("tags", entry.tags.join(", "))] : []),
329
+ ...(entry.match.length > 0 ? [incidentField("match", entry.match.join(", "))] : []),
330
+ incidentField("failure", entry.failure),
331
+ ...(entry.advice ? [incidentField("advice", entry.advice)] : []),
332
+ incidentField("rule", entry.rule),
333
+ incidentField("evidence", entry.evidence),
334
+ incidentField("enforcement", entry.enforcement),
335
+ ...(entry.sourceTask ? [incidentField("source_task", entry.sourceTask)] : []),
336
+ ...(entry.fixability ? [incidentField("fixability", entry.fixability)] : []),
337
+ incidentField("state", entry.state),
338
+ ];
339
+ return [
340
+ `- ${structuredFields[0]?.[0]}: ${structuredFields[0]?.[1] ?? ""}`,
341
+ ...structuredFields.slice(1).map(([key, value]) => ` ${key}: ${value}`),
342
+ ].join("\n");
343
+ }
344
+ function detectRegistryStyle(text) {
345
+ return /(^|\n)## Entries\s*$/mu.test(text) || /(^|\n)## Entry contract\s*$/mu.test(text)
346
+ ? "structured"
347
+ : "compact";
348
+ }
349
+ function entryRichness(entry) {
350
+ return [
351
+ entry.sourceTask ? 4 : 0,
352
+ entry.advice ? 3 : 0,
353
+ entry.tags.length,
354
+ entry.match.length,
355
+ entry.fixability ? 1 : 0,
356
+ entry.evidence.length > 0 ? 1 : 0,
357
+ ].reduce((sum, item) => sum + item, 0);
358
+ }
359
+ function nextIncidentIdForDate(dateStamp, usedIds, nextByDate) {
360
+ let next = nextByDate.get(dateStamp) ?? 0;
361
+ do {
362
+ next += 1;
363
+ } while (usedIds.has(`INC-${dateStamp}-${String(next).padStart(2, "0")}`));
364
+ nextByDate.set(dateStamp, next);
365
+ return `INC-${dateStamp}-${String(next).padStart(2, "0")}`;
366
+ }
367
+ function normalizeIncidentRegistryEntries(entries) {
368
+ const byFingerprint = new Map();
369
+ const orderedFingerprints = [];
370
+ for (const entry of entries) {
371
+ const fingerprint = buildIncidentFingerprint(entry);
372
+ const existing = byFingerprint.get(fingerprint);
373
+ if (!existing) {
374
+ byFingerprint.set(fingerprint, { ...entry });
375
+ orderedFingerprints.push(fingerprint);
376
+ continue;
377
+ }
378
+ if (entryRichness(entry) >= entryRichness(existing)) {
379
+ byFingerprint.set(fingerprint, { ...entry });
380
+ }
381
+ }
382
+ const normalized = orderedFingerprints.map((fingerprint) => byFingerprint.get(fingerprint));
383
+ const usedIds = new Set();
384
+ const nextByDate = new Map();
385
+ for (const entry of normalized) {
386
+ const match = /^INC-(\d{8})-(\d+)$/u.exec(entry.id);
387
+ if (!match)
388
+ continue;
389
+ const [, dateStamp, seqRaw] = match;
390
+ const seq = Number.parseInt(seqRaw ?? "", 10);
391
+ if (!Number.isInteger(seq))
392
+ continue;
393
+ const existing = nextByDate.get(dateStamp) ?? 0;
394
+ if (seq > existing)
395
+ nextByDate.set(dateStamp, seq);
396
+ }
397
+ return normalized.map((entry) => {
398
+ const dateStamp = /^\d{4}-\d{2}-\d{2}$/u.test(entry.date)
399
+ ? entry.date.replaceAll("-", "")
400
+ : "00000000";
401
+ const nextId = usedIds.has(entry.id)
402
+ ? nextIncidentIdForDate(dateStamp, usedIds, nextByDate)
403
+ : entry.id;
404
+ usedIds.add(nextId);
405
+ return nextId === entry.id ? entry : { ...entry, id: nextId };
406
+ });
407
+ }
408
+ function renderIncidentRegistryDocument(entries, style) {
409
+ const header = style === "structured" ? createIncidentRegistrySkeleton().trimEnd() : COMPACT_INCIDENTS_HEADER;
410
+ if (entries.length === 0)
411
+ return `${header}\n`;
412
+ const separator = style === "structured" ? "\n\n" : "\n";
413
+ return `${header}\n${entries.map((entry) => formatIncidentRegistryEntryForStyle(entry, style)).join(separator)}\n`;
414
+ }
415
+ export function appendIncidentRegistryEntries(currentText, entries) {
416
+ if (entries.length === 0)
417
+ return currentText;
418
+ const baseText = currentText.trim().length > 0 ? currentText : createIncidentRegistrySkeleton();
419
+ const style = detectRegistryStyle(baseText);
420
+ const existing = parseIncidentRegistry(baseText);
421
+ const merged = normalizeIncidentRegistryEntries([...existing.entries, ...entries]);
422
+ return renderIncidentRegistryDocument(merged, style);
423
+ }
424
+ export function extractIncidentCandidatesFromFindings(findings) {
425
+ return parseIncidentFindingBlocks(findings)
426
+ .filter((candidate) => candidate.shouldPromote)
427
+ .map(({ shouldPromote: _shouldPromote, ...candidate }) => candidate);
428
+ }
429
+ function parseIncidentFindingBlocks(findings) {
430
+ const lines = normalizeLines(findings);
431
+ const candidates = [];
432
+ let currentFields = null;
433
+ let currentLine = 0;
434
+ let currentKey = null;
435
+ const flush = () => {
436
+ if (!currentFields)
437
+ return;
438
+ const promotion = currentFields.promotion?.trim() || null;
439
+ const fixability = parseFixability(currentFields.fixability);
440
+ const incidentExternal = parseBoolean(currentFields.incidentexternal) || fixability === "external";
441
+ const incidentInternal = parseBoolean(currentFields.incidentinternal) || fixability === "repo-fixable";
442
+ const shouldPromote = promotion?.toLowerCase() === "incident-candidate" || incidentExternal || incidentInternal;
443
+ const observation = currentFields.observation?.trim() ?? "";
444
+ if (!observation) {
445
+ currentFields = null;
446
+ currentKey = null;
447
+ currentLine = 0;
448
+ return;
449
+ }
450
+ candidates.push({
451
+ observation,
452
+ impact: currentFields.impact?.trim() || null,
453
+ resolution: currentFields.resolution?.trim() || null,
454
+ promotion,
455
+ incidentScope: currentFields.incidentscope?.trim() || null,
456
+ incidentRule: currentFields.incidentrule?.trim() || null,
457
+ incidentAdvice: currentFields.incidentadvice?.trim() || null,
458
+ incidentTags: parseCsvList(currentFields.incidenttags),
459
+ incidentMatch: parseCsvList(currentFields.incidentmatch),
460
+ incidentExternal,
461
+ incidentInternal,
462
+ fixability,
463
+ shouldPromote,
464
+ line: currentLine,
465
+ rawFields: { ...currentFields },
466
+ });
467
+ currentFields = null;
468
+ currentKey = null;
469
+ currentLine = 0;
470
+ };
471
+ for (const [index, line] of lines.entries()) {
472
+ const observationMatch = /^\s*-\s+Observation:\s*(.*?)\s*$/.exec(line);
473
+ if (observationMatch) {
474
+ flush();
475
+ currentFields = { observation: observationMatch[1] ?? "" };
476
+ currentKey = "observation";
477
+ currentLine = index + 1;
478
+ continue;
479
+ }
480
+ if (!currentFields)
481
+ continue;
482
+ if (/^\s*-\s+/.test(line)) {
483
+ flush();
484
+ const nestedObservationMatch = /^\s*-\s+Observation:\s*(.*?)\s*$/.exec(line);
485
+ if (nestedObservationMatch) {
486
+ currentFields = { observation: nestedObservationMatch[1] ?? "" };
487
+ currentKey = "observation";
488
+ currentLine = index + 1;
489
+ }
490
+ continue;
491
+ }
492
+ const fieldMatch = /^\s{2,}([A-Za-z][A-Za-z0-9 _-]*):\s*(.*?)\s*$/.exec(line);
493
+ if (fieldMatch) {
494
+ currentKey = normalizeKey(fieldMatch[1] ?? "");
495
+ currentFields[currentKey] = fieldMatch[2] ?? "";
496
+ continue;
497
+ }
498
+ if (currentKey && /^\s{2,}\S/.test(line)) {
499
+ appendFieldValue(currentFields, currentKey, line.trim(), "\n");
500
+ continue;
501
+ }
502
+ if (!line.trim()) {
503
+ continue;
504
+ }
505
+ if (currentKey) {
506
+ appendFieldValue(currentFields, currentKey, line.trim());
507
+ }
508
+ }
509
+ flush();
510
+ return candidates;
511
+ }
512
+ function nextIncidentId(entries, now) {
513
+ const dateStamp = `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}`;
514
+ const prefix = `INC-${dateStamp}-`;
515
+ let max = 0;
516
+ for (const entry of entries) {
517
+ if (!entry.id.startsWith(prefix))
518
+ continue;
519
+ const num = Number.parseInt(entry.id.slice(prefix.length), 10);
520
+ if (Number.isInteger(num) && num > max)
521
+ max = num;
522
+ }
523
+ return `${prefix}${String(max + 1).padStart(2, "0")}`;
524
+ }
525
+ function buildPromotionIssues(candidate) {
526
+ const missingFields = [];
527
+ if (!candidate.incidentExternal && !candidate.incidentInternal && candidate.fixability === null) {
528
+ missingFields.push("Fixability: external or IncidentExternal: true");
529
+ }
530
+ if (!candidate.incidentAdvice && !candidate.resolution) {
531
+ missingFields.push("Resolution or IncidentAdvice");
532
+ }
533
+ return missingFields.length > 0 ? { candidate, missingFields } : null;
534
+ }
535
+ function buildIncidentRegistryEntry(opts) {
536
+ const date = opts.now.toISOString().slice(0, 10);
537
+ const scope = opts.candidate.incidentScope ?? summarizeTaskScope(opts.task.scope, opts.task.title);
538
+ const tags = dedupeCaseInsensitive([
539
+ ...opts.candidate.incidentTags,
540
+ ...opts.task.tags.map((tag) => tag.trim()),
541
+ ]);
542
+ const advice = opts.candidate.incidentAdvice ?? opts.candidate.resolution ?? opts.candidate.observation;
543
+ const rule = opts.candidate.incidentRule ?? buildDerivedIncidentRule(scope);
544
+ const state = resolveIncidentState({
545
+ registry: opts.registry,
546
+ entry: {
547
+ scope,
548
+ failure: opts.candidate.observation,
549
+ rule,
550
+ },
551
+ now: opts.now,
552
+ });
553
+ const match = buildMatchTerms({
554
+ scope,
555
+ tags,
556
+ explicitMatch: opts.candidate.incidentMatch,
557
+ extraText: [opts.task.title, opts.task.description, advice],
558
+ });
559
+ return {
560
+ id: nextIncidentId(opts.registry.entries, opts.now),
561
+ date,
562
+ scope,
563
+ failure: opts.candidate.observation,
564
+ rule,
565
+ evidence: `task ${opts.task.id}${opts.task.commitHash ? `; commit ${opts.task.commitHash.slice(0, 12)}` : ""}`,
566
+ enforcement: "manual",
567
+ state,
568
+ tags,
569
+ match,
570
+ advice,
571
+ sourceTask: opts.task.id,
572
+ fixability: opts.candidate.fixability ?? (opts.candidate.incidentInternal ? "repo-fixable" : "external"),
573
+ rawFields: {},
574
+ line: 0,
575
+ };
576
+ }
577
+ export function planIncidentCollection(opts) {
578
+ const parsed = parseIncidentFindingBlocks(opts.findings);
579
+ const candidates = parsed
580
+ .filter((candidate) => candidate.shouldPromote)
581
+ .map(({ shouldPromote: _shouldPromote, ...candidate }) => candidate);
582
+ const skipped = parsed
583
+ .filter((candidate) => !candidate.shouldPromote)
584
+ .map(({ observation, line, rawFields }) => ({
585
+ observation,
586
+ line,
587
+ reason: "not_marked_external_or_promotable",
588
+ rawFields,
589
+ }));
590
+ const issues = [];
591
+ const promotable = [];
592
+ const duplicates = [];
593
+ const now = opts.now ?? new Date();
594
+ const seenFingerprints = new Set(opts.registry.entries.map((entry) => buildIncidentFingerprint(entry)));
595
+ for (const candidate of candidates) {
596
+ const issue = buildPromotionIssues(candidate);
597
+ if (issue) {
598
+ issues.push(issue);
599
+ continue;
600
+ }
601
+ const entry = buildIncidentRegistryEntry({
602
+ task: opts.task,
603
+ candidate,
604
+ now,
605
+ registry: parseIncidentRegistry(appendIncidentRegistryEntries(createIncidentRegistrySkeleton(), [
606
+ ...opts.registry.entries,
607
+ ...promotable.map((item) => item.entry),
608
+ ])),
609
+ });
610
+ const fingerprint = buildIncidentFingerprint(entry);
611
+ const draft = { candidate, entry, fingerprint };
612
+ if (seenFingerprints.has(fingerprint)) {
613
+ duplicates.push(draft);
614
+ continue;
615
+ }
616
+ seenFingerprints.add(fingerprint);
617
+ promotable.push(draft);
618
+ }
619
+ return {
620
+ candidates,
621
+ skipped,
622
+ promotable,
623
+ duplicates,
624
+ issues,
625
+ findingsTextPresent: opts.findings.trim().length > 0,
626
+ structuredFindingCount: parsed.length,
627
+ };
628
+ }
629
+ export function buildIncidentAdviceQueryFromTask(opts) {
630
+ return {
631
+ taskId: opts.taskId,
632
+ title: opts.title,
633
+ description: opts.description,
634
+ scope: opts.scope ?? null,
635
+ tags: dedupeCaseInsensitive(opts.tags),
636
+ };
637
+ }
638
+ export function resolveIncidentAdviceMatches(opts) {
639
+ const limit = Math.max(1, opts.limit ?? 5);
640
+ const tagSet = new Set(opts.query.tags.map((tag) => tag.trim().toLowerCase()).filter(Boolean));
641
+ const haystack = [opts.query.title, opts.query.description, opts.query.scope ?? ""].join(" ");
642
+ const normalizedHaystack = normalizeSearchText(haystack);
643
+ const queryTokens = new Set([...tokenize(haystack), ...tagSet]);
644
+ const matchesBySignature = new Map();
645
+ for (const entry of opts.registry.entries) {
646
+ const matchedTags = entry.tags.filter((tag) => tagSet.has(tag.trim().toLowerCase()));
647
+ const matchedTerms = entry.match.filter((term) => queryTokens.has(term.trim().toLowerCase()) ||
648
+ normalizedHaystack.includes(normalizeSearchText(term)));
649
+ const normalizedScope = normalizeSearchText(entry.scope);
650
+ const scopeMatched = normalizedScope.length > 0 && normalizedHaystack.includes(normalizedScope);
651
+ const score = matchedTags.length * 5 + matchedTerms.length * 2 + (scopeMatched ? 3 : 0);
652
+ if (score <= 0)
653
+ continue;
654
+ const match = { entry, score, matchedTags, matchedTerms, scopeMatched };
655
+ const signature = buildIncidentSignature(entry);
656
+ const existing = matchesBySignature.get(signature);
657
+ if (!existing || compareIncidentAdviceMatch(match, existing) < 0) {
658
+ matchesBySignature.set(signature, match);
659
+ }
660
+ }
661
+ const matches = [...matchesBySignature.values()];
662
+ matches.sort((left, right) => {
663
+ return compareIncidentAdviceMatch(left, right);
664
+ });
665
+ return matches.slice(0, limit);
666
+ }
667
+ export function renderIncidentAdvice(matches) {
668
+ if (matches.length === 0)
669
+ return "No matching incident advice.";
670
+ return matches
671
+ .map((match) => {
672
+ const lines = [
673
+ `- ${match.entry.id} | scope: ${match.entry.scope}`,
674
+ ` failure: ${match.entry.failure}`,
675
+ ` advice: ${match.entry.advice ?? match.entry.rule}`,
676
+ ` rule: ${match.entry.rule}`,
677
+ ];
678
+ if (match.entry.evidence)
679
+ lines.push(` evidence: ${match.entry.evidence}`);
680
+ return lines.join("\n");
681
+ })
682
+ .join("\n");
683
+ }