cloving 1.1.0 → 1.3.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 (568) hide show
  1. package/README.md +584 -144
  2. package/assets/watch-fonts/fira-code-OFL.md +93 -0
  3. package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
  4. package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
  5. package/assets/watch-fonts/heebo-OFL.md +93 -0
  6. package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
  7. package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
  8. package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
  9. package/assets/watch-fonts/manifest.json +112 -0
  10. package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
  11. package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  12. package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  13. package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
  14. package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  15. package/dist/src/agent-harness-shell.d.ts +12 -0
  16. package/dist/src/agent-harness-shell.js +90 -0
  17. package/dist/src/agent-harness-versions.d.ts +8 -0
  18. package/dist/src/agent-harness-versions.js +49 -0
  19. package/dist/src/agent-harnesses.d.ts +4 -0
  20. package/dist/src/agent-harnesses.js +13 -0
  21. package/dist/src/authority/commands.d.ts +2 -0
  22. package/dist/src/authority/commands.js +49 -8
  23. package/dist/src/authority/dispatch-decision.d.ts +1 -0
  24. package/dist/src/authority/dispatch-decision.js +7 -4
  25. package/dist/src/authority/events.js +2 -2
  26. package/dist/src/authority/gate-reduction.d.ts +1 -0
  27. package/dist/src/authority/gate-reduction.js +18 -3
  28. package/dist/src/authority/gates.d.ts +2 -1
  29. package/dist/src/authority/gates.js +5 -1
  30. package/dist/src/authority/handoff-chain.d.ts +24 -0
  31. package/dist/src/authority/handoff-chain.js +46 -0
  32. package/dist/src/authority/operations.js +1 -1
  33. package/dist/src/authority/reconciliation.d.ts +1 -0
  34. package/dist/src/authority/reconciliation.js +18 -11
  35. package/dist/src/authority/reduction.d.ts +1 -1
  36. package/dist/src/authority/reduction.js +6 -1
  37. package/dist/src/authority/status-input.d.ts +1 -1
  38. package/dist/src/authority/status.d.ts +1 -0
  39. package/dist/src/authority/status.js +27 -3
  40. package/dist/src/authority/transitions.d.ts +5 -5
  41. package/dist/src/authority/transitions.js +9 -0
  42. package/dist/src/broker/actor/authority-delivery.js +1 -0
  43. package/dist/src/broker/actor/authority-queries.d.ts +11 -1
  44. package/dist/src/broker/actor/authority-queries.js +67 -3
  45. package/dist/src/broker/actor/authority-receipts.js +11 -1
  46. package/dist/src/broker/actor/authority-session.js +2 -2
  47. package/dist/src/broker/actor/authority-settings.js +4 -0
  48. package/dist/src/broker/actor/delivery-intents.d.ts +3 -1
  49. package/dist/src/broker/actor/delivery-intents.js +4 -4
  50. package/dist/src/broker/actor/effect-delivery.js +13 -1
  51. package/dist/src/broker/actor/effect-queries.d.ts +1 -0
  52. package/dist/src/broker/actor/effect-queries.js +7 -0
  53. package/dist/src/broker/actor/pin-check.js +1 -1
  54. package/dist/src/broker/actor/stop-plan.js +1 -1
  55. package/dist/src/broker/actor/turn-state.js +1 -1
  56. package/dist/src/broker/authority-admission.js +26 -5
  57. package/dist/src/broker/authority-restore.js +1 -0
  58. package/dist/src/broker/decision-restore.js +4 -4
  59. package/dist/src/broker/socket-address.d.ts +3 -1
  60. package/dist/src/broker/socket-address.js +2 -2
  61. package/dist/src/cli/arguments.d.ts +11 -13
  62. package/dist/src/cli/arguments.js +37 -107
  63. package/dist/src/cli/command-effects.d.ts +7 -0
  64. package/dist/src/cli/command-effects.js +39 -0
  65. package/dist/src/cli/commands.js +11 -4
  66. package/dist/src/cli/config-arguments.d.ts +11 -0
  67. package/dist/src/cli/config-arguments.js +59 -0
  68. package/dist/src/cli/config-command.d.ts +2 -0
  69. package/dist/src/cli/config-command.js +105 -0
  70. package/dist/src/cli/config-file.d.ts +3 -0
  71. package/dist/src/cli/config-file.js +50 -0
  72. package/dist/src/cli/config-lock.d.ts +7 -0
  73. package/dist/src/cli/config-lock.js +61 -0
  74. package/dist/src/cli/config-notice.d.ts +5 -0
  75. package/dist/src/cli/config-notice.js +46 -0
  76. package/dist/src/cli/doctor-github.d.ts +9 -0
  77. package/dist/src/cli/doctor-github.js +138 -0
  78. package/dist/src/cli/doctor-harness.d.ts +13 -0
  79. package/dist/src/cli/doctor-harness.js +242 -0
  80. package/dist/src/cli/doctor-local.d.ts +18 -0
  81. package/dist/src/cli/doctor-local.js +77 -0
  82. package/dist/src/cli/doctor-runtime.d.ts +15 -0
  83. package/dist/src/cli/doctor-runtime.js +176 -0
  84. package/dist/src/cli/doctor-service.d.ts +1 -0
  85. package/dist/src/cli/doctor-service.js +11 -0
  86. package/dist/src/cli/doctor-workflows.d.ts +3 -0
  87. package/dist/src/cli/doctor-workflows.js +45 -0
  88. package/dist/src/cli/doctor.d.ts +15 -0
  89. package/dist/src/cli/doctor.js +190 -0
  90. package/dist/src/cli/github-ci-progress.d.ts +8 -0
  91. package/dist/src/cli/github-ci-progress.js +83 -0
  92. package/dist/src/cli/github-retry.d.ts +6 -0
  93. package/dist/src/cli/github-retry.js +47 -0
  94. package/dist/src/cli/harness-probes.d.ts +22 -0
  95. package/dist/src/cli/harness-probes.js +183 -0
  96. package/dist/src/cli/main.d.ts +7 -1
  97. package/dist/src/cli/main.js +39 -61
  98. package/dist/src/cli/phone-arguments.d.ts +14 -0
  99. package/dist/src/cli/phone-arguments.js +37 -0
  100. package/dist/src/cli/phone-client.d.ts +2 -0
  101. package/dist/src/cli/phone-client.js +32 -0
  102. package/dist/src/cli/phone-command.d.ts +13 -0
  103. package/dist/src/cli/phone-command.js +101 -0
  104. package/dist/src/cli/probe-command.d.ts +36 -0
  105. package/dist/src/cli/probe-command.js +59 -0
  106. package/dist/src/cli/project-settings.d.ts +4 -0
  107. package/dist/src/cli/project-settings.js +33 -0
  108. package/dist/src/cli/render.d.ts +3 -1
  109. package/dist/src/cli/render.js +102 -39
  110. package/dist/src/cli/report-github.d.ts +18 -0
  111. package/dist/src/cli/report-github.js +200 -0
  112. package/dist/src/cli/report.d.ts +17 -0
  113. package/dist/src/cli/report.js +192 -0
  114. package/dist/src/cli/repository-arguments.d.ts +5 -0
  115. package/dist/src/cli/repository-arguments.js +34 -0
  116. package/dist/src/cli/runtime-arguments.d.ts +4 -0
  117. package/dist/src/cli/runtime-arguments.js +15 -0
  118. package/dist/src/cli/runtime-directory.d.ts +6 -2
  119. package/dist/src/cli/runtime-directory.js +72 -14
  120. package/dist/src/cli/toolchain.d.ts +2 -0
  121. package/dist/src/cli/toolchain.js +22 -2
  122. package/dist/src/cli/usage-render.d.ts +5 -0
  123. package/dist/src/cli/usage-render.js +40 -1
  124. package/dist/src/cli/usage.d.ts +3 -3
  125. package/dist/src/cli/usage.js +74 -45
  126. package/dist/src/cli/watch-actions.d.ts +2 -0
  127. package/dist/src/cli/watch-actions.js +4 -4
  128. package/dist/src/cli/watch-board-view.d.ts +12 -1
  129. package/dist/src/cli/watch-board-view.js +64 -12
  130. package/dist/src/cli/watch-board.d.ts +7 -1
  131. package/dist/src/cli/watch-board.js +61 -16
  132. package/dist/src/cli/watch-card-forms.js +2 -2
  133. package/dist/src/cli/watch-client.d.ts +1 -1
  134. package/dist/src/cli/watch-client.js +12 -3
  135. package/dist/src/cli/watch-header-view.d.ts +27 -0
  136. package/dist/src/cli/watch-header-view.js +116 -0
  137. package/dist/src/cli/watch-model.d.ts +10 -4
  138. package/dist/src/cli/watch-model.js +49 -59
  139. package/dist/src/cli/watch-page.js +67 -14
  140. package/dist/src/cli/watch-phases.js +3 -3
  141. package/dist/src/cli/watch-phone-client.d.ts +1 -0
  142. package/dist/src/cli/watch-phone-client.js +84 -0
  143. package/dist/src/cli/watch-phone-view.d.ts +56 -0
  144. package/dist/src/cli/watch-phone-view.js +113 -0
  145. package/dist/src/cli/watch-phone.d.ts +5 -0
  146. package/dist/src/cli/watch-phone.js +53 -0
  147. package/dist/src/cli/watch-pr-command.d.ts +5 -2
  148. package/dist/src/cli/watch-pr-command.js +41 -4
  149. package/dist/src/cli/watch-pr-identity.d.ts +14 -2
  150. package/dist/src/cli/watch-pr-identity.js +25 -0
  151. package/dist/src/cli/watch-pr-observer.d.ts +1 -0
  152. package/dist/src/cli/watch-pr-observer.js +48 -6
  153. package/dist/src/cli/watch-pull-request.d.ts +12 -0
  154. package/dist/src/cli/watch-pull-request.js +134 -0
  155. package/dist/src/cli/watch-reads.d.ts +7 -1
  156. package/dist/src/cli/watch-reads.js +42 -20
  157. package/dist/src/cli/watch-render.d.ts +23 -2
  158. package/dist/src/cli/watch-render.js +2 -1
  159. package/dist/src/cli/watch-server.js +56 -7
  160. package/dist/src/cli/watch-turn.d.ts +4 -1
  161. package/dist/src/cli/watch-turn.js +38 -2
  162. package/dist/src/cli/watch-usage.js +5 -1
  163. package/dist/src/cli/watch-view.d.ts +10 -17
  164. package/dist/src/cli/watch-view.js +33 -77
  165. package/dist/src/cli.js +106 -23
  166. package/dist/src/command-settings.d.ts +16 -0
  167. package/dist/src/command-settings.js +42 -0
  168. package/dist/src/configuration-change.d.ts +11 -0
  169. package/dist/src/configuration-change.js +62 -0
  170. package/dist/src/configuration-display.d.ts +21 -0
  171. package/dist/src/configuration-display.js +69 -0
  172. package/dist/src/configuration-schema.d.ts +49 -0
  173. package/dist/src/configuration-schema.js +159 -0
  174. package/dist/src/daemon/claude-turn.d.ts +20 -5
  175. package/dist/src/daemon/claude-turn.js +116 -53
  176. package/dist/src/daemon/claude-worker.d.ts +3 -5
  177. package/dist/src/daemon/claude-worker.js +64 -80
  178. package/dist/src/daemon/command-journal.d.ts +5 -0
  179. package/dist/src/daemon/command-journal.js +50 -0
  180. package/dist/src/daemon/command-process.d.ts +28 -0
  181. package/dist/src/daemon/command-process.js +164 -0
  182. package/dist/src/daemon/command-worker.d.ts +19 -0
  183. package/dist/src/daemon/command-worker.js +182 -0
  184. package/dist/src/daemon/cursor-stream.d.ts +4 -0
  185. package/dist/src/daemon/cursor-stream.js +154 -0
  186. package/dist/src/daemon/daemon-adapters.d.ts +58 -0
  187. package/dist/src/daemon/daemon-adapters.js +102 -0
  188. package/dist/src/daemon/daemon-loops.d.ts +14 -0
  189. package/dist/src/daemon/daemon-loops.js +39 -0
  190. package/dist/src/daemon/daemon.d.ts +3 -30
  191. package/dist/src/daemon/daemon.js +132 -110
  192. package/dist/src/daemon/declared-input.d.ts +3 -0
  193. package/dist/src/daemon/declared-input.js +9 -0
  194. package/dist/src/daemon/delivery-router.js +7 -1
  195. package/dist/src/daemon/gemini-stream.d.ts +4 -0
  196. package/dist/src/daemon/gemini-stream.js +129 -0
  197. package/dist/src/daemon/github-calls.d.ts +4 -0
  198. package/dist/src/daemon/github-calls.js +16 -7
  199. package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
  200. package/dist/src/daemon/github-ci-rerun.js +92 -0
  201. package/dist/src/daemon/github-ci.d.ts +6 -0
  202. package/dist/src/daemon/github-ci.js +251 -0
  203. package/dist/src/daemon/github-merge-call.d.ts +16 -0
  204. package/dist/src/daemon/github-merge-call.js +73 -0
  205. package/dist/src/daemon/github-merge.d.ts +3 -5
  206. package/dist/src/daemon/github-merge.js +59 -98
  207. package/dist/src/daemon/github-methods.d.ts +28 -0
  208. package/dist/src/daemon/github-methods.js +90 -16
  209. package/dist/src/daemon/github-operation.d.ts +3 -0
  210. package/dist/src/daemon/github-retry.d.ts +6 -0
  211. package/dist/src/daemon/github-retry.js +13 -0
  212. package/dist/src/daemon/github-ticket-status.js +27 -1
  213. package/dist/src/daemon/github-worker.js +2 -1
  214. package/dist/src/daemon/handoff-worker.d.ts +10 -0
  215. package/dist/src/daemon/handoff-worker.js +232 -0
  216. package/dist/src/daemon/issue-queue.d.ts +2 -0
  217. package/dist/src/daemon/issue-queue.js +92 -63
  218. package/dist/src/daemon/notify-journal.d.ts +18 -0
  219. package/dist/src/daemon/notify-journal.js +108 -0
  220. package/dist/src/daemon/notify-message.js +2 -1
  221. package/dist/src/daemon/notify.js +177 -37
  222. package/dist/src/daemon/opencode-stream.d.ts +5 -0
  223. package/dist/src/daemon/opencode-stream.js +87 -0
  224. package/dist/src/daemon/queue-status.d.ts +4 -0
  225. package/dist/src/daemon/queue-status.js +38 -0
  226. package/dist/src/daemon/retry-worktree.d.ts +18 -0
  227. package/dist/src/daemon/retry-worktree.js +139 -0
  228. package/dist/src/daemon/retrying-turn.d.ts +5 -0
  229. package/dist/src/daemon/retrying-turn.js +145 -21
  230. package/dist/src/daemon/schedule-journal.d.ts +19 -0
  231. package/dist/src/daemon/schedule-journal.js +57 -0
  232. package/dist/src/daemon/text-output.d.ts +18 -0
  233. package/dist/src/daemon/text-output.js +44 -0
  234. package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
  235. package/dist/src/daemon/ticket-dependency-waits.js +60 -0
  236. package/dist/src/daemon/ticket-registration.d.ts +10 -8
  237. package/dist/src/daemon/ticket-registration.js +146 -47
  238. package/dist/src/daemon/ticket-source.d.ts +4 -1
  239. package/dist/src/daemon/ticket-source.js +8 -2
  240. package/dist/src/daemon/turn-command.d.ts +10 -0
  241. package/dist/src/daemon/turn-command.js +33 -0
  242. package/dist/src/daemon/turn-report.d.ts +18 -0
  243. package/dist/src/daemon/turn-report.js +79 -0
  244. package/dist/src/daemon/work-tree.d.ts +2 -1
  245. package/dist/src/daemon/work-tree.js +15 -12
  246. package/dist/src/daemon/workflow-generations.d.ts +32 -0
  247. package/dist/src/daemon/workflow-generations.js +57 -0
  248. package/dist/src/daemon/workflow-replay.d.ts +16 -0
  249. package/dist/src/daemon/workflow-replay.js +58 -0
  250. package/dist/src/daemon/workflow-schedules.d.ts +27 -0
  251. package/dist/src/daemon/workflow-schedules.js +185 -0
  252. package/dist/src/decision-visibility.d.ts +2 -0
  253. package/dist/src/decision-visibility.js +10 -0
  254. package/dist/src/decision-wait.d.ts +1 -0
  255. package/dist/src/decision-wait.js +3 -0
  256. package/dist/src/delivery-backoff.d.ts +1 -0
  257. package/dist/src/delivery-backoff.js +3 -0
  258. package/dist/src/doctor-report.d.ts +24 -0
  259. package/dist/src/doctor-report.js +70 -0
  260. package/dist/src/execution-pin.d.ts +9 -0
  261. package/dist/src/execution-pin.js +86 -2
  262. package/dist/src/grok-result.d.ts +12 -0
  263. package/dist/src/grok-result.js +61 -0
  264. package/dist/src/harness-defaults.d.ts +35 -0
  265. package/dist/src/harness-defaults.js +121 -0
  266. package/dist/src/host/decision-resume.d.ts +35 -0
  267. package/dist/src/host/decision-resume.js +86 -0
  268. package/dist/src/host/gate-bridge.d.ts +48 -0
  269. package/dist/src/host/gate-bridge.js +124 -0
  270. package/dist/src/host/run-wait.d.ts +26 -0
  271. package/dist/src/host/run-wait.js +37 -0
  272. package/dist/src/host/start-delivery.d.ts +3 -2
  273. package/dist/src/host/start-delivery.js +11 -4
  274. package/dist/src/host/step-bridge-host.d.ts +6 -19
  275. package/dist/src/host/step-bridge-host.js +57 -55
  276. package/dist/src/host/world-reconciliation.d.ts +1 -0
  277. package/dist/src/host/world-reconciliation.js +3 -0
  278. package/dist/src/host/world-runs.js +5 -0
  279. package/dist/src/issue-identity.d.ts +6 -0
  280. package/dist/src/issue-identity.js +23 -0
  281. package/dist/src/merge-request.d.ts +19 -0
  282. package/dist/src/merge-request.js +32 -0
  283. package/dist/src/phone/canonical-json.d.ts +1 -0
  284. package/dist/src/phone/canonical-json.js +16 -0
  285. package/dist/src/phone/phone-link.d.ts +7 -0
  286. package/dist/src/phone/phone-link.js +21 -0
  287. package/dist/src/phone/qr-data.d.ts +8 -0
  288. package/dist/src/phone/qr-data.js +133 -0
  289. package/dist/src/phone/qr-matrix.d.ts +6 -0
  290. package/dist/src/phone/qr-matrix.js +175 -0
  291. package/dist/src/phone/qr-penalty.d.ts +3 -0
  292. package/dist/src/phone/qr-penalty.js +67 -0
  293. package/dist/src/phone/qr-picture.d.ts +5 -0
  294. package/dist/src/phone/qr-picture.js +24 -0
  295. package/dist/src/private-config.schema.json +263 -0
  296. package/dist/src/project-config.schema.json +65 -0
  297. package/dist/src/project-settings.d.ts +19 -0
  298. package/dist/src/project-settings.js +131 -0
  299. package/dist/src/relay/answer-check.d.ts +24 -0
  300. package/dist/src/relay/answer-check.js +145 -0
  301. package/dist/src/relay/answer-inbox.d.ts +15 -0
  302. package/dist/src/relay/answer-inbox.js +173 -0
  303. package/dist/src/relay/daemon-keys.d.ts +16 -0
  304. package/dist/src/relay/daemon-keys.js +75 -0
  305. package/dist/src/relay/decision-check.d.ts +3 -0
  306. package/dist/src/relay/decision-check.js +77 -0
  307. package/dist/src/relay/decision-close.d.ts +6 -0
  308. package/dist/src/relay/decision-close.js +72 -0
  309. package/dist/src/relay/decision-envelopes.d.ts +29 -0
  310. package/dist/src/relay/decision-envelopes.js +93 -0
  311. package/dist/src/relay/decision-watch.d.ts +14 -0
  312. package/dist/src/relay/decision-watch.js +68 -0
  313. package/dist/src/relay/envelope-post.d.ts +8 -0
  314. package/dist/src/relay/envelope-post.js +71 -0
  315. package/dist/src/relay/envelope.d.ts +28 -0
  316. package/dist/src/relay/envelope.js +53 -0
  317. package/dist/src/relay/hpke.d.ts +25 -0
  318. package/dist/src/relay/hpke.js +108 -0
  319. package/dist/src/relay/pairing-checks.d.ts +42 -0
  320. package/dist/src/relay/pairing-checks.js +172 -0
  321. package/dist/src/relay/pairing-follow.d.ts +8 -0
  322. package/dist/src/relay/pairing-follow.js +95 -0
  323. package/dist/src/relay/pairing-session.d.ts +29 -0
  324. package/dist/src/relay/pairing-session.js +87 -0
  325. package/dist/src/relay/phone-delivery.d.ts +51 -0
  326. package/dist/src/relay/phone-delivery.js +139 -0
  327. package/dist/src/relay/phone-devices.d.ts +36 -0
  328. package/dist/src/relay/phone-devices.js +46 -0
  329. package/dist/src/relay/phone-inbox.d.ts +18 -0
  330. package/dist/src/relay/phone-inbox.js +17 -0
  331. package/dist/src/relay/phone-operations.d.ts +18 -0
  332. package/dist/src/relay/phone-operations.js +121 -0
  333. package/dist/src/relay/phone-outbox.d.ts +21 -0
  334. package/dist/src/relay/phone-outbox.js +25 -0
  335. package/dist/src/relay/phone-socket.d.ts +6 -0
  336. package/dist/src/relay/phone-socket.js +63 -0
  337. package/dist/src/relay/relay-control.d.ts +7 -0
  338. package/dist/src/relay/relay-control.js +24 -0
  339. package/dist/src/relay/relay-files.d.ts +2 -0
  340. package/dist/src/relay/relay-files.js +23 -0
  341. package/dist/src/relay/relay-heartbeat.d.ts +17 -0
  342. package/dist/src/relay/relay-heartbeat.js +81 -0
  343. package/dist/src/relay/relay-http.d.ts +14 -0
  344. package/dist/src/relay/relay-http.js +63 -0
  345. package/dist/src/relay/relay-registration.d.ts +15 -0
  346. package/dist/src/relay/relay-registration.js +63 -0
  347. package/dist/src/relay/relay-service.d.ts +25 -0
  348. package/dist/src/relay/relay-service.js +216 -0
  349. package/dist/src/relay/relay-store.d.ts +48 -0
  350. package/dist/src/relay/relay-store.js +131 -0
  351. package/dist/src/relay/sealed-post.d.ts +25 -0
  352. package/dist/src/relay/sealed-post.js +52 -0
  353. package/dist/src/relay.d.ts +1 -0
  354. package/dist/src/relay.js +8 -0
  355. package/dist/src/report-statistics.d.ts +50 -0
  356. package/dist/src/report-statistics.js +70 -0
  357. package/dist/src/report.d.ts +171 -0
  358. package/dist/src/report.js +119 -0
  359. package/dist/src/repository-identity.d.ts +4 -0
  360. package/dist/src/repository-identity.js +4 -0
  361. package/dist/src/review-subject.d.ts +41 -0
  362. package/dist/src/review-subject.js +91 -0
  363. package/dist/src/run-wait.d.ts +23 -0
  364. package/dist/src/run-wait.js +20 -0
  365. package/dist/src/service/active-tickets.d.ts +4 -0
  366. package/dist/src/service/active-tickets.js +49 -0
  367. package/dist/src/service/command-effects.d.ts +4 -0
  368. package/dist/src/service/command-effects.js +16 -0
  369. package/dist/src/service/decision-handler.d.ts +4 -0
  370. package/dist/src/service/decision-handler.js +39 -4
  371. package/dist/src/service/gateway.js +18 -3
  372. package/dist/src/service/queue-runs.d.ts +3 -0
  373. package/dist/src/service/queue-runs.js +39 -0
  374. package/dist/src/service/registry.d.ts +22 -3
  375. package/dist/src/service/registry.js +51 -8
  376. package/dist/src/service/replies.d.ts +10 -0
  377. package/dist/src/service/replies.js +12 -0
  378. package/dist/src/service/run-handlers.js +45 -54
  379. package/dist/src/service/run-metadata.d.ts +8 -0
  380. package/dist/src/service/run-metadata.js +53 -0
  381. package/dist/src/service/run-waits.d.ts +3 -0
  382. package/dist/src/service/run-waits.js +41 -0
  383. package/dist/src/service/service.d.ts +21 -2
  384. package/dist/src/service/service.js +23 -5
  385. package/dist/src/service/submission-handler.js +70 -19
  386. package/dist/src/service/worker-port.d.ts +1 -0
  387. package/dist/src/service/worker-totals.js +10 -1
  388. package/dist/src/step-bridge.d.ts +32 -0
  389. package/dist/src/steps/decision-gate.d.ts +2 -1
  390. package/dist/src/steps/decision-gate.js +7 -0
  391. package/dist/src/steps/handoff.d.ts +2 -0
  392. package/dist/src/steps/handoff.js +13 -0
  393. package/dist/src/steps/merge-by-person.d.ts +2 -0
  394. package/dist/src/steps/merge-by-person.js +18 -0
  395. package/dist/src/steps/merge-when-green.d.ts +2 -0
  396. package/dist/src/steps/merge-when-green.js +62 -0
  397. package/dist/src/steps/review-by-agent.d.ts +5 -0
  398. package/dist/src/steps/review-by-agent.js +124 -0
  399. package/dist/src/steps/review-by-person.d.ts +4 -0
  400. package/dist/src/steps/review-by-person.js +16 -0
  401. package/dist/src/steps/review-subject.d.ts +2 -0
  402. package/dist/src/steps/review-subject.js +11 -0
  403. package/dist/src/steps/run-command.d.ts +2 -0
  404. package/dist/src/steps/run-command.js +15 -0
  405. package/dist/src/steps/sleep.d.ts +3 -0
  406. package/dist/src/steps/sleep.js +19 -0
  407. package/dist/src/steps/wait-for-decision.d.ts +2 -0
  408. package/dist/src/steps/wait-for-decision.js +71 -0
  409. package/dist/src/steps/wait-for-run.d.ts +5 -0
  410. package/dist/src/steps/wait-for-run.js +9 -0
  411. package/dist/src/storage/decision-snapshots.d.ts +1 -0
  412. package/dist/src/storage/decision-snapshots.js +7 -1
  413. package/dist/src/submission.d.ts +4 -0
  414. package/dist/src/submission.js +6 -2
  415. package/dist/src/testing.d.ts +29 -0
  416. package/dist/src/testing.js +264 -0
  417. package/dist/src/ticket-dependencies.d.ts +1 -0
  418. package/dist/src/ticket-dependencies.js +15 -0
  419. package/dist/src/ticket-status-stream.d.ts +9 -0
  420. package/dist/src/ticket-status-stream.js +94 -0
  421. package/dist/src/ticket-status.js +7 -4
  422. package/dist/src/token-prices.d.ts +14 -4
  423. package/dist/src/token-prices.js +56 -11
  424. package/dist/src/turn-profile.d.ts +1 -0
  425. package/dist/src/turn-profile.js +8 -1
  426. package/dist/src/worker-usage.d.ts +25 -0
  427. package/dist/src/worker-usage.js +58 -1
  428. package/dist/src/workflow-admission.d.ts +6 -0
  429. package/dist/src/workflow-candidate.d.ts +7 -2
  430. package/dist/src/workflow-candidate.js +48 -5
  431. package/dist/src/workflow-contracts.d.ts +2 -0
  432. package/dist/src/workflow-contracts.js +8 -3
  433. package/dist/src/workflow-declaration.d.ts +31 -2
  434. package/dist/src/workflow-declaration.js +140 -16
  435. package/dist/src/workflow-discovery.d.ts +19 -0
  436. package/dist/src/workflow-discovery.js +36 -0
  437. package/dist/src/workflow-refusals.d.ts +6 -0
  438. package/dist/src/workflow-refusals.js +42 -0
  439. package/dist/src/workflow-schedule.d.ts +22 -0
  440. package/dist/src/workflow-schedule.js +53 -0
  441. package/dist/src/workflows.d.ts +12 -1
  442. package/dist/src/workflows.js +9 -0
  443. package/dist/tools/admit-workflow.d.ts +14 -0
  444. package/dist/tools/admit-workflow.js +107 -0
  445. package/dist/tools/doctor-adoption.d.ts +1 -0
  446. package/dist/tools/doctor-adoption.js +11 -0
  447. package/dist/tools/project-configuration.d.ts +4 -0
  448. package/dist/tools/project-configuration.js +47 -0
  449. package/dist/tools/self-host-processes.d.ts +1 -0
  450. package/dist/tools/self-host-processes.js +33 -22
  451. package/dist/tools/self-host-project.d.ts +21 -0
  452. package/dist/tools/self-host-project.js +224 -0
  453. package/dist/tools/self-host-runtime.d.ts +16 -0
  454. package/dist/tools/self-host-runtime.js +60 -0
  455. package/dist/tools/self-host-workflows.d.ts +1 -0
  456. package/dist/tools/self-host-workflows.js +36 -1
  457. package/dist/tools/self-host.js +106 -135
  458. package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
  459. package/dist/tools/workflow-bundle-dependencies.js +93 -0
  460. package/dist/tools/workflow-bundles.d.ts +20 -0
  461. package/dist/tools/workflow-bundles.js +173 -0
  462. package/dist/tools/workflow-candidate-counts.d.ts +12 -0
  463. package/dist/tools/workflow-candidate-counts.js +266 -0
  464. package/dist/tools/workflow-candidate-fields.d.ts +5 -0
  465. package/dist/tools/workflow-candidate-fields.js +24 -0
  466. package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
  467. package/dist/tools/workflow-candidate-helper-counts.js +129 -0
  468. package/dist/tools/workflow-candidate-program.d.ts +13 -0
  469. package/dist/tools/workflow-candidate-program.js +106 -0
  470. package/dist/tools/workflow-candidate-source.d.ts +6 -0
  471. package/dist/tools/workflow-candidate-source.js +169 -0
  472. package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
  473. package/dist/tools/workflow-candidate-syntax.js +263 -0
  474. package/dist/tools/workflow-command.d.ts +1 -0
  475. package/dist/tools/workflow-command.js +143 -0
  476. package/dist/tools/workflow-folder-capture.d.ts +18 -0
  477. package/dist/tools/workflow-folder-capture.js +261 -0
  478. package/dist/tools/workflow-folders.d.ts +49 -0
  479. package/dist/tools/workflow-folders.js +203 -0
  480. package/dist/tools/workflow-source-effects.d.ts +10 -0
  481. package/dist/tools/workflow-source-effects.js +213 -0
  482. package/dist/tools/workflow-test-hook.d.ts +7 -0
  483. package/dist/tools/workflow-test-hook.js +16 -0
  484. package/dist/tools/workflow-test-loader.d.ts +1 -0
  485. package/dist/tools/workflow-test-loader.js +10 -0
  486. package/dist/workflows/develop-prd.js +71 -3
  487. package/dist/workflows/develop-ticket.js +6 -1
  488. package/dist/workflows/ticket-prompts.js +17 -3
  489. package/package.json +66 -6
  490. package/templates/develop/README.md +78 -0
  491. package/templates/develop/develop/accept.ts +11 -0
  492. package/templates/develop/develop/flow-tests.ts +357 -0
  493. package/templates/develop/develop/local.ts +40 -0
  494. package/templates/develop/develop/option-tests.ts +174 -0
  495. package/templates/develop/develop/partial-choice.ts +29 -0
  496. package/templates/develop/develop/partial.ts +28 -0
  497. package/templates/develop/develop/pull.ts +152 -0
  498. package/templates/develop/develop/queue-partial.ts +39 -0
  499. package/templates/develop/develop/refusal-tests.ts +174 -0
  500. package/templates/develop/develop/report.ts +156 -0
  501. package/templates/develop/develop/round.ts +40 -0
  502. package/templates/develop/develop/scenarios.ts +87 -0
  503. package/templates/develop/develop/turn.ts +67 -0
  504. package/templates/develop/develop.declaration.json +24 -0
  505. package/templates/develop/develop.test.ts +287 -0
  506. package/templates/develop/develop.ts +30 -0
  507. package/templates/develop/template.json +153 -0
  508. package/dist/src/chats/analysis-batches.d.ts +0 -24
  509. package/dist/src/chats/analysis-batches.js +0 -83
  510. package/dist/src/chats/analysis-contract.d.ts +0 -80
  511. package/dist/src/chats/analysis-contract.js +0 -16
  512. package/dist/src/chats/analysis-data.d.ts +0 -3
  513. package/dist/src/chats/analysis-data.js +0 -85
  514. package/dist/src/chats/analysis-input.d.ts +0 -12
  515. package/dist/src/chats/analysis-input.js +0 -83
  516. package/dist/src/chats/analysis-links.d.ts +0 -2
  517. package/dist/src/chats/analysis-links.js +0 -25
  518. package/dist/src/chats/analysis-prompt.d.ts +0 -10
  519. package/dist/src/chats/analysis-prompt.js +0 -16
  520. package/dist/src/chats/analysis-proposal.d.ts +0 -2
  521. package/dist/src/chats/analysis-proposal.js +0 -32
  522. package/dist/src/chats/analysis-provenance.d.ts +0 -4
  523. package/dist/src/chats/analysis-provenance.js +0 -99
  524. package/dist/src/chats/analysis-shape.d.ts +0 -3
  525. package/dist/src/chats/analysis-shape.js +0 -228
  526. package/dist/src/chats/analysis.d.ts +0 -3
  527. package/dist/src/chats/analysis.js +0 -42
  528. package/dist/src/chats/corpus-input.d.ts +0 -5
  529. package/dist/src/chats/corpus-input.js +0 -288
  530. package/dist/src/chats/destination.d.ts +0 -4
  531. package/dist/src/chats/destination.js +0 -96
  532. package/dist/src/chats/import.d.ts +0 -15
  533. package/dist/src/chats/import.js +0 -243
  534. package/dist/src/chats/input-file.d.ts +0 -3
  535. package/dist/src/chats/input-file.js +0 -32
  536. package/dist/src/chats/normalize.d.ts +0 -29
  537. package/dist/src/chats/normalize.js +0 -155
  538. package/dist/src/chats/previous-import.d.ts +0 -5
  539. package/dist/src/chats/previous-import.js +0 -34
  540. package/dist/src/chats/reader.d.ts +0 -21
  541. package/dist/src/chats/reader.js +0 -118
  542. package/dist/src/chats/redact-import.d.ts +0 -14
  543. package/dist/src/chats/redact-import.js +0 -141
  544. package/dist/src/chats/redaction.d.ts +0 -41
  545. package/dist/src/chats/redaction.js +0 -161
  546. package/dist/src/chats/revision-input.d.ts +0 -3
  547. package/dist/src/chats/revision-input.js +0 -180
  548. package/dist/src/chats/revision.d.ts +0 -48
  549. package/dist/src/chats/revision.js +0 -94
  550. package/dist/src/chats/selection.d.ts +0 -25
  551. package/dist/src/chats/selection.js +0 -109
  552. package/dist/src/chats/source.d.ts +0 -23
  553. package/dist/src/chats/source.js +0 -135
  554. package/dist/src/chats/structure.d.ts +0 -57
  555. package/dist/src/chats/structure.js +0 -216
  556. package/dist/src/daemon/analysis-launch.d.ts +0 -5
  557. package/dist/src/daemon/analysis-launch.js +0 -81
  558. package/dist/src/daemon/analysis-token.d.ts +0 -6
  559. package/dist/src/daemon/analysis-token.js +0 -88
  560. package/dist/src/daemon/analysis-worker.d.ts +0 -22
  561. package/dist/src/daemon/analysis-worker.js +0 -219
  562. package/dist/src/daemon/chats-files.d.ts +0 -15
  563. package/dist/src/daemon/chats-files.js +0 -113
  564. package/dist/src/daemon/chats-worker.d.ts +0 -12
  565. package/dist/src/daemon/chats-worker.js +0 -200
  566. package/dist/workflows/analyze-chats.d.ts +0 -10
  567. package/dist/workflows/analyze-chats.declaration.json +0 -9
  568. package/dist/workflows/analyze-chats.js +0 -73
