dsh-pstack 0.2.0-beta.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/LICENSE +2 -3
  2. package/README.md +148 -84
  3. package/README.zh.md +198 -0
  4. package/assets/pstack-config-entry.png +0 -0
  5. package/cordis.patch.yml +105 -27
  6. package/dist/client.mjs +2341 -0
  7. package/dist/client.mjs.map +1 -0
  8. package/dist/host-contract-CUPSpeNk.d.mts +22 -0
  9. package/dist/index.d.mts +49 -238
  10. package/dist/index.mjs +250 -123
  11. package/dist/models.d.mts +44 -0
  12. package/dist/models.mjs +201 -0
  13. package/dist/paths-BT77khwm.mjs +48 -0
  14. package/dist/pstack/LICENSE +21 -0
  15. package/dist/pstack/README.md +291 -0
  16. package/dist/pstack/agents/poteto-agent.md +9 -0
  17. package/{assets → dist/pstack}/docs/guide/01-setup.md +13 -11
  18. package/{assets → dist/pstack}/docs/guide/02-poteto-mode.md +4 -4
  19. package/{assets → dist/pstack}/docs/guide/04-design.md +4 -4
  20. package/{assets → dist/pstack}/docs/guide/05-build-and-clean.md +2 -2
  21. package/{assets → dist/pstack}/docs/guide/06-verify-and-ship.md +13 -3
  22. package/{assets → dist/pstack}/docs/guide/07-overnight.md +15 -13
  23. package/{assets → dist/pstack}/docs/guide/09-make-it-yours.md +6 -2
  24. package/{assets → dist/pstack}/docs/guide/10-recipes-and-pitfalls.md +7 -5
  25. package/{assets → dist/pstack}/docs/guide/README.md +1 -1
  26. package/dist/pstack/docs/harness/dsh.md +98 -0
  27. package/{assets → dist/pstack}/skills/architect/SKILL.md +12 -12
  28. package/dist/pstack/skills/arena/SKILL.md +50 -0
  29. package/{assets → dist/pstack}/skills/automate-me/SKILL.md +14 -14
  30. package/{assets → dist/pstack}/skills/benchmark-checklist/SKILL.md +1 -1
  31. package/{assets → dist/pstack}/skills/blast-radius/SKILL.md +4 -6
  32. package/{assets → dist/pstack}/skills/correct/SKILL.md +1 -1
  33. package/{assets → dist/pstack}/skills/create-formal-verification-skill/SKILL.md +4 -2
  34. package/{assets → dist/pstack}/skills/create-verification-skill/SKILL.md +5 -5
  35. package/dist/pstack/skills/figure-it-out/SKILL.md +54 -0
  36. package/dist/pstack/skills/how/SKILL.md +38 -0
  37. package/{assets → dist/pstack}/skills/in-your-own-words/SKILL.md +1 -1
  38. package/dist/pstack/skills/interrogate/SKILL.md +33 -0
  39. package/{assets → dist/pstack}/skills/ketchup/SKILL.md +3 -5
  40. package/dist/pstack/skills/ketchup-video/SKILL.md +29 -0
  41. package/{assets → dist/pstack}/skills/maintain-formal-verification-skill/SKILL.md +1 -1
  42. package/{assets → dist/pstack}/skills/maintain-verification-skill/SKILL.md +3 -3
  43. package/dist/pstack/skills/make-bot-ui/SKILL.md +117 -0
  44. package/dist/pstack/skills/no-comments/SKILL.md +26 -0
  45. package/{assets → dist/pstack}/skills/poteto-help/SKILL.md +34 -31
  46. package/{assets → dist/pstack}/skills/poteto-help/references/prompting.md +1 -1
  47. package/{assets → dist/pstack}/skills/poteto-help/references/recipes.md +3 -3
  48. package/{assets → dist/pstack}/skills/poteto-mode/SKILL.md +20 -19
  49. package/dist/pstack/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  50. package/dist/pstack/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  51. package/dist/pstack/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
  52. package/dist/pstack/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
  53. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/babysit.md +4 -4
  54. package/dist/pstack/skills/poteto-mode/playbooks/bug-fix.md +15 -0
  55. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/eval.md +3 -3
  56. package/dist/pstack/skills/poteto-mode/playbooks/feature.md +21 -0
  57. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/hillclimb.md +3 -3
  58. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/investigation.md +2 -2
  59. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/multi-phase-plan.md +23 -23
  60. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/opening-a-pr.md +6 -6
  61. package/dist/pstack/skills/poteto-mode/playbooks/orchestrate.md +25 -0
  62. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/pause-safely.md +2 -2
  63. package/dist/pstack/skills/poteto-mode/playbooks/perf-issue.md +25 -0
  64. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/prototype.md +4 -4
  65. package/dist/pstack/skills/poteto-mode/playbooks/refactoring.md +16 -0
  66. package/dist/pstack/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  67. package/dist/pstack/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  68. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/shipping.md +2 -2
  69. package/{assets → dist/pstack}/skills/poteto-mode/playbooks/trace-forensics.md +2 -2
  70. package/dist/pstack/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  71. package/dist/pstack/skills/poteto-mode/playbooks/worktree-cleanup.md +12 -0
  72. package/{assets → dist/pstack}/skills/poteto-mode/scripts/check-plan.mjs +6 -8
  73. package/dist/pstack/skills/poteto-mode/scripts/check-plan.test.mjs +128 -0
  74. package/{assets/skills/poteto-mode/scripts/check-plan.test.mjs → dist/pstack/skills/poteto-mode/scripts/expect.mjs} +12 -101
  75. package/dist/pstack/skills/poteto-mode/scripts/support.mjs +93 -0
  76. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.mjs +123 -0
  77. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +217 -0
  78. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.mjs +119 -0
  79. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.mjs +626 -0
  80. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/github.test.mjs +521 -0
  81. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.mjs +657 -0
  82. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +523 -0
  83. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/render.mjs +106 -0
  84. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/types.mjs +9 -0
  85. package/dist/pstack/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +5 -0
  86. package/{assets → dist/pstack}/skills/poteto-mode/scripts/worktree-audit.mjs +15 -22
  87. package/dist/pstack/skills/poteto-mode/scripts/worktree-audit.test.mjs +134 -0
  88. package/{assets → dist/pstack}/skills/principle-attack-the-premise/SKILL.md +1 -1
  89. package/{assets → dist/pstack}/skills/principle-boundary-discipline/SKILL.md +1 -1
  90. package/{assets → dist/pstack}/skills/principle-encode-lessons-in-structure/SKILL.md +1 -1
  91. package/{assets → dist/pstack}/skills/principle-exhaust-the-design-space/SKILL.md +1 -1
  92. package/{assets → dist/pstack}/skills/principle-experience-first/SKILL.md +1 -1
  93. package/{assets → dist/pstack}/skills/principle-explain-the-number/SKILL.md +3 -2
  94. package/{assets → dist/pstack}/skills/principle-fix-root-causes/SKILL.md +1 -1
  95. package/{assets → dist/pstack}/skills/principle-laziness-protocol/SKILL.md +1 -1
  96. package/{assets → dist/pstack}/skills/principle-make-operations-idempotent/SKILL.md +1 -1
  97. package/{assets → dist/pstack}/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +1 -1
  98. package/{assets → dist/pstack}/skills/principle-minimize-reader-load/SKILL.md +1 -1
  99. package/{assets → dist/pstack}/skills/principle-model-the-domain/SKILL.md +1 -1
  100. package/{assets → dist/pstack}/skills/principle-never-block-on-the-human/SKILL.md +1 -1
  101. package/{assets → dist/pstack}/skills/principle-outcome-oriented-execution/SKILL.md +1 -1
  102. package/{assets → dist/pstack}/skills/principle-prove-it-works/SKILL.md +2 -2
  103. package/{assets → dist/pstack}/skills/principle-redesign-from-first-principles/SKILL.md +1 -1
  104. package/{assets → dist/pstack}/skills/principle-separate-before-serializing-shared-state/SKILL.md +1 -1
  105. package/{assets → dist/pstack}/skills/principle-sequence-verifiable-units/SKILL.md +1 -1
  106. package/{assets → dist/pstack}/skills/principle-subtract-before-you-add/SKILL.md +1 -1
  107. package/{assets → dist/pstack}/skills/principle-test-behavior-not-implementation/SKILL.md +1 -1
  108. package/{assets → dist/pstack}/skills/principle-type-system-discipline/SKILL.md +1 -1
  109. package/dist/pstack/skills/recall/SKILL.md +37 -0
  110. package/dist/pstack/skills/reflect/SKILL.md +71 -0
  111. package/{assets → dist/pstack}/skills/reflect/references/divergent-reviewer.md +4 -4
  112. package/{assets → dist/pstack}/skills/reflect/references/judgment-reviewer.md +2 -2
  113. package/{assets → dist/pstack}/skills/reflect/references/synthesizer.md +5 -5
  114. package/{assets → dist/pstack}/skills/reflect/references/tooling-reviewer.md +2 -2
  115. package/dist/pstack/skills/setup-pstack/SKILL.md +80 -0
  116. package/{assets → dist/pstack}/skills/sharpen/SKILL.md +1 -1
  117. package/{assets → dist/pstack}/skills/show-me-your-work/SKILL.md +8 -8
  118. package/{assets → dist/pstack}/skills/show-me-your-work/scripts/log.mjs +1 -3
  119. package/dist/pstack/skills/show-me-your-work/scripts/log.test.mjs +56 -0
  120. package/dist/pstack/skills/statechart/SKILL.md +82 -0
  121. package/dist/pstack/skills/statechart/references/render.md +93 -0
  122. package/dist/pstack/skills/statechart/scripts/backends/cfg.mjs +31 -0
  123. package/dist/pstack/skills/statechart/scripts/backends/mermaid.mjs +186 -0
  124. package/dist/pstack/skills/statechart/scripts/backends/plain-text.mjs +62 -0
  125. package/dist/pstack/skills/statechart/scripts/backends/report.mjs +84 -0
  126. package/dist/pstack/skills/statechart/scripts/frontends/config.mjs +268 -0
  127. package/dist/pstack/skills/statechart/scripts/frontends/dot.mjs +67 -0
  128. package/dist/pstack/skills/statechart/scripts/frontends/marks.mjs +94 -0
  129. package/dist/pstack/skills/statechart/scripts/frontends/messages.mjs +48 -0
  130. package/dist/pstack/skills/statechart/scripts/frontends/spec.mjs +101 -0
  131. package/dist/pstack/skills/statechart/scripts/frontends/trace.mjs +39 -0
  132. package/dist/pstack/skills/statechart/scripts/frontends/value.mjs +180 -0
  133. package/dist/pstack/skills/statechart/scripts/frontends/verdict.mjs +40 -0
  134. package/dist/pstack/skills/statechart/scripts/frontends/view.mjs +99 -0
  135. package/dist/pstack/skills/statechart/scripts/ir.mjs +277 -0
  136. package/dist/pstack/skills/statechart/scripts/passes/annotate.mjs +92 -0
  137. package/dist/pstack/skills/statechart/scripts/passes/label.mjs +210 -0
  138. package/dist/pstack/skills/statechart/scripts/passes/lift.mjs +84 -0
  139. package/dist/pstack/skills/statechart/scripts/passes/loop-check.mjs +47 -0
  140. package/dist/pstack/skills/statechart/scripts/passes/paths.mjs +72 -0
  141. package/dist/pstack/skills/statechart/scripts/passes/reach.mjs +135 -0
  142. package/dist/pstack/skills/statechart/scripts/passes/region-check.mjs +82 -0
  143. package/dist/pstack/skills/statechart/scripts/passes/regions.mjs +268 -0
  144. package/dist/pstack/skills/statechart/scripts/pipeline.mjs +72 -0
  145. package/dist/pstack/skills/statechart/scripts/run.mjs +440 -0
  146. package/dist/pstack/skills/statechart/scripts/statechart.mjs +155 -0
  147. package/dist/pstack/skills/statechart/scripts/statechart.test.mjs +198 -0
  148. package/dist/pstack/skills/statechart/scripts/worker.mjs +31 -0
  149. package/dist/pstack/skills/swarm/SKILL.md +43 -0
  150. package/{assets → dist/pstack}/skills/tdd/SKILL.md +1 -1
  151. package/{assets → dist/pstack}/skills/teach/SKILL.md +2 -2
  152. package/{assets → dist/pstack}/skills/technical-writing/SKILL.md +1 -1
  153. package/{assets → dist/pstack}/skills/typescript-best-practices/SKILL.md +3 -6
  154. package/{assets → dist/pstack}/skills/why/SKILL.md +8 -8
  155. package/dist/remote.d.mts +27 -0
  156. package/dist/remote.mjs +234 -0
  157. package/dist/role-config-NNn5r1JX.mjs +415 -0
  158. package/dist/role-manifest-C3fUzjLI.d.mts +19 -0
  159. package/dist/role-wire-DZwTn2wF.d.mts +55 -0
  160. package/dist/roles.d.mts +18 -0
  161. package/dist/roles.mjs +323 -0
  162. package/dist/script.d.mts +9 -111
  163. package/dist/script.mjs +32 -329
  164. package/dist/skill.d.mts +38 -0
  165. package/dist/skill.mjs +183 -0
  166. package/dist/skills/authored/decision-audit/SKILL.md +103 -0
  167. package/dist/skills/authored/decision-audit/SKILL.zh.md +103 -0
  168. package/dist/skills/authored/decision-audit/references/recover-commit.md +17 -0
  169. package/dist/skills/authored/decision-audit/references/recover-commit.zh.md +17 -0
  170. package/dist/skills/authored/decision-write/SKILL.md +133 -0
  171. package/dist/skills/authored/decision-write/SKILL.zh.md +133 -0
  172. package/dist/skills/authored/decision-write/references/land.md +48 -0
  173. package/dist/skills/authored/decision-write/references/land.zh.md +48 -0
  174. package/dist/skills/authored/decision-write/references/scope.md +16 -0
  175. package/dist/skills/authored/decision-write/references/scope.zh.md +16 -0
  176. package/dist/skills/authored/docs-drift/SKILL.md +120 -0
  177. package/dist/skills/authored/docs-drift/SKILL.zh.md +120 -0
  178. package/dist/skills/authored/setup-project-docs/SKILL.md +63 -0
  179. package/dist/skills/authored/setup-project-docs/SKILL.zh.md +63 -0
  180. package/dist/skills/authored/setup-project-docs/references/decision-conventions.md +13 -0
  181. package/dist/skills/authored/setup-project-docs/references/decision-conventions.zh.md +13 -0
  182. package/dist/skills/vendored/retro/SKILL.md +44 -0
  183. package/dist/skills/vendored/retro/agents/openai.yaml +5 -0
  184. package/dist/skills/vendored/writing-for-agents/SKILL-MECHANICS.md +22 -0
  185. package/dist/skills/vendored/writing-for-agents/SKILL.md +81 -0
  186. package/dist/skills/vendored/writing-for-agents/agents/openai.yaml +3 -0
  187. package/dist/subagent.d.mts +54 -206
  188. package/dist/subagent.mjs +258 -963
  189. package/locale/en.json +3 -2
  190. package/locale/zh.json +3 -2
  191. package/package.json +93 -66
  192. package/assets/agents/poteto-agent.md +0 -8
  193. package/assets/docs/harness/dsh.md +0 -60
  194. package/assets/docs/pstack-models.example.md +0 -54
  195. package/assets/skills/arena/SKILL.md +0 -50
  196. package/assets/skills/figure-it-out/SKILL.md +0 -54
  197. package/assets/skills/how/SKILL.md +0 -38
  198. package/assets/skills/interrogate/SKILL.md +0 -71
  199. package/assets/skills/interrogate/references/code-quality-review.md +0 -47
  200. package/assets/skills/interrogate/references/lead-judgment.md +0 -39
  201. package/assets/skills/interrogate/references/reviewer-prompt.md +0 -62
  202. package/assets/skills/interrogate/references/rubric.md +0 -77
  203. package/assets/skills/no-comments/SKILL.md +0 -26
  204. package/assets/skills/poteto-mode/playbooks/authoring-a-skill.md +0 -12
  205. package/assets/skills/poteto-mode/playbooks/autonomous-run.md +0 -15
  206. package/assets/skills/poteto-mode/playbooks/autopilot-full.md +0 -25
  207. package/assets/skills/poteto-mode/playbooks/autopilot-stack.md +0 -12
  208. package/assets/skills/poteto-mode/playbooks/bug-fix.md +0 -15
  209. package/assets/skills/poteto-mode/playbooks/feature.md +0 -21
  210. package/assets/skills/poteto-mode/playbooks/orchestrate.md +0 -112
  211. package/assets/skills/poteto-mode/playbooks/perf-issue.md +0 -25
  212. package/assets/skills/poteto-mode/playbooks/refactoring.md +0 -16
  213. package/assets/skills/poteto-mode/playbooks/runtime-forensics.md +0 -11
  214. package/assets/skills/poteto-mode/playbooks/session-pickup.md +0 -11
  215. package/assets/skills/poteto-mode/playbooks/visual-parity.md +0 -11
  216. package/assets/skills/poteto-mode/playbooks/worktree-cleanup.md +0 -20
  217. package/assets/skills/poteto-mode/scripts/orch/orch.mjs +0 -4282
  218. package/assets/skills/poteto-mode/scripts/orch/orch.test.mjs +0 -2042
  219. package/assets/skills/poteto-mode/scripts/watch-pr/cli.test.mjs +0 -5101
  220. package/assets/skills/poteto-mode/scripts/watch-pr/github.test.mjs +0 -1177
  221. package/assets/skills/poteto-mode/scripts/watch-pr/policy.test.mjs +0 -1441
  222. package/assets/skills/poteto-mode/scripts/watch-pr/watch-pr.mjs +0 -4601
  223. package/assets/skills/recall/SKILL.md +0 -37
  224. package/assets/skills/reflect/SKILL.md +0 -69
  225. package/assets/skills/setup-pstack/SKILL.md +0 -67
  226. package/assets/skills/swarm/SKILL.md +0 -43
  227. package/dist/frontmatter-BQX3ekwP.mjs +0 -229
  228. package/dist/frontmatter-BQX3ekwP.mjs.map +0 -1
  229. package/dist/history.d.mts +0 -429
  230. package/dist/history.mjs +0 -1129
  231. package/dist/history.mjs.map +0 -1
  232. package/dist/host-contract-o47JH_r8.d.mts +0 -527
  233. package/dist/index.mjs.map +0 -1
  234. package/dist/paths-D_JlVmBk.mjs +0 -42
  235. package/dist/paths-D_JlVmBk.mjs.map +0 -1
  236. package/dist/script.mjs.map +0 -1
  237. package/dist/subagent.mjs.map +0 -1
  238. /package/{static/icon.png → assets/logo.png} +0 -0
  239. /package/{assets → dist/pstack}/agents/comment-sicko.md +0 -0
  240. /package/{assets → dist/pstack}/docs/guide/03-understand.md +0 -0
  241. /package/{assets → dist/pstack}/docs/guide/08-principles.md +0 -0
  242. /package/{assets → dist/pstack}/docs/guide/images/design.jpg +0 -0
  243. /package/{assets → dist/pstack}/docs/guide/images/overnight.jpg +0 -0
  244. /package/{assets → dist/pstack}/docs/guide/images/recipes.jpg +0 -0
  245. /package/{assets → dist/pstack}/docs/guide/images/router.jpg +0 -0
  246. /package/{assets → dist/pstack}/docs/guide/images/understanding.jpg +0 -0
  247. /package/{assets → dist/pstack}/docs/guide/images/verification.jpg +0 -0
  248. /package/{assets → dist/pstack}/skills/architect/references/design-red-flags.md +0 -0
  249. /package/{assets → dist/pstack}/skills/architect/references/rationale-template.md +0 -0
  250. /package/{assets → dist/pstack}/skills/architect/references/runner-prompt.md +0 -0
  251. /package/{assets → dist/pstack}/skills/bro/SKILL.md +0 -0
  252. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/README.md +0 -0
  253. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/create-note.md +0 -0
  254. /package/{assets → dist/pstack}/skills/create-verification-skill/references/feature-map-example/search.md +0 -0
  255. /package/{assets → dist/pstack}/skills/how/references/explainer-prompt.md +0 -0
  256. /package/{assets → dist/pstack}/skills/how/references/explorer-prompt.md +0 -0
  257. /package/{assets → dist/pstack}/skills/poteto-mode/references/bugbot-triage.md +0 -0
  258. /package/{assets → dist/pstack}/skills/principle-build-the-lever/SKILL.md +0 -0
  259. /package/{assets → dist/pstack}/skills/principle-foundational-thinking/SKILL.md +0 -0
  260. /package/{assets → dist/pstack}/skills/principle-guard-the-context-window/SKILL.md +0 -0
  261. /package/{assets → dist/pstack}/skills/show-me-your-work/references/decision-log-template.tsv +0 -0
  262. /package/{assets → dist/pstack}/skills/typescript-best-practices/references/patterns.md +0 -0
  263. /package/{assets → dist/pstack}/skills/unslop/SKILL.md +0 -0
  264. /package/{assets → dist/pstack}/skills/why/references/epistemics.md +0 -0
  265. /package/{assets → dist/pstack}/skills/why/references/investigator-prompt.md +0 -0
  266. /package/{assets → dist/pstack}/skills/why/references/source-playbook.md +0 -0
  267. /package/{assets → dist/pstack}/skills/why/references/sources/code-archaeology.md +0 -0
  268. /package/{assets → dist/pstack}/skills/why/references/sources/databricks.md +0 -0
  269. /package/{assets → dist/pstack}/skills/why/references/sources/datadog.md +0 -0
  270. /package/{assets → dist/pstack}/skills/why/references/sources/incident-postmortem.md +0 -0
  271. /package/{assets → dist/pstack}/skills/why/references/sources/linear.md +0 -0
  272. /package/{assets → dist/pstack}/skills/why/references/sources/notion.md +0 -0
  273. /package/{assets → dist/pstack}/skills/why/references/sources/sentry.md +0 -0
  274. /package/{assets → dist/pstack}/skills/why/references/sources/slack.md +0 -0
  275. /package/{assets → dist/pstack}/skills/why/references/synthesizer-prompt.md +0 -0
