dsh-pstack 0.2.0-beta.1 → 0.2.0-beta.3

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 (261) hide show
  1. package/LICENSE +2 -3
  2. package/README.md +135 -84
  3. package/README.zh.md +185 -0
  4. package/cordis.patch.yml +97 -27
  5. package/dist/host-contract-CUPSpeNk.d.mts +22 -0
  6. package/dist/index.d.mts +49 -238
  7. package/dist/index.mjs +250 -123
  8. package/dist/models.d.mts +44 -0
  9. package/dist/models.mjs +201 -0
  10. package/dist/paths-BT77khwm.mjs +48 -0
  11. package/dist/pstack/LICENSE +21 -0
  12. package/dist/pstack/README.md +291 -0
  13. package/dist/pstack/agents/poteto-agent.md +9 -0
  14. package/{assets → dist/pstack}/docs/guide/01-setup.md +13 -11
  15. package/{assets → dist/pstack}/docs/guide/02-poteto-mode.md +4 -4
  16. package/{assets → dist/pstack}/docs/guide/04-design.md +4 -4
  17. package/{assets → dist/pstack}/docs/guide/05-build-and-clean.md +2 -2
  18. package/{assets → dist/pstack}/docs/guide/06-verify-and-ship.md +13 -3
  19. package/{assets → dist/pstack}/docs/guide/07-overnight.md +15 -13
  20. package/{assets → dist/pstack}/docs/guide/09-make-it-yours.md +6 -2
  21. package/{assets → dist/pstack}/docs/guide/10-recipes-and-pitfalls.md +7 -5
  22. package/{assets → dist/pstack}/docs/guide/README.md +1 -1
  23. package/dist/pstack/docs/harness/dsh.md +98 -0
  24. package/{assets → dist/pstack}/skills/architect/SKILL.md +12 -12
  25. package/dist/pstack/skills/arena/SKILL.md +50 -0
  26. package/{assets → dist/pstack}/skills/automate-me/SKILL.md +14 -14
  27. package/{assets → dist/pstack}/skills/benchmark-checklist/SKILL.md +1 -1
  28. package/{assets → dist/pstack}/skills/blast-radius/SKILL.md +4 -6
  29. package/{assets → dist/pstack}/skills/correct/SKILL.md +1 -1
  30. package/{assets → dist/pstack}/skills/create-formal-verification-skill/SKILL.md +4 -2
  31. package/{assets → dist/pstack}/skills/create-verification-skill/SKILL.md +5 -5
  32. package/dist/pstack/skills/figure-it-out/SKILL.md +54 -0
  33. package/dist/pstack/skills/how/SKILL.md +38 -0
  34. package/{assets → dist/pstack}/skills/in-your-own-words/SKILL.md +1 -1
  35. package/dist/pstack/skills/interrogate/SKILL.md +33 -0
  36. package/{assets → dist/pstack}/skills/ketchup/SKILL.md +3 -5
  37. package/dist/pstack/skills/ketchup-video/SKILL.md +29 -0
  38. package/{assets → dist/pstack}/skills/maintain-formal-verification-skill/SKILL.md +1 -1
  39. package/{assets → dist/pstack}/skills/maintain-verification-skill/SKILL.md +3 -3
  40. package/dist/pstack/skills/make-bot-ui/SKILL.md +117 -0
  41. package/dist/pstack/skills/no-comments/SKILL.md +26 -0
  42. package/{assets → dist/pstack}/skills/poteto-help/SKILL.md +34 -31
  43. package/{assets → dist/pstack}/skills/poteto-help/references/prompting.md +1 -1
  44. package/{assets → dist/pstack}/skills/poteto-help/references/recipes.md +3 -3
  45. package/{assets → dist/pstack}/skills/poteto-mode/SKILL.md +20 -19
  46. package/dist/pstack/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  47. package/dist/pstack/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  48. package/dist/pstack/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
  49. package/dist/pstack/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
  50. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/babysit.md +4 -4
  51. package/dist/pstack/skills/poteto-mode/playbooks/bug-fix.md +15 -0
  52. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/eval.md +3 -3
  53. package/dist/pstack/skills/poteto-mode/playbooks/feature.md +21 -0
  54. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/hillclimb.md +3 -3
  55. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/investigation.md +2 -2
  56. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/multi-phase-plan.md +23 -23
  57. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/opening-a-pr.md +6 -6
  58. package/dist/pstack/skills/poteto-mode/playbooks/orchestrate.md +25 -0
  59. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/pause-safely.md +2 -2
  60. package/dist/pstack/skills/poteto-mode/playbooks/perf-issue.md +25 -0
  61. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/prototype.md +4 -4
  62. package/dist/pstack/skills/poteto-mode/playbooks/refactoring.md +16 -0
  63. package/dist/pstack/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  64. package/dist/pstack/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  65. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/shipping.md +2 -2
  66. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/trace-forensics.md +2 -2
  67. package/dist/pstack/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  68. package/dist/pstack/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
  69. package/{assets → dist/pstack}/skills/poteto-mode/scripts/check-plan.mjs +6 -8
  70. package/dist/pstack/skills/poteto-mode/scripts/check-plan.test.mjs +128 -0
  71. package/{assets/skills/poteto-mode/scripts/check-plan.test.mjs → dist/pstack/skills/poteto-mode/scripts/expect.mjs} +12 -101
  72. package/dist/pstack/skills/poteto-mode/scripts/support.mjs +93 -0
  73. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.mjs +123 -0
  74. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +217 -0
  75. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.mjs +119 -0
  76. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.mjs +626 -0
  77. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.test.mjs +521 -0
  78. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.mjs +657 -0
  79. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +523 -0
  80. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/render.mjs +106 -0
  81. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/types.mjs +9 -0
  82. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +5 -0
  83. package/{assets → dist/pstack}/skills/poteto-mode/scripts/worktree-audit.mjs +15 -22
  84. package/dist/pstack/skills/poteto-mode/scripts/worktree-audit.test.mjs +134 -0
  85. package/{assets → dist/pstack}/skills/principle-attack-the-premise/SKILL.md +1 -1
  86. package/{assets → dist/pstack}/skills/principle-boundary-discipline/SKILL.md +1 -1
  87. package/{assets → dist/pstack}/skills/principle-encode-lessons-in-structure/SKILL.md +1 -1
  88. package/{assets → dist/pstack}/skills/principle-exhaust-the-design-space/SKILL.md +1 -1
  89. package/{assets → dist/pstack}/skills/principle-experience-first/SKILL.md +1 -1
  90. package/{assets → dist/pstack}/skills/principle-explain-the-number/SKILL.md +3 -2
  91. package/{assets → dist/pstack}/skills/principle-fix-root-causes/SKILL.md +1 -1
  92. package/{assets → dist/pstack}/skills/principle-laziness-protocol/SKILL.md +1 -1
  93. package/{assets → dist/pstack}/skills/principle-make-operations-idempotent/SKILL.md +1 -1
  94. package/{assets → dist/pstack}/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +1 -1
  95. package/{assets → dist/pstack}/skills/principle-minimize-reader-load/SKILL.md +1 -1
  96. package/{assets → dist/pstack}/skills/principle-model-the-domain/SKILL.md +1 -1
  97. package/{assets → dist/pstack}/skills/principle-never-block-on-the-human/SKILL.md +1 -1
  98. package/{assets → dist/pstack}/skills/principle-outcome-oriented-execution/SKILL.md +1 -1
  99. package/{assets → dist/pstack}/skills/principle-prove-it-works/SKILL.md +2 -2
  100. package/{assets → dist/pstack}/skills/principle-redesign-from-first-principles/SKILL.md +1 -1
  101. package/{assets → dist/pstack}/skills/principle-separate-before-serializing-shared-state/SKILL.md +1 -1
  102. package/{assets → dist/pstack}/skills/principle-sequence-verifiable-units/SKILL.md +1 -1
  103. package/{assets → dist/pstack}/skills/principle-subtract-before-you-add/SKILL.md +1 -1
  104. package/{assets → dist/pstack}/skills/principle-test-behavior-not-implementation/SKILL.md +1 -1
  105. package/{assets → dist/pstack}/skills/principle-type-system-discipline/SKILL.md +1 -1
  106. package/dist/pstack/skills/recall/SKILL.md +37 -0
  107. package/dist/pstack/skills/reflect/SKILL.md +71 -0
  108. package/{assets → dist/pstack}/skills/reflect/references/divergent-reviewer.md +4 -4
  109. package/{assets → dist/pstack}/skills/reflect/references/judgment-reviewer.md +2 -2
  110. package/{assets → dist/pstack}/skills/reflect/references/synthesizer.md +5 -5
  111. package/{assets → dist/pstack}/skills/reflect/references/tooling-reviewer.md +2 -2
  112. package/dist/pstack/skills/setup-pstack/SKILL.md +80 -0
  113. package/{assets → dist/pstack}/skills/sharpen/SKILL.md +1 -1
  114. package/{assets → dist/pstack}/skills/show-me-your-work/SKILL.md +8 -8
  115. package/{assets → dist/pstack}/skills/show-me-your-work/scripts/log.mjs +1 -3
  116. package/dist/pstack/skills/show-me-your-work/scripts/log.test.mjs +56 -0
  117. package/dist/pstack/skills/statechart/SKILL.md +82 -0
  118. package/dist/pstack/skills/statechart/references/render.md +93 -0
  119. package/dist/pstack/skills/statechart/scripts/backends/cfg.mjs +31 -0
  120. package/dist/pstack/skills/statechart/scripts/backends/mermaid.mjs +186 -0
  121. package/dist/pstack/skills/statechart/scripts/backends/plain-text.mjs +62 -0
  122. package/dist/pstack/skills/statechart/scripts/backends/report.mjs +84 -0
  123. package/dist/pstack/skills/statechart/scripts/frontends/config.mjs +268 -0
  124. package/dist/pstack/skills/statechart/scripts/frontends/dot.mjs +67 -0
  125. package/dist/pstack/skills/statechart/scripts/frontends/marks.mjs +94 -0
  126. package/dist/pstack/skills/statechart/scripts/frontends/messages.mjs +48 -0
  127. package/dist/pstack/skills/statechart/scripts/frontends/spec.mjs +101 -0
  128. package/dist/pstack/skills/statechart/scripts/frontends/trace.mjs +39 -0
  129. package/dist/pstack/skills/statechart/scripts/frontends/value.mjs +180 -0
  130. package/dist/pstack/skills/statechart/scripts/frontends/verdict.mjs +40 -0
  131. package/dist/pstack/skills/statechart/scripts/frontends/view.mjs +99 -0
  132. package/dist/pstack/skills/statechart/scripts/ir.mjs +277 -0
  133. package/dist/pstack/skills/statechart/scripts/passes/annotate.mjs +92 -0
  134. package/dist/pstack/skills/statechart/scripts/passes/label.mjs +210 -0
  135. package/dist/pstack/skills/statechart/scripts/passes/lift.mjs +84 -0
  136. package/dist/pstack/skills/statechart/scripts/passes/loop-check.mjs +47 -0
  137. package/dist/pstack/skills/statechart/scripts/passes/paths.mjs +72 -0
  138. package/dist/pstack/skills/statechart/scripts/passes/reach.mjs +135 -0
  139. package/dist/pstack/skills/statechart/scripts/passes/region-check.mjs +82 -0
  140. package/dist/pstack/skills/statechart/scripts/passes/regions.mjs +268 -0
  141. package/dist/pstack/skills/statechart/scripts/pipeline.mjs +72 -0
  142. package/dist/pstack/skills/statechart/scripts/run.mjs +440 -0
  143. package/dist/pstack/skills/statechart/scripts/statechart.mjs +155 -0
  144. package/dist/pstack/skills/statechart/scripts/statechart.test.mjs +198 -0
  145. package/dist/pstack/skills/statechart/scripts/worker.mjs +31 -0
  146. package/dist/pstack/skills/swarm/SKILL.md +43 -0
  147. package/{assets → dist/pstack}/skills/tdd/SKILL.md +1 -1
  148. package/{assets → dist/pstack}/skills/teach/SKILL.md +2 -2
  149. package/{assets → dist/pstack}/skills/technical-writing/SKILL.md +1 -1
  150. package/{assets → dist/pstack}/skills/typescript-best-practices/SKILL.md +3 -6
  151. package/{assets → dist/pstack}/skills/why/SKILL.md +8 -8
  152. package/dist/script.d.mts +9 -111
  153. package/dist/script.mjs +32 -329
  154. package/dist/skill.d.mts +38 -0
  155. package/dist/skill.mjs +183 -0
  156. package/dist/skills/authored/decision-audit/SKILL.md +99 -0
  157. package/dist/skills/authored/decision-audit/SKILL.zh.md +99 -0
  158. package/dist/skills/authored/decision-audit/references/recover-commit.md +17 -0
  159. package/dist/skills/authored/decision-audit/references/recover-commit.zh.md +17 -0
  160. package/dist/skills/authored/decision-write/SKILL.md +131 -0
  161. package/dist/skills/authored/decision-write/SKILL.zh.md +131 -0
  162. package/dist/skills/authored/decision-write/references/land.md +48 -0
  163. package/dist/skills/authored/decision-write/references/land.zh.md +48 -0
  164. package/dist/skills/authored/setup-project-docs/SKILL.md +58 -0
  165. package/dist/skills/authored/setup-project-docs/SKILL.zh.md +58 -0
  166. package/dist/skills/authored/setup-project-docs/references/decision-conventions.md +11 -0
  167. package/dist/skills/authored/setup-project-docs/references/decision-conventions.zh.md +11 -0
  168. package/dist/skills/vendored/retro/SKILL.md +44 -0
  169. package/dist/skills/vendored/retro/agents/openai.yaml +5 -0
  170. package/dist/skills/vendored/writing-for-agents/SKILL-MECHANICS.md +22 -0
  171. package/dist/skills/vendored/writing-for-agents/SKILL.md +81 -0
  172. package/dist/skills/vendored/writing-for-agents/agents/openai.yaml +3 -0
  173. package/dist/subagent.d.mts +56 -193
  174. package/dist/subagent.mjs +443 -741
  175. package/locale/en.json +3 -2
  176. package/locale/zh.json +3 -2
  177. package/package.json +63 -66
  178. package/assets/agents/poteto-agent.md +0 -8
  179. package/assets/docs/harness/dsh.md +0 -60
  180. package/assets/docs/pstack-models.example.md +0 -54
  181. package/assets/skills/arena/SKILL.md +0 -50
  182. package/assets/skills/figure-it-out/SKILL.md +0 -54
  183. package/assets/skills/how/SKILL.md +0 -38
  184. package/assets/skills/interrogate/SKILL.md +0 -71
  185. package/assets/skills/interrogate/references/code-quality-review.md +0 -47
  186. package/assets/skills/interrogate/references/lead-judgment.md +0 -39
  187. package/assets/skills/interrogate/references/reviewer-prompt.md +0 -62
  188. package/assets/skills/interrogate/references/rubric.md +0 -77
  189. package/assets/skills/no-comments/SKILL.md +0 -26
  190. package/assets/skills/poteto-mode/playbooks/authoring-a-skill.md +0 -12
  191. package/assets/skills/poteto-mode/playbooks/autonomous-run.md +0 -15
  192. package/assets/skills/poteto-mode/playbooks/autopilot-full.md +0 -25
  193. package/assets/skills/poteto-mode/playbooks/autopilot-stack.md +0 -12
  194. package/assets/skills/poteto-mode/playbooks/bug-fix.md +0 -15
  195. package/assets/skills/poteto-mode/playbooks/feature.md +0 -21
  196. package/assets/skills/poteto-mode/playbooks/orchestrate.md +0 -112
  197. package/assets/skills/poteto-mode/playbooks/perf-issue.md +0 -25
  198. package/assets/skills/poteto-mode/playbooks/refactoring.md +0 -16
  199. package/assets/skills/poteto-mode/playbooks/runtime-forensics.md +0 -11
  200. package/assets/skills/poteto-mode/playbooks/session-pickup.md +0 -11
  201. package/assets/skills/poteto-mode/playbooks/visual-parity.md +0 -11
  202. package/assets/skills/poteto-mode/playbooks/worktree-cleanup.md +0 -20
  203. package/assets/skills/poteto-mode/scripts/orch/orch.mjs +0 -4282
  204. package/assets/skills/poteto-mode/scripts/orch/orch.test.mjs +0 -2042
  205. package/assets/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +0 -5101
  206. package/assets/skills/poteto-mode/scripts/watch-pr/github.test.mjs +0 -1177
  207. package/assets/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +0 -1441
  208. package/assets/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +0 -4601
  209. package/assets/skills/recall/SKILL.md +0 -37
  210. package/assets/skills/reflect/SKILL.md +0 -69
  211. package/assets/skills/setup-pstack/SKILL.md +0 -67
  212. package/assets/skills/swarm/SKILL.md +0 -43
  213. package/dist/frontmatter-BQX3ekwP.mjs +0 -229
  214. package/dist/frontmatter-BQX3ekwP.mjs.map +0 -1
  215. package/dist/history.d.mts +0 -429
  216. package/dist/history.mjs +0 -1129
  217. package/dist/history.mjs.map +0 -1
  218. package/dist/host-contract-o47JH_r8.d.mts +0 -527
  219. package/dist/index.mjs.map +0 -1
  220. package/dist/paths-D_JlVmBk.mjs +0 -42
  221. package/dist/paths-D_JlVmBk.mjs.map +0 -1
  222. package/dist/script.mjs.map +0 -1
  223. package/dist/subagent.mjs.map +0 -1
  224. /package/{static/icon.png → assets/logo.png} +0 -0
  225. /package/{assets → dist/pstack}/agents/comment-sicko.md +0 -0
  226. /package/{assets → dist/pstack}/docs/guide/03-understand.md +0 -0
  227. /package/{assets → dist/pstack}/docs/guide/08-principles.md +0 -0
  228. /package/{assets → dist/pstack}/docs/guide/images/design.jpg +0 -0
  229. /package/{assets → dist/pstack}/docs/guide/images/overnight.jpg +0 -0
  230. /package/{assets → dist/pstack}/docs/guide/images/recipes.jpg +0 -0
  231. /package/{assets → dist/pstack}/docs/guide/images/router.jpg +0 -0
  232. /package/{assets → dist/pstack}/docs/guide/images/understanding.jpg +0 -0
  233. /package/{assets → dist/pstack}/docs/guide/images/verification.jpg +0 -0
  234. /package/{assets → dist/pstack}/skills/architect/references/design-red-flags.md +0 -0
  235. /package/{assets → dist/pstack}/skills/architect/references/rationale-template.md +0 -0
  236. /package/{assets → dist/pstack}/skills/architect/references/runner-prompt.md +0 -0
  237. /package/{assets → dist/pstack}/skills/bro/SKILL.md +0 -0
  238. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/README.md +0 -0
  239. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/create-note.md +0 -0
  240. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/search.md +0 -0
  241. /package/{assets → dist/pstack}/skills/how/references/explainer-prompt.md +0 -0
  242. /package/{assets → dist/pstack}/skills/how/references/explorer-prompt.md +0 -0
  243. /package/{assets → dist/pstack}/skills/poteto-mode/references/bugbot-triage.md +0 -0
  244. /package/{assets → dist/pstack}/skills/principle-build-the-lever/SKILL.md +0 -0
  245. /package/{assets → dist/pstack}/skills/principle-foundational-thinking/SKILL.md +0 -0
  246. /package/{assets → dist/pstack}/skills/principle-guard-the-context-window/SKILL.md +0 -0
  247. /package/{assets → dist/pstack}/skills/show-me-your-work/references/decision-log-template.tsv +0 -0
  248. /package/{assets → dist/pstack}/skills/typescript-best-practices/references/patterns.md +0 -0
  249. /package/{assets → dist/pstack}/skills/unslop/SKILL.md +0 -0
  250. /package/{assets → dist/pstack}/skills/why/references/epistemics.md +0 -0
  251. /package/{assets → dist/pstack}/skills/why/references/investigator-prompt.md +0 -0
  252. /package/{assets → dist/pstack}/skills/why/references/source-playbook.md +0 -0
  253. /package/{assets → dist/pstack}/skills/why/references/sources/code-archaeology.md +0 -0
  254. /package/{assets → dist/pstack}/skills/why/references/sources/databricks.md +0 -0
  255. /package/{assets → dist/pstack}/skills/why/references/sources/datadog.md +0 -0
  256. /package/{assets → dist/pstack}/skills/why/references/sources/incident-postmortem.md +0 -0
  257. /package/{assets → dist/pstack}/skills/why/references/sources/linear.md +0 -0
  258. /package/{assets → dist/pstack}/skills/why/references/sources/notion.md +0 -0
  259. /package/{assets → dist/pstack}/skills/why/references/sources/sentry.md +0 -0
  260. /package/{assets → dist/pstack}/skills/why/references/sources/slack.md +0 -0
  261. /package/{assets → dist/pstack}/skills/why/references/synthesizer-prompt.md +0 -0