@@ -0,0 +1,53 @@
1
+ import { qrMatrix } from "../phone/qr-matrix.js";
2
+ import { qrPicture } from "../phone/qr-picture.js";
3
+ import { phoneRequest } from "./phone-client.js";
4
+ import { actionAllowed, actionBody, } from "./watch-actions.js";
5
+ const operations = {
6
+ "/actions/phone/pair": "phone-pair-start",
7
+ "/actions/phone/cancel": "phone-pair-cancel",
8
+ "/actions/phone/accept": "phone-pair-accept",
9
+ "/actions/phone/deny": "phone-pair-deny",
10
+ "/actions/phone/remove": "phone-remove",
11
+ };
12
+ export function isPhoneAction(path) {
13
+ return Object.hasOwn(operations, path);
14
+ }
15
+ function withPicture(result) {
16
+ const link = result["link"];
17
+ return typeof link === "string"
18
+ ? { ...result, picture: qrPicture(qrMatrix(link).modules) }
19
+ : result;
20
+ }
21
+ export async function phoneAction(actions, request) {
22
+ const operation = operations[new URL(String(request.url), "http://localhost").pathname];
23
+ if (operation === undefined || !actionAllowed(actions, request))
24
+ return null;
25
+ const body = await actionBody(request);
26
+ if (typeof body !== "object" || body === null || Array.isArray(body))
27
+ return null;
28
+ const reply = await phoneRequest(actions.runtimeDirectory, {
29
+ operation,
30
+ parameters: { ...body },
31
+ });
32
+ if (reply === undefined)
33
+ return JSON.stringify({
34
+ error: {
35
+ code: "phone-relay-off",
36
+ detail: "The phone relay is off or not started.",
37
+ },
38
+ });
39
+ return JSON.stringify(reply.kind === "result"
40
+ ? withPicture(reply.result)
41
+ : { error: reply.error });
42
+ }
43
+ export async function phoneRead(runtimeDirectory) {
44
+ const reply = await phoneRequest(runtimeDirectory, {
45
+ operation: "phone-state",
46
+ parameters: {},
47
+ });
48
+ if (reply === undefined)
49
+ return JSON.stringify({ relay: "off" });
50
+ return JSON.stringify(reply.kind === "result"
51
+ ? { relay: "on", ...reply.result }
52
+ : { relay: "on", error: reply.error });
53
+ }
@@ -1,4 +1,4 @@
1
- import { type PrIdentity, type PrObservation } from "./watch-pr-identity.ts";
1
+ import { type PrIdentity, type PrReadResult } from "./watch-pr-identity.ts";
2
2
  export interface WatchCommandOutput {
3
3
  readonly stdout: string;
4
4
  readonly stderr: string;
@@ -12,4 +12,7 @@ export interface WatchCommandRequest {
12
12
  }
13
13
  export type WatchCommandRunner = (request: WatchCommandRequest) => Promise<WatchCommandOutput>;
14
14
  export declare function prArguments(identity: PrIdentity): readonly string[];
15
- export declare function prCommandResult(identity: PrIdentity, output: WatchCommandOutput): PrObservation;
15
+ export declare function prCommandResult(identity: PrIdentity, reply: {
16
+ readonly output: WatchCommandOutput;
17
+ readonly now: number;
18
+ }): PrReadResult;
@@ -15,15 +15,52 @@ function commandFailure(output) {
15
15
  /^HTTP\/[^ ]+ (\d{3})/m.exec(output.stdout)?.[1]);
16
16
  if (status === 429 ||
17
17
  /rate limit/i.test(output.stderr) ||
18
- /x-ratelimit-remaining: 0\s*$/im.test(output.stdout))
18
+ headerValues(output.stdout, "x-ratelimit-remaining").includes("0"))
19
19
  return "rate-limit";