@@ -0,0 +1,626 @@
1
+ import { nonEmpty, parsePrNumber } from "./types.mjs";
2
+ import { spawn } from "node:child_process";
3
+ // runtime/skills/poteto-mode/scripts/watch-pr/github.ts
4
+ const REVIEW_THREADS_QUERY = "\nquery ReviewThreads($owner: String!, $repo: String!, $pr: Int!, $after: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $pr) {\n reviewThreads(first: 100, after: $after) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n id\n isResolved\n comments(first: 10) {\n nodes {\n body\n createdAt\n path\n line\n author { login }\n }\n }\n }\n }\n }\n }\n}\n";
5
+ const PR_COMMIT_STATUS_QUERY = "\nquery PrCommitStatuses($owner: String!, $repo: String!, $pr: Int!) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $pr) {\n commits(last: 50) {\n nodes {\n commit {\n oid\n statusCheckRollup {\n state\n }\n }\n }\n }\n }\n }\n}\n";
6
+ const PR_CHECK_ROLLUP_QUERY = "\nquery PrCheckRollup($owner: String!, $repo: String!, $pr: Int!, $after: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $pr) {\n commits(last: 1) {\n nodes {\n commit {\n statusCheckRollup {\n contexts(first: 100, after: $after) {\n pageInfo {\n hasNextPage\n endCursor\n }\n nodes {\n __typename\n ... on CheckRun {\n name\n status\n conclusion\n detailsUrl\n }\n ... on StatusContext {\n context\n state\n targetUrl\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}\n";
7
+ var WatcherQueryError = class extends Error {
8
+ failure;
9
+ constructor(failure) {
10
+ super(failure.detail);
11
+ this.name = "WatcherQueryError";
12
+ this.failure = failure;
13
+ }
14
+ };
15
+ var ChecksUnavailable = class extends WatcherQueryError {
16
+ constructor(detail) {
17
+ super({
18
+ kind: "checks-unavailable",
19
+ retryable: true,
20
+ detail
21
+ });
22
+ this.name = "ChecksUnavailable";
23
+ }
24
+ };
25
+ const firstLine = (value) => value.trim().split(/\r?\n/, 1)[0]?.slice(0, 240) ?? "";
26
+ function run(argv) {
27
+ return new Promise((resolve, reject) => {
28
+ const child = spawn(argv[0], argv.slice(1), { stdio: [
29
+ "ignore",
30
+ "pipe",
31
+ "pipe"
32
+ ] });
33
+ let stdout = "";
34
+ let stderr = "";
35
+ child.stdout.setEncoding("utf8");
36
+ child.stderr.setEncoding("utf8");
37
+ child.stdout.on("data", (chunk) => {
38
+ stdout += chunk;
39
+ });
40
+ child.stderr.on("data", (chunk) => {
41
+ stderr += chunk;
42
+ });
43
+ child.on("error", reject);
44
+ child.on("close", (code) => resolve({
45
+ code: code ?? -1,
46
+ stdout,
47
+ stderr
48
+ }));
49
+ });
50
+ }
51
+ function parseJson(text, label) {
52
+ try {
53
+ return JSON.parse(text);
54
+ } catch (error) {
55
+ throw new WatcherQueryError({
56
+ kind: "json-parse",
57
+ retryable: true,
58
+ detail: `${label}: ${error instanceof Error ? error.message : String(error)}`
59
+ });
60
+ }
61
+ }
62
+ async function runJson(argv) {
63
+ const result = await run(argv);
64
+ if (result.code !== 0) throw new WatcherQueryError({
65
+ kind: "command-exit",
66
+ retryable: true,
67
+ code: result.code,
68
+ detail: firstLine(result.stderr) || `${argv.join(" ")} exited ${result.code}`
69
+ });
70
+ return parseJson(result.stdout, argv.join(" "));
71
+ }
72
+ function raw(value) {
73
+ try {
74
+ return JSON.stringify(value);
75
+ } catch {
76
+ return String(value);
77
+ }
78
+ }
79
+ function missing(path, value) {
80
+ throw new WatcherQueryError({
81
+ kind: "missing-key",
82
+ retryable: true,
83
+ detail: value === void 0 ? `missing ${path}` : `invalid ${path}: ${raw(value)}`,
84
+ ...value === void 0 ? {} : { rawValue: raw(value) }
85
+ });
86
+ }
87
+ function isRecord(value) {
88
+ return typeof value === "object" && value !== null && !Array.isArray(value);
89
+ }
90
+ function record(value, path) {
91
+ if (!isRecord(value)) missing(path, value);
92
+ return value;
93
+ }
94
+ function list(value, path) {
95
+ if (!Array.isArray(value)) missing(path, value);
96
+ return value;
97
+ }
98
+ function at(value, path) {
99
+ let current = value;
100
+ for (const key of path) {
101
+ const object = record(current, path.join("."));
102
+ if (!(key in object)) missing(path.join("."));
103
+ current = object[key];
104
+ }
105
+ return current;
106
+ }
107
+ function string(value, path) {
108
+ if (typeof value !== "string") missing(path, value);
109
+ return value;
110
+ }
111
+ const optionalString = (value, path) => value === null ? null : string(value, path);
112
+ function enumValue(value, values, path) {
113
+ if (typeof value === "string") {
114
+ for (const candidate of values) if (candidate === value) return candidate;
115
+ }
116
+ return missing(path, value);
117
+ }
118
+ const nullableEnum = (value, values, path) => value === null ? null : enumValue(value, values, path);
119
+ const MERGE_STATES = [
120
+ "BEHIND",
121
+ "BLOCKED",
122
+ "CLEAN",
123
+ "CONFLICTING",
124
+ "DIRTY",
125
+ "DRAFT",
126
+ "HAS_HOOKS",
127
+ "UNKNOWN",
128
+ "UNSTABLE"
129
+ ];
130
+ const ROLLUP_STATES = [
131
+ "ERROR",
132
+ "EXPECTED",
133
+ "FAILURE",
134
+ "PENDING",
135
+ "SUCCESS"
136
+ ];
137
+ const REVIEW_DECISIONS = [
138
+ "APPROVED",
139
+ "CHANGES_REQUESTED",
140
+ "REVIEW_REQUIRED"
141
+ ];
142
+ const reviewDecision = (value) => nullableEnum(value === "" ? null : value, REVIEW_DECISIONS, "pull request.reviewDecision");
143
+ function parseRemote(value) {
144
+ let normalized = value.trim();
145
+ if (normalized.startsWith("git@github.com:")) normalized = `https://github.com/${normalized.slice(15)}`;
146
+ if (normalized.startsWith("ssh://git@github.com/")) normalized = `https://github.com/${normalized.slice(21)}`;
147
+ try {
148
+ const url = new URL(normalized);
149
+ const parts = url.pathname.replace(/\.git$/, "").split("/").filter(Boolean);
150
+ if (url.protocol !== "https:" || url.hostname !== "github.com" || url.port || url.username || url.password || url.search || url.hash || parts.length !== 2) return null;
151
+ return {
152
+ owner: parts[0],
153
+ repo: parts[1]
154
+ };
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ function parsePrUrl(value) {
160
+ try {
161
+ const url = new URL(value);
162
+ const parts = url.pathname.split("/").filter(Boolean);
163
+ if (url.protocol !== "https:" || url.hostname !== "github.com" || url.port || url.username || url.password || url.search || url.hash || parts.length !== 4 || parts[2] !== "pull") throw new Error("not a canonical GitHub pull URL");
164
+ return {
165
+ owner: parts[0],
166
+ repo: parts[1],
167
+ number: parsePrNumber(Number(parts[3]))
168
+ };
169
+ } catch (error) {
170
+ throw new WatcherQueryError({
171
+ kind: "invalid-context-url",
172
+ retryable: false,
173
+ rawValue: value,
174
+ detail: `could not infer owner/repo from PR URL: ${value} (${error instanceof Error ? error.message : String(error)})`
175
+ });
176
+ }
177
+ }
178
+ function checkDetails(value, nameKey) {
179
+ return {
180
+ name: string(value[nameKey], nameKey),
181
+ description: typeof value.description === "string" ? value.description : "",
182
+ link: typeof value.link === "string" ? value.link : typeof value.detailsUrl === "string" ? value.detailsUrl : "",
183
+ workflow: typeof value.workflow === "string" ? value.workflow : ""
184
+ };
185
+ }
186
+ function parseFastCheck(value) {
187
+ const object = record(value, "check");
188
+ const details = checkDetails(object, "name");
189
+ const state = string(object.state, "check.state").toUpperCase();
190
+ const bucket = string(object.bucket, "check.bucket");
191
+ if (state === "ACTION_REQUIRED") return gateOr("failed", details, state);
192
+ if (bucket === "fail" || ["FAILURE", "ERROR"].includes(state)) return {
193
+ ...details,
194
+ kind: "failed",
195
+ reportedState: state
196
+ };
197
+ if (bucket === "pending") return gateOr("pending", details, state);
198
+ if (bucket === "pass") return {
199
+ ...details,
200
+ kind: "passed",
201
+ reportedState: state
202
+ };
203
+ if (bucket === "skipping") return {
204
+ ...details,
205
+ kind: "skipped",
206
+ reportedState: state
207
+ };
208
+ return {
209
+ ...details,
210
+ kind: "failed",
211
+ reportedState: state
212
+ };
213
+ }
214
+ function gateOr(kind, details, reportedState) {
215
+ return details.name === "Code Review Gate" ? {
216
+ ...details,
217
+ kind: "code-review-gate",
218
+ name: "Code Review Gate",
219
+ reportedState
220
+ } : {
221
+ ...details,
222
+ kind,
223
+ reportedState
224
+ };
225
+ }
226
+ function mapRollupNode(value) {
227
+ const object = record(value, "rollup node");
228
+ const typename = object.__typename;
229
+ if (typename !== "CheckRun" && typename !== "StatusContext") return null;
230
+ const details = checkDetails(object, typename === "CheckRun" ? "name" : "context");
231
+ const link = typeof object.targetUrl === "string" ? object.targetUrl : details.link;
232
+ if (typename === "CheckRun") {
233
+ const status = typeof object.status === "string" ? object.status.toUpperCase() : "";
234
+ const conclusion = typeof object.conclusion === "string" ? object.conclusion.toUpperCase() : "";
235
+ if (status !== "COMPLETED") return gateOr("pending", {
236
+ ...details,
237
+ link
238
+ }, "PENDING");
239
+ if (conclusion === "SUCCESS") return {
240
+ ...details,
241
+ link,
242
+ kind: "passed",
243
+ reportedState: "SUCCESS"
244
+ };
245
+ if (conclusion === "NEUTRAL" || conclusion === "SKIPPED") return {
246
+ ...details,
247
+ link,
248
+ kind: "skipped",
249
+ reportedState: conclusion
250
+ };
251
+ if (conclusion === "ACTION_REQUIRED") return gateOr("failed", {
252
+ ...details,
253
+ link
254
+ }, conclusion);
255
+ return {
256
+ ...details,
257
+ link,
258
+ kind: "failed",
259
+ reportedState: "FAILURE"
260
+ };
261
+ }
262
+ const state = typeof object.state === "string" ? object.state.toUpperCase() : "";
263
+ if (state === "PENDING" || state === "EXPECTED") return gateOr("pending", {
264
+ ...details,
265
+ link
266
+ }, "PENDING");
267
+ return state === "SUCCESS" ? {
268
+ ...details,
269
+ link,
270
+ kind: "passed",
271
+ reportedState: state
272
+ } : {
273
+ ...details,
274
+ link,
275
+ kind: "failed",
276
+ reportedState: state || "FAILURE"
277
+ };
278
+ }
279
+ function parseComment(value) {
280
+ const object = record(value, "review comment");
281
+ const author = object.author === null ? null : record(object.author, "review comment.author");
282
+ return {
283
+ authorLogin: author === null ? null : optionalString(author.login, "review comment.author.login"),
284
+ body: string(object.body, "review comment.body"),
285
+ path: optionalString(object.path, "review comment.path"),
286
+ line: object.line === null ? null : Number.isInteger(object.line) ? Number(object.line) : missing("review comment.line", object.line),
287
+ createdAt: string(object.createdAt, "review comment.createdAt")
288
+ };
289
+ }
290
+ function isBugbot(comment) {
291
+ if (comment === null) return false;
292
+ const author = (comment.authorLogin ?? "").toLowerCase();
293
+ const body = comment.body.toLowerCase();
294
+ return author.includes("bugbot") || author === "cursor" && [
295
+ "bugbot",
296
+ "cursor_automation_id",
297
+ "agentic security review",
298
+ "description start",
299
+ "severity"
300
+ ].some((token) => body.includes(token));
301
+ }
302
+ function passKey(comment) {
303
+ if (comment === null) return null;
304
+ for (const pattern of [/RUN_ID:\s*([a-zA-Z0-9_.:-]+)/, /CURSOR_AUTOMATION_ID:\s*([a-zA-Z0-9_.:-]+)/]) {
305
+ const match = pattern.exec(comment.body);
306
+ if (match?.[1]) return match[1];
307
+ }
308
+ return null;
309
+ }
310
+ function parseReviewThreadPage(value) {
311
+ const reviewThreads = record(at(value, [
312
+ "data",
313
+ "repository",
314
+ "pullRequest",
315
+ "reviewThreads"
316
+ ]), "reviewThreads");
317
+ const nodes = list(reviewThreads.nodes, "reviewThreads.nodes");
318
+ const threads = [];
319
+ for (const node of nodes) {
320
+ const thread = record(node, "review thread");
321
+ if (typeof thread.isResolved !== "boolean") missing("review thread.isResolved", thread.isResolved);
322
+ const comments = list(at(thread, ["comments", "nodes"]), "review thread.comments.nodes");
323
+ threads.push({
324
+ id: string(thread.id, "review thread.id"),
325
+ firstComment: comments.length === 0 ? null : parseComment(comments[0]),
326
+ resolved: thread.isResolved
327
+ });
328
+ }
329
+ const page = record(reviewThreads.pageInfo, "reviewThreads.pageInfo");
330
+ if (typeof page.hasNextPage !== "boolean") missing("reviewThreads.pageInfo.hasNextPage", page.hasNextPage);
331
+ const cursor = optionalString(page.endCursor, "reviewThreads.pageInfo.endCursor");
332
+ return {
333
+ threads,
334
+ endCursor: page.hasNextPage && cursor ? cursor : null
335
+ };
336
+ }
337
+ function buildReviewThreads(threads) {
338
+ const keys = /* @__PURE__ */ new Set();
339
+ let keyless = false;
340
+ for (const thread of threads) {
341
+ if (!isBugbot(thread.firstComment)) continue;
342
+ const key = passKey(thread.firstComment);
343
+ if (key === null) keyless = true;
344
+ else keys.add(key);
345
+ }
346
+ const passes = keys.size > 0 ? keys.size : keyless ? 1 : 0;
347
+ return threads.filter((thread) => !thread.resolved).map(({ id, firstComment }) => ({
348
+ id,
349
+ firstComment,
350
+ isBugbot: isBugbot(firstComment),
351
+ bugbotReviewPasses: passes
352
+ }));
353
+ }
354
+ function parsePullRequest(value, context) {
355
+ const object = record(value, "pull request");
356
+ if (typeof object.isDraft !== "boolean") missing("pull request.isDraft", object.isDraft);
357
+ return {
358
+ context,
359
+ mergeable: enumValue(object.mergeable, [
360
+ "MERGEABLE",
361
+ "CONFLICTING",
362
+ "UNKNOWN"
363
+ ], "pull request.mergeable"),
364
+ mergeStateStatus: enumValue(object.mergeStateStatus, MERGE_STATES, "pull request.mergeStateStatus"),
365
+ reviewDecision: reviewDecision(object.reviewDecision),
366
+ headRefOid: optionalString(object.headRefOid, "pull request.headRefOid"),
367
+ headRefName: string(object.headRefName, "pull request.headRefName"),
368
+ baseRefName: string(object.baseRefName, "pull request.baseRefName"),
369
+ state: enumValue(object.state, [
370
+ "OPEN",
371
+ "CLOSED",
372
+ "MERGED"
373
+ ], "pull request.state"),
374
+ mergedAt: optionalString(object.mergedAt, "pull request.mergedAt"),
375
+ isDraft: object.isDraft
376
+ };
377
+ }
378
+ function graphqlArgs(query, context) {
379
+ return [
380
+ "gh",
381
+ "api",
382
+ "graphql",
383
+ "-f",
384
+ `query=${query}`,
385
+ "-f",
386
+ `owner=${context.owner}`,
387
+ "-f",
388
+ `repo=${context.repo}`,
389
+ "-F",
390
+ `pr=${context.number}`
391
+ ];
392
+ }
393
+ var GhGitHubReader = class {
394
+ async originRepo() {
395
+ const result = await run([
396
+ "git",
397
+ "remote",
398
+ "get-url",
399
+ "origin"
400
+ ]);
401
+ return result.code === 0 ? parseRemote(result.stdout) : null;
402
+ }
403
+ async currentPr(pr) {
404
+ const argv = [
405
+ "gh",
406
+ "pr",
407
+ "view"
408
+ ];
409
+ if (pr !== null) argv.push(String(pr));
410
+ argv.push("--json", "number,url");
411
+ const object = record(await runJson(argv), "current PR");
412
+ return {
413
+ ...parsePrUrl(string(object.url, "current PR.url")),
414
+ number: pr ?? parsePrNumber(object.number, "current PR.number")
415
+ };
416
+ }
417
+ async pullRequest(context) {
418
+ return parsePullRequest(await runJson([
419
+ "gh",
420
+ "pr",
421
+ "view",
422
+ String(context.number),
423
+ "--repo",
424
+ `${context.owner}/${context.repo}`,
425
+ "--json",
426
+ "mergeable,mergeStateStatus,reviewDecision,headRefOid,headRefName,baseRefName,state,mergedAt,isDraft"
427
+ ]), context);
428
+ }
429
+ async openPullRequests(repository) {
430
+ return list(await runJson([
431
+ "gh",
432
+ "pr",
433
+ "list",
434
+ "--repo",
435
+ `${repository.owner}/${repository.repo}`,
436
+ "--state",
437
+ "open",
438
+ "--limit",
439
+ "300",
440
+ "--json",
441
+ "number,headRefName,baseRefName,isCrossRepository"
442
+ ]), "open PRs").map((item, index) => {
443
+ const object = record(item, `open PRs[${index}]`);
444
+ if (typeof object.isCrossRepository !== "boolean") missing(`open PRs[${index}].isCrossRepository`, object.isCrossRepository);
445
+ return {
446
+ isCrossRepository: object.isCrossRepository,
447
+ number: parsePrNumber(object.number, `open PRs[${index}].number`),
448
+ headRefName: string(object.headRefName, `open PRs[${index}].headRefName`),
449
+ baseRefName: string(object.baseRefName, `open PRs[${index}].baseRefName`)
450
+ };
451
+ });
452
+ }
453
+ async checksFastPath(context) {
454
+ const result = await run([
455
+ "gh",
456
+ "pr",
457
+ "checks",
458
+ String(context.number),
459
+ "--repo",
460
+ `${context.owner}/${context.repo}`,
461
+ "--json",
462
+ "name,state,description,link,workflow,bucket"
463
+ ]);
464
+ if ([
465
+ 0,
466
+ 1,
467
+ 8
468
+ ].includes(result.code) && result.stdout.trim()) try {
469
+ const value = parseJson(result.stdout, "gh pr checks");
470
+ if (Array.isArray(value)) return {
471
+ kind: "checks",
472
+ checks: value.map(parseFastCheck)
473
+ };
474
+ } catch (error) {
475
+ if (!(error instanceof WatcherQueryError)) throw error;
476
+ }
477
+ return {
478
+ kind: "unusable",
479
+ exitCode: result.code,
480
+ stderr: result.stderr
481
+ };
482
+ }
483
+ async checkRollupPage(context, after) {
484
+ const argv = graphqlArgs(PR_CHECK_ROLLUP_QUERY, context);
485
+ if (after !== null) argv.push("-f", `after=${after}`);
486
+ const commits = list(at(await runJson(argv), [
487
+ "data",
488
+ "repository",
489
+ "pullRequest",
490
+ "commits",
491
+ "nodes"
492
+ ]), "commits.nodes");
493
+ if (commits.length === 0) return {
494
+ checks: [],
495
+ endCursor: null
496
+ };
497
+ const commit = record(at(commits[commits.length - 1], ["commit"]), "commit");
498
+ if (commit.statusCheckRollup === null) return {
499
+ checks: [],
500
+ endCursor: null
501
+ };
502
+ const contexts = record(at(commit, ["statusCheckRollup", "contexts"]), "contexts");
503
+ const checks = list(contexts.nodes, "contexts.nodes").map(mapRollupNode).filter((check) => check !== null);
504
+ const page = record(contexts.pageInfo, "contexts.pageInfo");
505
+ if (typeof page.hasNextPage !== "boolean") missing("contexts.pageInfo.hasNextPage", page.hasNextPage);
506
+ const cursor = optionalString(page.endCursor, "contexts.pageInfo.endCursor");
507
+ return {
508
+ checks,
509
+ endCursor: page.hasNextPage && cursor ? cursor : null
510
+ };
511
+ }
512
+ async reviewThreadPage(context, after) {
513
+ const argv = graphqlArgs(REVIEW_THREADS_QUERY, context);
514
+ if (after !== null) argv.push("-f", `after=${after}`);
515
+ return parseReviewThreadPage(await runJson(argv));
516
+ }
517
+ async commitRollups(context) {
518
+ return list(at(await runJson(graphqlArgs(PR_COMMIT_STATUS_QUERY, context)), [
519
+ "data",
520
+ "repository",
521
+ "pullRequest",
522
+ "commits",
523
+ "nodes"
524
+ ]), "commits.nodes").map((item, index) => {
525
+ const commit = record(at(item, ["commit"]), `commits[${index}].commit`);
526
+ const rollup = commit.statusCheckRollup;
527
+ return {
528
+ oid: string(commit.oid, `commits[${index}].oid`),
529
+ state: rollup === null ? null : nullableEnum(at(rollup, ["state"]), ROLLUP_STATES, `commits[${index}].statusCheckRollup.state`)
530
+ };
531
+ });
532
+ }
533
+ };
534
+ async function resolveChecks(reader, context) {
535
+ const fast = await reader.checksFastPath(context);
536
+ const direct = fast.kind === "checks" ? nonEmpty(fast.checks) : null;
537
+ if (direct !== null) return {
538
+ source: "gh-pr-checks",
539
+ checks: direct
540
+ };
541
+ const checks = [];
542
+ let after = null;
543
+ do {
544
+ const page = await reader.checkRollupPage(context, after);
545
+ checks.push(...page.checks);
546
+ after = page.endCursor;
547
+ } while (after !== null);
548
+ const fallback = nonEmpty(checks);
549
+ if (fallback !== null) return {
550
+ source: "graphql-rollup",
551
+ checks: fallback
552
+ };
553
+ throw new ChecksUnavailable(`could not read PR checks: ${fast.kind === "unusable" ? `fast path exit=${fast.exitCode}; GraphQL rollup was empty${firstLine(fast.stderr) ? `; ${firstLine(fast.stderr)}` : ""}` : "fast path and GraphQL rollup were empty"}`);
554
+ }
555
+ async function resolveReviewThreads(reader, context) {
556
+ const threads = [];
557
+ let after = null;
558
+ do {
559
+ const page = await reader.reviewThreadPage(context, after);
560
+ threads.push(...page.threads);
561
+ after = page.endCursor;
562
+ } while (after !== null);
563
+ return buildReviewThreads(threads);
564
+ }
565
+ async function resolveContext(args) {
566
+ if (args.pr !== null && args.owner !== null && args.repo !== null) return {
567
+ owner: args.owner,
568
+ repo: args.repo,
569
+ number: args.pr
570
+ };
571
+ if (args.pr !== null) {
572
+ const origin = await args.reader.originRepo();
573
+ if (origin !== null) return {
574
+ owner: args.owner ?? origin.owner,
575
+ repo: args.repo ?? origin.repo,
576
+ number: args.pr
577
+ };
578
+ }
579
+ const inferred = await args.reader.currentPr(args.pr);
580
+ return {
581
+ owner: args.owner ?? inferred.owner,
582
+ repo: args.repo ?? inferred.repo,
583
+ number: args.pr ?? inferred.number
584
+ };
585
+ }
586
+ function orderStack(context, open) {
587
+ const byNumber = new Map(open.map((pr) => [pr.number, pr]));
588
+ const byHead = new Map(open.filter((pr) => !pr.isCrossRepository).map((pr) => [pr.headRefName, pr]));
589
+ const children = /* @__PURE__ */ new Map();
590
+ for (const pr of open) children.set(pr.baseRefName, [...children.get(pr.baseRefName) ?? [], pr]);
591
+ for (const values of children.values()) values.sort((a, b) => a.number - b.number);
592
+ const start = byNumber.get(context.number);
593
+ if (start === void 0) return [context];
594
+ const down = [];
595
+ let current = start;
596
+ while (byHead.has(current.baseRefName)) {
597
+ const parent = byHead.get(current.baseRefName);
598
+ if (parent === void 0) break;
599
+ down.push(parent);
600
+ current = parent;
601
+ }
602
+ const seen = /* @__PURE__ */ new Set([...down.map((pr) => pr.number), start.number]);
603
+ const up = [];
604
+ const visit = (parent) => {
605
+ if (parent.isCrossRepository) return;
606
+ for (const child of children.get(parent.headRefName) ?? []) {
607
+ if (seen.has(child.number)) continue;
608
+ seen.add(child.number);
609
+ up.push(child);
610
+ visit(child);
611
+ }
612
+ };
613
+ visit(start);
614
+ return nonEmpty([
615
+ ...down.reverse(),
616
+ start,
617
+ ...up
618
+ ].map((pr) => ({
619
+ ...context,
620
+ number: pr.number
621
+ }))) ?? [context];
622
+ }
623
+ async function discoverStack(reader, context) {
624
+ return orderStack(context, await reader.openPullRequests(context));
625
+ }
626
+ export { ChecksUnavailable, GhGitHubReader, PR_CHECK_ROLLUP_QUERY, PR_COMMIT_STATUS_QUERY, REVIEW_THREADS_QUERY, WatcherQueryError, buildReviewThreads, discoverStack, mapRollupNode, orderStack, parseFastCheck, parsePullRequest, parseReviewThreadPage, resolveChecks, resolveContext, resolveReviewThreads };