@@ -0,0 +1,657 @@
1
+ import { nonEmpty } from "./types.mjs";
2
+ import { WatcherQueryError, resolveChecks, resolveReviewThreads } from "./github.mjs";
3
+ // runtime/skills/poteto-mode/scripts/watch-pr/policy.ts
4
+ function assessGitHubMerge(args) {
5
+ if (args.mergeStateStatus === "BLOCKED") {
6
+ if (args.headRollupState === "ERROR" || args.headRollupState === "FAILURE") return {
7
+ kind: "refused",
8
+ mergeStateStatus: args.mergeStateStatus,
9
+ headRollupState: args.headRollupState
10
+ };
11
+ return {
12
+ kind: "allowed",
13
+ basis: "rollup",
14
+ mergeStateStatus: args.mergeStateStatus,
15
+ headRollupState: args.headRollupState
16
+ };
17
+ }
18
+ return {
19
+ kind: "allowed",
20
+ basis: "merge-state",
21
+ mergeStateStatus: args.mergeStateStatus,
22
+ headRollupState: args.headRollupState
23
+ };
24
+ }
25
+ async function mergeAssessment(reader, facts) {
26
+ const commits = await reader.commitRollups(facts.context);
27
+ const headRollupState = facts.headRefOid === null ? null : commits.find((commit) => commit.oid === facts.headRefOid)?.state ?? null;
28
+ return {
29
+ hadPreviousPassingCi: commits.some((commit) => commit.oid !== facts.headRefOid && commit.state === "SUCCESS"),
30
+ github: assessGitHubMerge({
31
+ mergeStateStatus: facts.mergeStateStatus,
32
+ headRollupState
33
+ })
34
+ };
35
+ }
36
+ const AUTOMATION_TOKENS = [
37
+ "bugbot",
38
+ "security review",
39
+ "pr review automation",
40
+ "review automation"
41
+ ];
42
+ async function readSnapshot(args) {
43
+ const facts = await args.reader.pullRequest(args.context);
44
+ if (facts.state === "MERGED" || facts.mergedAt !== null) return {
45
+ kind: "merged",
46
+ context: args.context,
47
+ facts
48
+ };
49
+ if (facts.state === "CLOSED") return {
50
+ kind: "closed",
51
+ context: args.context,
52
+ facts
53
+ };
54
+ const threads = await resolveReviewThreads(args.reader, args.context);
55
+ const checks = await resolveChecks(args.reader, args.context);
56
+ const failed = nonEmpty(checks.checks.filter((check) => check.kind === "failed"));
57
+ const pending = nonEmpty(checks.checks.filter((check) => check.kind === "pending"));
58
+ let ci;
59
+ if (failed === null && pending !== null && args.pendingHistory === "omit") ci = {
60
+ kind: "ci-pending",
61
+ source: checks.source,
62
+ all: checks.checks,
63
+ failed: [],
64
+ pending,
65
+ hadPreviousPassingCi: false
66
+ };
67
+ else {
68
+ const merge = await mergeAssessment(args.reader, facts);
69
+ const base = {
70
+ source: checks.source,
71
+ all: checks.checks,
72
+ hadPreviousPassingCi: merge.hadPreviousPassingCi
73
+ };
74
+ if (failed !== null) ci = {
75
+ ...base,
76
+ kind: "ci-failing",
77
+ failed,
78
+ pending: pending ?? [],
79
+ github: merge.github
80
+ };
81
+ else if (merge.github.kind === "refused") ci = {
82
+ ...base,
83
+ kind: "ci-github-rejected",
84
+ failed: [],
85
+ pending: pending ?? [],
86
+ github: merge.github
87
+ };
88
+ else if (pending !== null) ci = {
89
+ ...base,
90
+ kind: "ci-pending",
91
+ failed: [],
92
+ pending
93
+ };
94
+ else ci = {
95
+ ...base,
96
+ kind: "ci-clean",
97
+ failed: [],
98
+ pending: [],
99
+ github: merge.github
100
+ };
101
+ }
102
+ return {
103
+ kind: "open",
104
+ context: args.context,
105
+ facts,
106
+ threads,
107
+ ci,
108
+ reviewAutomationRunning: checks.checks.some((check) => check.kind === "pending" && AUTOMATION_TOKENS.some((token) => check.name.toLowerCase().includes(token)))
109
+ };
110
+ }
111
+ const conflictBlocker = (row) => row.kind === "open" && (row.facts.mergeable === "CONFLICTING" || row.facts.mergeStateStatus === "DIRTY" || row.facts.mergeStateStatus === "CONFLICTING") ? {
112
+ kind: "merge-conflicts",
113
+ pr: row.context,
114
+ facts: row.facts
115
+ } : null;
116
+ function threadBlocker(row) {
117
+ if (row.kind !== "open") return null;
118
+ const threads = nonEmpty(row.threads);
119
+ return threads === null ? null : {
120
+ kind: "review-threads",
121
+ pr: row.context,
122
+ threads
123
+ };
124
+ }
125
+ const ciBlocker = (row) => row.kind === "open" && (row.ci.kind === "ci-failing" || row.ci.kind === "ci-github-rejected") ? {
126
+ kind: "failing-checks",
127
+ pr: row.context,
128
+ ci: row.ci
129
+ } : null;
130
+ function gateReason(row, allowDraft) {
131
+ if (row.kind === "merged") return null;
132
+ if (row.kind === "closed") return "closed-without-merge";
133
+ if (row.facts.isDraft && !allowDraft) return "draft-pr";
134
+ return row.facts.reviewDecision === "CHANGES_REQUESTED" ? "changes-requested" : null;
135
+ }
136
+ function gateBlocker(row, allowDraft) {
137
+ const reason = gateReason(row, allowDraft);
138
+ return reason === null || reason === "draft-pr" && row.kind === "open" && row.ci.kind === "ci-pending" ? null : {
139
+ kind: "merge-gate",
140
+ pr: row.context,
141
+ reason
142
+ };
143
+ }
144
+ function readyContribution(row, allowDraft) {
145
+ if (row.kind === "merged") return {
146
+ kind: "merged-pr",
147
+ context: row.context,
148
+ mergedAt: row.facts.mergedAt
149
+ };
150
+ if (row.kind !== "open" || row.ci.kind !== "ci-clean" || row.threads.length !== 0 || conflictBlocker(row) !== null || gateReason(row, allowDraft) !== null) return null;
151
+ const reviewDecision = row.facts.reviewDecision;
152
+ if (reviewDecision === "CHANGES_REQUESTED") return null;
153
+ return {
154
+ kind: "ready-pr",
155
+ context: row.context,
156
+ proof: {
157
+ mergeability: "clear",
158
+ threads: [],
159
+ ci: row.ci,
160
+ gate: {
161
+ state: "OPEN",
162
+ reviewDecision,
163
+ draft: row.facts.isDraft ? "draft-allowed" : "not-draft"
164
+ }
165
+ }
166
+ };
167
+ }
168
+ function classifyPr(row, allowDraft = false) {
169
+ for (const blocker of [
170
+ conflictBlocker(row),
171
+ threadBlocker(row),
172
+ ciBlocker(row),
173
+ gateBlocker(row, allowDraft)
174
+ ]) if (blocker !== null) return {
175
+ kind: "blocker",
176
+ blocker
177
+ };
178
+ if (row.kind === "open" && row.ci.kind === "ci-pending") return {
179
+ kind: "waiting",
180
+ frontier: row.context,
181
+ pending: row.ci.pending
182
+ };
183
+ const ready = readyContribution(row, allowDraft);
184
+ if (ready === null) throw new Error("snapshot has no classified decision");
185
+ return ready.kind === "merged-pr" ? {
186
+ kind: "merged",
187
+ pr: ready
188
+ } : {
189
+ kind: "ready",
190
+ pr: ready
191
+ };
192
+ }
193
+ function selectTierMajorStackDecision(rows, allowDraft = false) {
194
+ for (const tier of [
195
+ conflictBlocker,
196
+ threadBlocker,
197
+ ciBlocker
198
+ ]) for (const row of rows) {
199
+ const blocker = tier(row);
200
+ if (blocker !== null) return {
201
+ kind: "blocker",
202
+ blocker
203
+ };
204
+ }
205
+ for (const row of rows) {
206
+ const blocker = gateBlocker(row, allowDraft);
207
+ if (blocker !== null) return {
208
+ kind: "blocker",
209
+ blocker
210
+ };
211
+ }
212
+ for (const row of rows) if (row.kind === "open" && row.ci.kind === "ci-pending") return {
213
+ kind: "waiting",
214
+ frontier: row.context,
215
+ pending: row.ci.pending
216
+ };
217
+ const prs = nonEmpty(rows.map((row) => readyContribution(row, allowDraft)).filter((row) => row !== null));
218
+ if (prs === null || prs.length !== rows.length) throw new Error("stack has no classified decision");
219
+ return {
220
+ kind: "clear",
221
+ prs
222
+ };
223
+ }
224
+ const queryBackoffSeconds = (interval, failures) => Math.min(Math.max(interval, 60) * 2 ** (failures - 1), 300);
225
+ function verdictFactory(clock, mode) {
226
+ let sequence = 0;
227
+ function stamp(payload, override) {
228
+ return {
229
+ schemaVersion: 1,
230
+ sequence: sequence += 1,
231
+ observedAt: clock.observedAt(),
232
+ mode: override ?? mode,
233
+ ...payload
234
+ };
235
+ }
236
+ return stamp;
237
+ }
238
+ function blockerVerdict(stamp, blocker) {
239
+ switch (blocker.kind) {
240
+ case "merge-conflicts": return stamp({
241
+ kind: "BLOCKER",
242
+ terminal: true,
243
+ exitCode: 2,
244
+ blocker
245
+ });
246
+ case "review-threads": return stamp({
247
+ kind: "BLOCKER",
248
+ terminal: true,
249
+ exitCode: 3,
250
+ blocker
251
+ });
252
+ case "failing-checks": return stamp({
253
+ kind: "BLOCKER",
254
+ terminal: true,
255
+ exitCode: 4,
256
+ blocker
257
+ });
258
+ case "merge-gate": return stamp({
259
+ kind: "BLOCKER",
260
+ terminal: true,
261
+ exitCode: 6,
262
+ blocker
263
+ });
264
+ default: return blocker;
265
+ }
266
+ }
267
+ function statusQueryVerdict(stamp, failures, failure) {
268
+ return stamp({
269
+ kind: "BLOCKER",
270
+ terminal: true,
271
+ exitCode: 7,
272
+ blocker: {
273
+ kind: "status-query",
274
+ failures,
275
+ failure
276
+ }
277
+ });
278
+ }
279
+ const deadlinePassed = (started, options, now) => options.timeout > 0 && now - started >= options.timeout;
280
+ async function pollUntilTerminal(args) {
281
+ let failures = 0;
282
+ const started = args.dependencies.clock.now();
283
+ const sleep = async (seconds) => {
284
+ const remaining = args.options.timeout > 0 ? Math.max(0, args.options.timeout - (args.dependencies.clock.now() - started)) : seconds;
285
+ await args.dependencies.clock.sleep(Math.min(seconds, remaining));
286
+ };
287
+ while (true) {
288
+ let result;
289
+ try {
290
+ result = await args.step();
291
+ failures = 0;
292
+ } catch (error) {
293
+ if (!(error instanceof WatcherQueryError)) throw error;
294
+ failures += 1;
295
+ if (!error.failure.retryable || failures >= args.options.maxQueryErrors) return statusQueryVerdict(args.stamp, failures, error.failure);
296
+ const retryInSeconds = queryBackoffSeconds(args.options.interval, failures);
297
+ args.dependencies.emit(args.stamp({
298
+ kind: "RETRY",
299
+ terminal: false,
300
+ failure: error.failure,
301
+ consecutiveFailures: failures,
302
+ retryInSeconds
303
+ }));
304
+ if (deadlinePassed(started, args.options, args.dependencies.clock.now())) return args.stamp({
305
+ kind: "TIMEOUT",
306
+ terminal: true,
307
+ exitCode: 5,
308
+ reason: {
309
+ kind: "status-unavailable",
310
+ failure: error.failure
311
+ }
312
+ });
313
+ await sleep(retryInSeconds);
314
+ continue;
315
+ }
316
+ if (result.kind === "terminal") return result.verdict;
317
+ if (result.kind === "sleep") {
318
+ if (result.onDeadline !== void 0 && deadlinePassed(started, args.options, args.dependencies.clock.now())) return result.onDeadline();
319
+ await sleep(result.seconds);
320
+ }
321
+ }
322
+ }
323
+ async function runSimple(args) {
324
+ const stamp = verdictFactory(args.dependencies.clock, args.mode);
325
+ const step = async () => {
326
+ const rows = [];
327
+ for (const context of args.contexts) rows.push(await readSnapshot({
328
+ reader: args.dependencies.reader,
329
+ context,
330
+ pendingHistory: "include",
331
+ allowDraft: args.options.allowDraft
332
+ }));
333
+ const complete = nonEmpty(rows);
334
+ if (complete === null) throw new Error("watch context cannot be empty");
335
+ if (args.statusOnly) return {
336
+ kind: "terminal",
337
+ verdict: stamp({
338
+ kind: "STATUS",
339
+ terminal: true,
340
+ exitCode: 0,
341
+ reason: "status-only",
342
+ rows: complete
343
+ })
344
+ };
345
+ if (args.mode === "queued-stack") throw new Error("queued-stack requires status-only in the simple runner");
346
+ if (args.mode === "stack") args.dependencies.emit(stamp({
347
+ kind: "STATUS",
348
+ terminal: false,
349
+ reason: "poll",
350
+ rows: complete
351
+ }, args.mode));
352
+ const decision = args.mode === "single" ? classifyPr(complete[0], args.options.allowDraft) : selectTierMajorStackDecision(complete, args.options.allowDraft);
353
+ if (decision.kind === "blocker") return {
354
+ kind: "terminal",
355
+ verdict: blockerVerdict(stamp, decision.blocker)
356
+ };
357
+ if (decision.kind === "ready" || decision.kind === "merged") return {
358
+ kind: "terminal",
359
+ verdict: stamp({
360
+ kind: "READY",
361
+ terminal: true,
362
+ exitCode: 0,
363
+ scope: {
364
+ kind: "single",
365
+ pr: decision.pr
366
+ }
367
+ }, args.mode)
368
+ };
369
+ if (decision.kind === "clear") return {
370
+ kind: "terminal",
371
+ verdict: stamp({
372
+ kind: "READY",
373
+ terminal: true,
374
+ exitCode: 0,
375
+ scope: {
376
+ kind: "stack",
377
+ prs: decision.prs
378
+ }
379
+ }, args.mode)
380
+ };
381
+ args.dependencies.emit(stamp({
382
+ kind: "WAITING",
383
+ terminal: false,
384
+ frontier: decision.frontier,
385
+ reason: {
386
+ kind: "pending-checks",
387
+ pending: decision.pending
388
+ }
389
+ }));
390
+ return {
391
+ kind: "sleep",
392
+ seconds: args.options.interval,
393
+ onDeadline: () => stamp({
394
+ kind: "TIMEOUT",
395
+ terminal: true,
396
+ exitCode: 5,
397
+ reason: {
398
+ kind: "pending-checks",
399
+ pending: decision.pending
400
+ }
401
+ })
402
+ };
403
+ };
404
+ return pollUntilTerminal({
405
+ dependencies: args.dependencies,
406
+ options: args.options,
407
+ stamp,
408
+ step
409
+ });
410
+ }
411
+ const createQueueState = (queue, now) => ({
412
+ queue,
413
+ snapshots: /* @__PURE__ */ new Map(),
414
+ work: {
415
+ kind: "whole-stack-sweep",
416
+ remaining: queue
417
+ },
418
+ nextSweepAt: now,
419
+ frontier: null,
420
+ lastWaitKey: null,
421
+ startedAt: now
422
+ });
423
+ const orderedRows = (state) => state.queue.flatMap((context) => {
424
+ const row = state.snapshots.get(context.number);
425
+ return row === void 0 ? [] : [row];
426
+ });
427
+ const activeRows = (state) => orderedRows(state).filter((row) => row.kind !== "merged");
428
+ function planQueue(state, now) {
429
+ if (state.work !== null) return state;
430
+ if (state.snapshots.size === 0 || now >= state.nextSweepAt) {
431
+ const remaining = nonEmpty(state.queue.filter((context) => state.snapshots.get(context.number)?.kind !== "merged"));
432
+ if (remaining !== null) return {
433
+ ...state,
434
+ work: {
435
+ kind: "whole-stack-sweep",
436
+ remaining
437
+ }
438
+ };
439
+ }
440
+ const frontier = activeRows(state)[0]?.context;
441
+ return frontier === void 0 ? state : {
442
+ ...state,
443
+ work: {
444
+ kind: "frontier-poll",
445
+ frontier
446
+ }
447
+ };
448
+ }
449
+ function applyQueueSnapshot(state, snapshot, now, options) {
450
+ if (state.work === null) throw new Error("queue has no read in flight");
451
+ const snapshots = new Map(state.snapshots);
452
+ snapshots.set(snapshot.context.number, snapshot);
453
+ const base = {
454
+ ...state,
455
+ snapshots
456
+ };
457
+ if (state.work.kind === "frontier-poll") return {
458
+ state: {
459
+ ...base,
460
+ work: null
461
+ },
462
+ completedSweepRows: null
463
+ };
464
+ const [head, ...tail] = state.work.remaining;
465
+ if (head.number !== snapshot.context.number) throw new Error("snapshot does not match sweep head");
466
+ const remaining = nonEmpty(tail);
467
+ if (remaining !== null) return {
468
+ state: {
469
+ ...base,
470
+ work: {
471
+ kind: "whole-stack-sweep",
472
+ remaining
473
+ }
474
+ },
475
+ completedSweepRows: null
476
+ };
477
+ const rows = nonEmpty(state.queue.flatMap((context) => {
478
+ const row = snapshots.get(context.number);
479
+ return row === void 0 ? [] : [row];
480
+ }));
481
+ if (rows === null || rows.length !== state.queue.length) throw new Error("sweep completed without every snapshot");
482
+ return {
483
+ state: {
484
+ ...base,
485
+ work: null,
486
+ nextSweepAt: now + options.sweepInterval
487
+ },
488
+ completedSweepRows: rows
489
+ };
490
+ }
491
+ function evaluateQueue(state, now, options) {
492
+ const active = activeRows(state);
493
+ if (active.length === 0) {
494
+ const merged = nonEmpty(orderedRows(state).flatMap((row) => row.kind === "merged" ? [{
495
+ kind: "merged-pr",
496
+ context: row.context,
497
+ mergedAt: row.facts.mergedAt
498
+ }] : []));
499
+ if (merged === null) throw new Error("empty queue cannot complete");
500
+ return {
501
+ kind: "complete",
502
+ state,
503
+ merged
504
+ };
505
+ }
506
+ const rows = nonEmpty(active);
507
+ if (rows === null) throw new Error("active queue cannot be empty");
508
+ const decision = selectTierMajorStackDecision(rows, options.allowDraft);
509
+ if (decision.kind === "blocker") return {
510
+ kind: "blocker",
511
+ state,
512
+ blocker: decision.blocker
513
+ };
514
+ const frontier = rows[0].context;
515
+ if (state.frontier !== null && state.frontier.number !== frontier.number) return {
516
+ kind: "advance",
517
+ state: {
518
+ ...state,
519
+ frontier,
520
+ lastWaitKey: null
521
+ },
522
+ merged: state.frontier,
523
+ frontier,
524
+ remaining: active.length
525
+ };
526
+ if (deadlinePassed(state.startedAt, options, now)) return {
527
+ kind: "timeout",
528
+ state: {
529
+ ...state,
530
+ frontier
531
+ },
532
+ frontier,
533
+ unmergedCount: active.length
534
+ };
535
+ const row = rows[0];
536
+ const pending = row.kind === "open" && row.ci.kind === "ci-pending" ? row.ci.pending : null;
537
+ const reason = pending === null ? {
538
+ kind: "merge-queue",
539
+ unmergedCount: active.length
540
+ } : {
541
+ kind: "pending-checks",
542
+ pending
543
+ };
544
+ const key = reason.kind === "pending-checks" ? `pending:${frontier.number}:${reason.pending.length}` : `queue:${frontier.number}:${reason.unmergedCount}`;
545
+ return {
546
+ kind: "waiting",
547
+ state: {
548
+ ...state,
549
+ frontier,
550
+ lastWaitKey: key
551
+ },
552
+ frontier,
553
+ reason,
554
+ emit: state.lastWaitKey !== key
555
+ };
556
+ }
557
+ async function runQueued(args) {
558
+ let state = createQueueState(args.contexts, args.dependencies.clock.now());
559
+ const stamp = verdictFactory(args.dependencies.clock, "queued-stack");
560
+ args.dependencies.emit(stamp({
561
+ kind: "QUEUE",
562
+ terminal: false,
563
+ queue: args.contexts
564
+ }));
565
+ const step = async () => {
566
+ state = planQueue(state, args.dependencies.clock.now());
567
+ if (state.work === null) {
568
+ const complete = evaluateQueue(state, args.dependencies.clock.now(), args.options);
569
+ if (complete.kind !== "complete") throw new Error("queue has no work while active");
570
+ return {
571
+ kind: "terminal",
572
+ verdict: stamp({
573
+ kind: "COMPLETE",
574
+ terminal: true,
575
+ exitCode: 0,
576
+ queue: state.queue,
577
+ merged: complete.merged
578
+ })
579
+ };
580
+ }
581
+ const context = state.work.kind === "whole-stack-sweep" ? state.work.remaining[0] : state.work.frontier;
582
+ const snapshot = await readSnapshot({
583
+ reader: args.dependencies.reader,
584
+ context,
585
+ pendingHistory: "omit",
586
+ allowDraft: args.options.allowDraft
587
+ });
588
+ const applied = applyQueueSnapshot(state, snapshot, args.dependencies.clock.now(), args.options);
589
+ state = applied.state;
590
+ if (applied.completedSweepRows !== null) args.dependencies.emit(stamp({
591
+ kind: "STATUS",
592
+ terminal: false,
593
+ reason: "whole-stack-sweep",
594
+ rows: applied.completedSweepRows
595
+ }));
596
+ if (state.work !== null) return { kind: "continue" };
597
+ const evaluation = evaluateQueue(state, args.dependencies.clock.now(), args.options);
598
+ state = evaluation.state;
599
+ switch (evaluation.kind) {
600
+ case "complete": return {
601
+ kind: "terminal",
602
+ verdict: stamp({
603
+ kind: "COMPLETE",
604
+ terminal: true,
605
+ exitCode: 0,
606
+ queue: state.queue,
607
+ merged: evaluation.merged
608
+ })
609
+ };
610
+ case "blocker": return {
611
+ kind: "terminal",
612
+ verdict: blockerVerdict(stamp, evaluation.blocker)
613
+ };
614
+ case "advance":
615
+ args.dependencies.emit(stamp({
616
+ kind: "ADVANCE",
617
+ terminal: false,
618
+ merged: evaluation.merged,
619
+ frontier: evaluation.frontier,
620
+ remaining: evaluation.remaining
621
+ }));
622
+ return { kind: "continue" };
623
+ case "timeout": return {
624
+ kind: "terminal",
625
+ verdict: stamp({
626
+ kind: "TIMEOUT",
627
+ terminal: true,
628
+ exitCode: 5,
629
+ reason: {
630
+ kind: "queued-stack",
631
+ frontier: evaluation.frontier,
632
+ unmergedCount: evaluation.unmergedCount
633
+ }
634
+ })
635
+ };
636
+ case "waiting":
637
+ if (evaluation.emit) args.dependencies.emit(stamp({
638
+ kind: "WAITING",
639
+ terminal: false,
640
+ frontier: evaluation.frontier,
641
+ reason: evaluation.reason
642
+ }));
643
+ return {
644
+ kind: "sleep",
645
+ seconds: args.options.interval
646
+ };
647
+ default: return evaluation;
648
+ }
649
+ };
650
+ return pollUntilTerminal({
651
+ dependencies: args.dependencies,
652
+ options: args.options,
653
+ stamp,
654
+ step
655
+ });
656
+ }
657
+ export { applyQueueSnapshot, assessGitHubMerge, classifyPr, createQueueState, evaluateQueue, planQueue, queryBackoffSeconds, readSnapshot, runQueued, runSimple, selectTierMajorStackDecision, statusQueryVerdict, verdictFactory };