20
20
  if (output.status === 4 || [401, 403, 404].includes(status))
21
21
  return "access";
22
22
  return "command";
23
23
  }
24
- export function prCommandResult(identity, output) {
25
- if (output.status !== 0 || output.errorCode !== null)
26
- return { status: "unavailable", failure: commandFailure(output) };
24
+ function headerValues(stdout, name) {
25
+ if (!/^HTTP\/[^ ]+ \d{3}/.test(stdout))
26
+ return [];
27
+ const headers = stdout.split(/\r?\n\r?\n/, 1)[0] ?? "";
28
+ return headers.split(/\r?\n/).flatMap((line) => {
29
+ const separator = line.indexOf(":");
30
+ return line.slice(0, separator).toLowerCase() === name
31
+ ? [line.slice(separator + 1).trim()]
32
+ : [];
33
+ });
34
+ }
35
+ function millisecondsOf(value) {
36
+ if (!/^\d+$/.test(value))
37
+ return [];
38
+ const milliseconds = Number(value) * 1000;
39
+ return Number.isSafeInteger(milliseconds) ? [milliseconds] : [];
40
+ }
41
+ function retryDeadline(output, now) {
42
+ const delays = headerValues(output.stdout, "retry-after")
43
+ .flatMap(millisecondsOf)
44
+ .map((delay) => now + delay)
45
+ .filter(Number.isSafeInteger);
46
+ const resets = headerValues(output.stdout, "x-ratelimit-remaining").includes("0")
47
+ ? headerValues(output.stdout, "x-ratelimit-reset").flatMap(millisecondsOf)
48
+ : [];
49
+ const deadlines = [...delays, ...resets];
50
+ return deadlines.length === 0 ? now + 60000 : Math.max(now, ...deadlines);
51
+ }
52
+ export function prCommandResult(identity, reply) {
53
+ const { output, now } = reply;
54
+ if (output.status !== 0 || output.errorCode !== null) {
55
+ const failure = commandFailure(output);
56
+ return {
57
+ status: "unavailable",
58
+ failure,
59
+ ...(failure === "rate-limit"
60
+ ? { retryAt: retryDeadline(output, now) }
61
+ : {}),
62
+ };
63
+ }
27
64
  const envelope = /^HTTP\/[^ ]+ 200[^\n]*\r?\n[\s\S]*?\r?\n\r?\n([\s\S]*)$/.exec(output.stdout);
28
65
  if (envelope?.[1] === undefined)
29
66
  return { status: "unavailable", failure: "response" };
@@ -5,14 +5,26 @@ export interface PrIdentity {
5
5
  readonly number: number;
6
6
  }
7
7
  export type PrFailure = "configuration" | "identity" | "command" | "access" | "rate-limit" | "response" | "timeout";
8
- export type PrObservation = {
8
+ export type PrReadResult = {
9
9
  readonly status: "merged" | "unmerged";
10
10
  } | {
11
11
  readonly status: "unavailable";
12
12
  readonly failure: PrFailure;
13
+ readonly retryAt?: number;
13
14
  };
14
- export declare function prResponse(identity: PrIdentity, value: unknown): PrObservation;
15
+ export type PrObservation = (PrReadResult | {
16
+ readonly status: "pending";
17
+ }) & {
18
+ readonly retryAt?: number;
19
+ readonly lastSuccess?: {
20
+ readonly status: "merged" | "unmerged";
21
+ readonly readAt: number;
22
+ };
23
+ };
24
+ export declare function prResponse(identity: PrIdentity, value: unknown): PrReadResult;
15
25
  export type PrRepository = Omit<PrIdentity, "number">;
26
+ export declare function establishedIssue(repository: PrRepository | null, value: unknown): PrIdentity | null;
27
+ export declare function sameIssue(first: PrIdentity | null | undefined, second: PrIdentity | null | undefined): boolean;
16
28
  export declare function prRepository(origin: string): PrRepository | null;
17
29
  export declare function prIdentity(repository: PrRepository, pullRequest: {
18
30
  readonly number: number;
@@ -31,6 +31,31 @@ export function prResponse(identity, value) {
31
31
  return { status: "unavailable", failure: "response" };
32
32
  return { status: merged ? "merged" : "unmerged" };
33
33
  }
34
+ export function establishedIssue(repository, value) {
35
+ const fields = record(value) ?? {};
36
+ const number = fields["number"];
37
+ if (repository === null ||
38
+ typeof number !== "number" ||
39
+ !Number.isSafeInteger(number) ||
40
+ number <= 0)
41
+ return null;
42
+ const owner = fields["owner"];
43
+ const name = fields["repository"];
44
+ if (typeof owner !== "string" ||
45
+ typeof name !== "string" ||
46
+ owner.toLowerCase() !== repository.owner ||
47
+ name.toLowerCase() !== repository.repository)
48
+ return null;
49
+ return { ...repository, number };
50
+ }
51
+ export function sameIssue(first, second) {
52
+ return (first != null &&
53
+ second != null &&
54
+ first.host === second.host &&
55
+ first.owner === second.owner &&
56
+ first.repository === second.repository &&
57
+ first.number === second.number);
58
+ }
34
59
  export function prRepository(origin) {
35
60
  const address = origin
36
61
  .replace(/^git@([^:/]+):/, "ssh://git@$1/")
@@ -2,6 +2,7 @@ import type { WatchPullRequest } from "./watch-render.ts";
2
2
  import { type WatchCommandRunner } from "./watch-pr-command.ts";
3
3
  import { type PrObservation, type PrRepository } from "./watch-pr-identity.ts";
4
4
  export interface PrObserver {
5
+ readonly repository?: PrRepository | null;
5
6
  readonly observe: (pullRequest: WatchPullRequest) => PrObservation | null;
6
7
  readonly close: () => void;
7
8
  }
@@ -9,13 +9,23 @@ const systemClock = {
9
9
  };
10
10
  },
11
11
  };
12
+ function observationOf(entry, reply) {
13
+ const { result, now } = reply;
14
+ if (result.status !== "unavailable")
15
+ return { ...result, lastSuccess: { status: result.status, readAt: now } };
16
+ const lastSuccess = entry.result?.lastSuccess;
17
+ return { ...result, ...(lastSuccess === undefined ? {} : { lastSuccess }) };
18
+ }
12
19
  async function readPr(state, attempt) {
13
20
  const { entry, controller } = attempt;
14
21
  const deadline = { expired: false };
15
22
  const timeout = { status: "unavailable", failure: "timeout" };
16
23
  const cancel = state.clock.after(() => {
17
24
  deadline.expired = true;
18
- entry.result = timeout;
25
+ entry.result = observationOf(entry, {
26
+ result: timeout,
27
+ now: state.clock.now(),
28
+ });
19
29
  controller.abort();
20
30
  }, 5000);
21
31
  controller.signal.addEventListener("abort", cancel, { once: true });
@@ -28,7 +38,9 @@ async function readPr(state, attempt) {
28
38
  directory: state.settings.directory,
29
39
  signal: controller.signal,
30
40
  }));
31
- return deadline.expired ? timeout : prCommandResult(entry.identity, output);
41
+ return deadline.expired
42
+ ? timeout
43
+ : prCommandResult(entry.identity, { output, now: state.clock.now() });
32
44
  }
33
45
  catch {
34
46
  return deadline.expired
@@ -43,14 +55,32 @@ async function readPr(state, attempt) {
43
55
  function pump(state) {
44
56
  if (state.closed || state.active !== null)
45
57
  return;
46
- const entry = state.queue.shift();
58
+ state.wake?.();
59
+ state.wake = null;
60
+ if (state.queue.length === 0)
61
+ return;
62
+ const now = state.clock.now();
63
+ const position = state.queue.findIndex((entry) => (state.retryDeadlines.get(entry.identity.host) ?? 0) <= now);
64
+ if (position === -1) {
65
+ const next = Math.min(...state.queue.map((entry) => state.retryDeadlines.get(entry.identity.host) ?? now));
66
+ state.wake = state.clock.after(() => {
67
+ state.wake = null;
68
+ pump(state);
69
+ }, Math.min(next - now, 2147483647));
70
+ return;
71
+ }
72
+ const [entry] = state.queue.splice(position, 1);
47
73
  if (entry === undefined)
48
74
  return;
49
75
  const controller = new AbortController();
50
76
  state.active = controller;
51
77
  entry.started = state.clock.now();
52
78
  const completed = (result) => {
53
- entry.result = result;
79
+ if (state.closed)
80
+ return;
81
+ entry.result = observationOf(entry, { result, now: state.clock.now() });
82
+ if (result.status === "unavailable" && result.failure === "rate-limit")
83
+ state.retryDeadlines.set(entry.identity.host, Math.max(state.retryDeadlines.get(entry.identity.host) ?? 0, result.retryAt ?? state.clock.now() + 60000));
54
84
  entry.pending = false;
55
85
  state.active = null;
56
86
  pump(state);
@@ -59,6 +89,11 @@ function pump(state) {
59
89
  completed({ status: "unavailable", failure: "command" });
60
90
  });
61
91
  }
92
+ function currentObservation(state, entry) {
93
+ const result = entry.result ?? { status: "pending" };
94
+ const retryAt = state.retryDeadlines.get(entry.identity.host) ?? 0;
95
+ return retryAt > state.clock.now() ? { ...result, retryAt } : result;
96
+ }
62
97
  function needsRead(entry, now) {
63
98
  if (entry === undefined)
64
99
  return true;
@@ -72,6 +107,8 @@ export function prObserver(settings) {
72
107
  clock: settings.clock ?? systemClock,
73
108
  cache: new Map(),
74
109
  queue: [],
110
+ retryDeadlines: new Map(),
111
+ wake: null,
75
112
  active: null,
76
113
  closed: false,
77
114
  };
@@ -85,7 +122,9 @@ export function prObserver(settings) {
85
122
  const key = JSON.stringify(identity);
86
123
  const known = state.cache.get(key);
87
124
  if (state.closed || !needsRead(known, state.clock.now()))
88
- return known?.result ?? null;
125
+ return known === undefined
126
+ ? { status: "pending" }
127
+ : currentObservation(state, known);
89
128
  const entry = {
90
129
  identity,
91
130
  result: known?.result ?? null,
@@ -95,13 +134,16 @@ export function prObserver(settings) {
95
134
  state.cache.set(key, entry);
96
135
  state.queue.push(entry);
97
136
  pump(state);
98
- return entry.result;
137
+ return currentObservation(state, entry);
99
138
  };
100
139
  return {
140
+ repository: settings.repository,
101
141
  observe,
102
142
  close: () => {
103
143
  state.closed = true;
104
144
  state.queue.length = 0;
145
+ state.wake?.();
146
+ state.wake = null;
105
147
  state.active?.abort();
106
148
  },
107
149
  };
@@ -0,0 +1,12 @@
1
+ import type { CiRerunNotice } from "./github-ci-progress.ts";
2
+ import type { WatchRun } from "./watch-render.ts";
3
+ import { type PrRepository } from "./watch-pr-identity.ts";
4
+ export interface GithubRecords {
5
+ readonly started: unknown;
6
+ readonly result: unknown;
7
+ readonly ciReruns?: readonly CiRerunNotice[];
8
+ }
9
+ export declare function pullOf(inputs: {
10
+ readonly records: readonly GithubRecords[];
11
+ readonly repository: PrRepository | null;
12
+ }, runId: string): Pick<WatchRun, "pullRequest" | "reviews" | "mergeCommit" | "mergeProof" | "ciReruns">;
@@ -0,0 +1,134 @@
1
+ import { operationIdentity } from "../operation-identity.js";
2
+ import { prIdentity, } from "./watch-pr-identity.js";
3
+ function record(value) {
4
+ return typeof value === "object" && value !== null ? { ...value } : {};
5
+ }
6
+ function text(value) {
7
+ return typeof value === "string" ? value : "";
8
+ }
9
+ function stamp(value) {
10
+ return typeof value === "string" ? value : null;
11
+ }
12
+ function parsed(line) {
13
+ try {
14
+ return JSON.parse(line);
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ }
20
+ function list(value) {
21
+ return Array.isArray(value) ? value.map((item) => item) : [];
22
+ }
23
+ function count(value) {
24
+ return typeof value === "number" ? value : null;
25
+ }
26
+ function attributed(started, operation) {
27
+ const stage = list(operation[5]);
28
+ const checked = operationIdentity({
29
+ round: operation[1],
30
+ run: operation[2],
31
+ phase: operation[3],
32
+ operation: operation[4],
33
+ ...(operation[5] === null
34
+ ? {}
35
+ : { stage: { id: stage[0], visit: stage[1], branch: stage[2] } }),
36
+ ...(operation[6] === null ? {} : { key: operation[6] }),
37
+ });
38
+ return (checked.kind === "valid" &&
39
+ checked.value === JSON.stringify(operation) &&
40
+ operation[3] === "pull-request" &&
41
+ operation[4] === `github-${text(started["method"])}` &&
42
+ (started["runId"] === undefined || started["runId"] === operation[2]));
43
+ }
44
+ function githubOf(records) {
45
+ const started = record(records.started);
46
+ const operation = list(parsed(text(started["operationId"])));
47
+ const result = record(records.result);
48
+ const completed = result["outcome"] === "completed";
49
+ return {
50
+ runId: text(operation[2]),
51
+ round: Number(operation[1]),
52
+ method: text(started["method"]),
53
+ completed,
54
+ attributed: attributed(started, operation) && !Object.hasOwn(result, "reason"),
55
+ report: completed ? record(parsed(text(result["result"]))) : {},
56
+ };
57
+ }
58
+ function pullRequestOf(results) {
59
+ const opened = results
60
+ .filter((item) => item.method === "open-pr")
61
+ .map((item) => item.report)
62
+ .findLast((report) => text(report["url"]).startsWith("https://"));
63
+ if (opened === undefined)
64
+ return null;
65
+ return { number: Number(opened["number"]), url: text(opened["url"]) };
66
+ }
67
+ function reviewsOf(results) {
68
+ return results
69
+ .filter((item) => item.method === "wait-review")
70
+ .flatMap(({ round, report }) => {
71
+ const score = count(report["score"]);
72
+ if (score === null)
73
+ return [];
74
+ return [{ round, commit: text(report["commit"]), score }];
75
+ });
76
+ }
77
+ function mergeCommitOf(results) {
78
+ const merged = results
79
+ .filter((item) => item.method === "merge")
80
+ .map((item) => stamp(item.report["merged"]));
81
+ return merged.find((commit) => commit !== null) ?? null;
82
+ }
83
+ function mergeProofOf(results, context) {
84
+ if (context.repository === null || context.pullRequest === null)
85
+ return null;
86
+ const repository = context.repository;
87
+ const identity = prIdentity(repository, context.pullRequest);
88
+ if (identity === null)
89
+ return null;
90
+ const opened = results.filter((item) => item.method === "open-pr" && item.completed && item.attributed);
91
+ if (opened.length === 0 ||
92
+ opened.some(({ report }) => report["number"] !== identity.number ||
93
+ typeof report["url"] !== "string" ||
94
+ prIdentity(repository, {
95
+ number: identity.number,
96
+ url: report["url"],
97
+ }) === null))
98
+ return null;
99
+ const merged = results.filter((item) => item.method === "merge" &&
100
+ item.completed &&
101
+ item.attributed &&
102
+ (typeof item.report["reason"] !== "string" ||
103
+ Object.hasOwn(item.report, "merged")));
104
+ if (merged.length === 0 ||
105
+ merged.some(({ report }) => report["number"] !== identity.number ||
106
+ typeof report["merged"] !== "string" ||
107
+ report["merged"].trim() === "" ||
108
+ Object.hasOwn(report, "reason")))
109
+ return null;
110
+ return new Set(merged.map(({ report }) => report["merged"])).size === 1
111
+ ? identity
112
+ : null;
113
+ }
114
+ export function pullOf(inputs, runId) {
115
+ const results = inputs.records
116
+ .map(githubOf)
117
+ .filter((item) => item.runId === runId)
118
+ .toSorted((first, second) => first.round - second.round);
119
+ const pullRequest = pullRequestOf(results);
120
+ const mergeProof = mergeProofOf(results, {
121
+ repository: inputs.repository,
122
+ pullRequest,
123
+ });
124
+ const ciReruns = inputs.records
125
+ .filter((item) => record(item.started)["runId"] === runId)
126
+ .flatMap((item) => item.ciReruns ?? []);
127
+ return {
128
+ pullRequest,
129
+ reviews: reviewsOf(results),
130
+ mergeCommit: mergeCommitOf(results),
131
+ ...(ciReruns.length === 0 ? {} : { ciReruns }),
132
+ ...(mergeProof === null ? {} : { mergeProof }),
133
+ };
134
+ }
@@ -1,4 +1,7 @@
1
+ import { type PrRepository } from "./watch-pr-identity.ts";
2
+ import { type WorkflowStages } from "../workflow-declaration.ts";
1
3
  import { type Fields } from "../protocol.ts";
4
+ import { type WorkflowRefusal } from "../workflow-refusals.ts";
2
5
  interface ReadStatus extends Fields {
3
6
  readonly runId: string;
4
7
  readonly latestSequence: number;
@@ -13,8 +16,11 @@ interface ReadRun {
13
16
  readonly events: readonly ReadEvent[];
14
17
  }
15
18
  export interface WatchRead {
19
+ readonly queue?: Fields;
16
20
  readonly service: string;
17
21
  readonly workflows: readonly string[];
22
+ readonly workflowRefusals: readonly WorkflowRefusal[];
23
+ readonly workflowStages?: WorkflowStages;
18
24
  readonly summaries: readonly ReadStatus[];
19
25
  readonly runs: readonly ReadRun[];
20
26
  readonly completionCandidates: readonly ReadRun[];
@@ -24,5 +30,5 @@ export interface WatchReader {
24
30
  readonly read: (now: string) => Promise<WatchRead>;
25
31
  readonly run: (runId: string) => Promise<WatchRead>;
26
32
  }
27
- export declare function watchReader(runtimeDirectory: string): WatchReader;
33
+ export declare function watchReader(runtimeDirectory: string, repository?: PrRepository | null): WatchReader;
28
34
  export {};
@@ -1,9 +1,13 @@
1
+ import { establishedIssue } from "./watch-pr-identity.js";
2
+ import { isWorkflowStages, } from "../workflow-declaration.js";
1
3
  import { record } from "../protocol.js";
2
4
  import { send } from "./client.js";
3
5
  import { activeRun, recentRun } from "./watch-board.js";
6
+ import { workflowRefusals, } from "../workflow-refusals.js";
4
7
  const unavailable = {
5
8
  service: "down",
6
9
  workflows: [],
10
+ workflowRefusals: [],
7
11
  summaries: [],
8
12
  runs: [],
9
13
  completionCandidates: [],
@@ -79,15 +83,15 @@ async function creationOf(reader, runId) {
79
83
  }
80
84
  return null;
81
85
  }
82
- function matchingCompletion(status, ticketIds) {
83
- const ticketId = status["ticketId"];
86
+ function matchingCompletion(status, context) {
87
+ const issue = establishedIssue(context.repository, status["issueIdentity"]);
84
88
  return (status.state === "completed" &&
85
89
  status["workflowId"] === "develop-issue" &&
86
90
  record(status["outcome"])?.["kind"] === "handoff_requested" &&
87
91
  record(status["outcome"])?.["ticketStatus"] !== "partial" &&
88
92
  record(status["outcome"])?.["issueUpdate"] !== "failed" &&
89
- typeof ticketId === "string" &&
90
- ticketIds.has(ticketId));
93
+ issue !== null &&
94
+ context.issues.has(JSON.stringify(issue)));
91
95
  }
92
96
  async function completionOf(reader, search) {
93
97
  const { runId, latestSequence } = search.summary;
@@ -106,12 +110,16 @@ async function completionOf(reader, search) {
106
110
  state: status.state,
107
111
  workflowId: status["workflowId"],
108
112
  ticketId: status["ticketId"],
113
+ issueIdentity: status["issueIdentity"],
109
114
  outcome: status["outcome"],
110
115
  },
111
116
  };
112
117
  reader.completions.set(runId, known);
113
118
  }
114
- if (!matchingCompletion(known.status, search.ticketIds))
119
+ if (!matchingCompletion(known.status, {
120
+ issues: search.issues,
121
+ repository: reader.repository,
122
+ }))
115
123
  return null;
116
124
  const creation = known.creation === undefined
117
125
  ? await creationOf(reader, runId)
@@ -119,11 +127,20 @@ async function completionOf(reader, search) {
119
127
  reader.completions.set(runId, { ...known, creation });
120
128
  return { status: known.status, events: creation === null ? [] : [creation] };
121
129
  }
130
+ function refreshedLinks(run, status) {
131
+ const links = Object.fromEntries(["parentRunId", "chainId", "childRunIds"]
132
+ .filter((name) => Object.hasOwn(status, name))
133
+ .map((name) => [name, status[name]]));
134
+ return {
135
+ ...run,
136
+ status: { ...run.status, ...links },
137
+ };
138
+ }
122
139
  async function detailed(reader, summary) {
123
140
  const { runId, latestSequence: sequence } = summary;
124
141
  const known = reader.details.get(runId);
125
142
  if (known !== undefined && known.sequence === sequence)
126
- return known.value;
143
+ return refreshedLinks(known.value, summary);
127
144
  const shown = await asked(reader, {
128
145
  operation: "status",
129
146
  parameters: { runId },
@@ -160,10 +177,10 @@ async function decisionsOf(reader) {
160
177
  });
161
178
  return list(questions["decisions"]);
162
179
  }
163
- function stoppedTicketIds(runs, now) {
180
+ function stoppedIssues(runs, context) {
164
181
  const stopped = runs
165
182
  .map((run) => run.status)
166
- .filter((status) => recentRun(status.latestAt, now) &&
183
+ .filter((status) => recentRun(status.latestAt, context.now) &&
167
184
  status["workflowId"] === "develop-issue" &&
168
185
  (["failed", "cancelled"].includes(status.state) ||
169
186
  (status.state === "completed" &&
@@ -171,16 +188,15 @@ function stoppedTicketIds(runs, now) {
171
188
  .toSorted((first, second) => Date.parse(second.latestAt ?? "") - Date.parse(first.latestAt ?? ""))
172
189
  .slice(0, 20);
173
190
  return new Set(stopped.flatMap((status) => {
174
- const ticketId = status["ticketId"];
175
- return status.state === "completed" &&
176
- record(status["outcome"])?.["ticketStatus"] !== "partial" &&
177
- record(status["outcome"])?.["issueUpdate"] !== "failed" &&
178
- typeof ticketId === "string" &&
179
- ticketId !== ""
180
- ? [ticketId]
191
+ const issue = establishedIssue(context.repository, status["issueIdentity"]);
192
+ return status.state === "completed" && issue !== null
193
+ ? [JSON.stringify(issue)]
181
194
  : [];
182
195
  }));
183
196
  }
197
+ function stageMetadata(value) {
198
+ return Object.fromEntries(Object.entries(record(value) ?? {}).flatMap(([workflowId, stages]) => isWorkflowStages(stages) ? [[workflowId, stages]] : []));
199
+ }
184
200
  async function service(reader, now) {
185
201
  const status = await asked(reader, {
186
202
  operation: "status",
@@ -194,20 +210,25 @@ async function service(reader, now) {
194
210
  const current = summaries.filter((summary) => activeRun(summary.state) || recentRun(summary.latestAt, now));
195
211
  for (const summary of current)
196
212
  runs.push(await detailed(reader, summary));
197
- const ticketIds = stoppedTicketIds(runs, now);
198
- const older = ticketIds.size === 0
213
+ const issues = stoppedIssues(runs, { now, repository: reader.repository });
214
+ const older = issues.size === 0
199
215
  ? []
200
216
  : summaries.filter((summary) => !recentRun(summary.latestAt, now) &&
201
217
  summary["workflowId"] === "develop-issue" &&
202
218
  summary.state === "completed");
203
219
  for (const summary of older) {
204
- const candidate = await completionOf(reader, { summary, ticketIds });
220
+ const candidate = await completionOf(reader, { summary, issues });
205
221
  if (candidate !== null)
206
222
  completionCandidates.push(candidate);
207
223
  }
208
224
  return {
209
225
  service: "up",
226
+ ...(record(status["queue"]) === undefined
227
+ ? {}
228
+ : { queue: record(status["queue"]) ?? {} }),
210
229
  workflows: list(status["workflows"]).filter((value) => typeof value === "string"),
230
+ workflowStages: stageMetadata(status["workflowStages"]),
231
+ workflowRefusals: workflowRefusals(status["workflowRefusals"]),
211
232
  summaries,
212
233
  runs,
213
234
  completionCandidates,
@@ -226,7 +247,7 @@ async function singleRun(reader, runId) {
226
247
  const status = statusOf(reply.result["run"]);
227
248
  const known = reader.details.get(runId);
228
249
  const value = known !== undefined && known.sequence === status.latestSequence
229
- ? known.value
250
+ ? refreshedLinks(known.value, status)
230
251
  : await remember(reader, status);
231
252
  return {
232
253
  ...unavailable,
@@ -235,9 +256,10 @@ async function singleRun(reader, runId) {
235
256
  decisions: await decisionsOf(reader),
236
257
  };
237
258
  }
238
- export function watchReader(runtimeDirectory) {
259
+ export function watchReader(runtimeDirectory, repository = null) {
239
260
  const reader = {
240
261
  runtimeDirectory,
262
+ repository,
241
263
  details: new Map(),
242
264
  completions: new Map(),
243
265
  };