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
@@ -55,21 +55,45 @@ export function CardReview(props) {
55
55
  ]),
56
56
  });
57
57
  }
58
- export function completionMark(card, workflowId) {
58
+ export function staleObservation(card, now) {
59
+ const observation = card.pullRequestObservation;
60
+ const lastSuccess = observation?.lastSuccess;
61
+ if (observation?.status === "merged" ||
62
+ lastSuccess?.status !== "unmerged" ||
63
+ !(Date.parse(now) - lastSuccess.readAt > 120000))
64
+ return null;
65
+ return [
66
+ " ",
67
+ element("span", { class: "completion-stale", children: "Stale" }),
68
+ ];
69
+ }
70
+ export function observationText(card, fallback) {
71
+ if (fallback !== "Needs attention")
72
+ return fallback;
73
+ const status = card.pullRequestObservation?.status;
74
+ if (status === "merged")
75
+ return `PR merged · #${String(card.pullRequestNumber)}`;
76
+ if (status === "pending")
77
+ return "Checking PR";
78
+ if (status === "unavailable")
79
+ return "PR status unavailable";
80
+ return fallback;
81
+ }
82
+ export function completionMark(card, context) {
59
83
  const mark = card.completionMark;
60
84
  if (mark === null)
61
85
  return null;
62
- let text = mark.text;
63
- const status = card.pullRequestObservation?.status;
64
- if (text === "Needs attention" && status === "merged")
65
- text = `PR merged #${String(card.pullRequestNumber)}`;
66
- if (text === "Needs attention" && status === "unavailable")
67
- text = "PR status unavailable";
86
+ const text = observationText(card, mark.text);
68
87
  if (mark.laterRunId === null)
69
- return element("span", { class: "completion-mark", children: text });
88
+ return [
89
+ element("span", { class: "completion-mark", children: text }),
90
+ mark.text === "Needs attention"
91
+ ? staleObservation(card, context.now)
92
+ : null,
93
+ ];
70
94
  return element("a", {
71
95
  class: "completion-mark",
72
- href: watchHash({ workflowId, runId: mark.laterRunId }),
96
+ href: watchHash({ workflowId: context.workflowId, runId: mark.laterRunId }),
73
97
  children: mark.text,
74
98
  });
75
99
  }
@@ -106,10 +130,28 @@ export function Card(props) {
106
130
  element("small", { children: card.runId.slice(0, 12) }),
107
131
  ],
108
132
  }),
109
- completionMark(card, workflowId),
133
+ completionMark(card, { workflowId, now: props.observationNow ?? now }),
134
+ component(HandoffLinks, { run: card }),
110
135
  ],
111
136
  });
112
137
  }
138
+ export function HandoffLinks(props) {
139
+ const { parentRunId, childRunIds, awaitedRunId } = props.run;
140
+ const links = [
141
+ ...(awaitedRunId == null
142
+ ? []
143
+ : [{ label: "Waiting for run", runId: awaitedRunId }]),
144
+ ...(parentRunId == null
145
+ ? []
146
+ : [{ label: "Parent run", runId: parentRunId }]),
147
+ ...(childRunIds ?? []).map((runId) => ({ label: "Child run", runId })),
148
+ ];
149
+ return links.map(({ label, runId }) => element("a", {
150
+ class: "meta",
151
+ href: watchHash({ workflowId: null, runId }),
152
+ children: `${label}: ${runId}`,
153
+ }));
154
+ }
113
155
  export function WorkflowList(props) {
114
156
  return element("nav", {
115
157
  class: "workflows",
@@ -167,7 +209,13 @@ export function Column(props) {
167
209
  : element("div", {
168
210
  class: "column-cards",
169
211
  children: [
170
- column.cards.map((card) => component(Card, { key: card.runId, card, workflowId, now })),
212
+ column.cards.map((card) => component(Card, {
213
+ key: card.runId,
214
+ card,
215
+ workflowId,
216
+ now,
217
+ observationNow: props.observationNow,
218
+ })),
171
219
  props.addCard,
172
220
  ],
173
221
  }),
@@ -179,7 +227,10 @@ export function Board(props) {
179
227
  return element("main", {
180
228
  class: "board",
181
229
  children: [
182
- element("h2", { children: workflow.workflowId }),
230
+ element("h2", {
231
+ class: "visually-hidden",
232
+ children: workflow.workflowId,
233
+ }),
183
234
  element("div", {
184
235
  class: "columns",
185
236
  children: workflow.columns.map((column, index) => component(Column, {
@@ -187,6 +238,7 @@ export function Board(props) {
187
238
  column,
188
239
  workflowId: workflow.workflowId,
189
240
  now,
241
+ observationNow: props.observationNow,
190
242
  controls: props.controls,
191
243
  addCard: index === 0
192
244
  ? component(AddCard, {
@@ -1,11 +1,17 @@
1
+ import type { WorkflowStage, WorkflowStages } from "../workflow-declaration.ts";
1
2
  import type { WatchCompletionMark, WatchRun, WatchStep, WatchWorkflow } from "./watch-render.ts";
2
3
  export declare function completionMarkOf(run: WatchRun, candidates: readonly WatchRun[]): WatchCompletionMark | null;
3
4
  export declare function activeRun(state: string): boolean;
4
5
  export declare function recentRun(latestAt: string | null, now: string): boolean;
5
- export declare function currentStepOf(events: readonly unknown[], workflowId: string): WatchStep;
6
+ export declare function stagesFor(metadata: WorkflowStages | undefined, workflowId: string): readonly WorkflowStage[] | undefined;
7
+ export declare function currentStepOf(events: readonly unknown[], workflow: {
8
+ readonly workflowId: string;
9
+ readonly stages: readonly WorkflowStage[] | undefined;
10
+ }): WatchStep;
6
11
  export declare function roundOf(events: readonly unknown[]): number;
7
12
  interface BoardInputs {
8
13
  readonly workflows: readonly string[];
14
+ readonly workflowStages?: WorkflowStages;
9
15
  readonly updatedAt: string;
10
16
  readonly summaries?: readonly unknown[];
11
17
  readonly completionCandidates?: readonly WatchRun[];
@@ -1,6 +1,8 @@
1
+ import { linksOf } from "../authority/handoff-chain.js";
1
2
  import { record } from "../protocol.js";
2
3
  import { isInstant } from "../authority/instants.js";
3
4
  import { issueSteps } from "./watch-phases.js";
5
+ import { sameIssue } from "./watch-pr-identity.js";
4
6
  const weekMilliseconds = 7 * 24 * 60 * 60 * 1000;
5
7
  const terminalStates = ["completed", "failed", "cancelled"];
6
8
  function eventTime(run, type) {
@@ -12,11 +14,15 @@ export function completionMarkOf(run, candidates) {
12
14
  run.state !== "completed" ||
13
15
  run.outcome !== "blocked")
14
16
  return null;
17
+ if (run.mergeProof != null)
18
+ return {
19
+ text: `PR merged · #${String(run.mergeProof.number)}`,
20
+ laterRunId: null,
21
+ };
15
22
  const completedAt = eventTime(run, "run.completed");
16
23
  const later = candidates
17
- .filter((candidate) => typeof run.ticketId === "string" &&
18
- run.ticketId !== "" &&
19
- candidate.ticketId === run.ticketId &&
24
+ .filter((candidate) => sameIssue(run.issueIdentity, candidate.issueIdentity) &&
25
+ candidate.mergeProof != null &&
20
26
  candidate.runId !== run.runId &&
21
27
  candidate.workflowId === "develop-issue" &&
22
28
  candidate.state === "completed" &&
@@ -32,7 +38,7 @@ export function completionMarkOf(run, candidates) {
32
38
  (first.runId < second.runId ? -1 : 1))[0];
33
39
  return later === undefined
34
40
  ? { text: "Needs attention", laterRunId: null }
35
- : { text: "Done in a later run", laterRunId: later.runId };
41
+ : { text: "Ticket completed by later run", laterRunId: later.runId };
36
42
  }
37
43
  export function activeRun(state) {
38
44
  return !terminalStates.includes(state);
@@ -41,10 +47,17 @@ export function recentRun(latestAt, now) {
41
47
  const age = Date.parse(now) - Date.parse(latestAt ?? "");
42
48
  return age >= 0 && age <= weekMilliseconds;
43
49
  }
44
- function stepNames(workflowId) {
50
+ export function stagesFor(metadata, workflowId) {
51
+ return metadata !== undefined && Object.hasOwn(metadata, workflowId)
52
+ ? metadata[workflowId]
53
+ : undefined;
54
+ }
55
+ function stepNames(workflowId, stages) {
56
+ if (workflowId !== "develop-issue" && stages !== undefined)
57
+ return [...stages.map((stage) => stage.label), "Other"];
45
58
  return workflowId === "develop-issue"
46
59
  ? issueSteps.map((step) => step.name)
47
- : ["Claude turn", "Your review"];
60
+ : ["Agent turn", "Your review"];
48
61
  }
49
62
  function operationOf(event) {
50
63
  const payload = record(record(event)?.["payload"]);
@@ -63,7 +76,7 @@ function stepName(event, workflowId) {
63
76
  if (type !== "effect.requested")
64
77
  return undefined;
65
78
  if (workflowId !== "develop-issue")
66
- return "Claude turn";
79
+ return "Agent turn";
67
80
  return issueSteps.find((step) => step.operation === operationOf(event)[4])
68
81
  ?.name;
69
82
  }
@@ -74,10 +87,30 @@ function startedAt(event) {
74
87
  function chronological(events) {
75
88
  return events.toSorted((first, second) => Date.parse(startedAt(first) ?? "") - Date.parse(startedAt(second) ?? ""));
76
89
  }
77
- export function currentStepOf(events, workflowId) {
90
+ function declaredStage(event, stages) {
91
+ if (record(event)?.["type"] === "effect.requested") {
92
+ const operation = operationOf(event)[4];
93
+ return stages.find((stage) => stage.operations?.some((name) => name === operation));
94
+ }
95
+ const payload = record(record(event)?.["payload"]);
96
+ return (stages.find((stage) => stage.gateIds?.some((name) => name === payload?.["gateId"])) ??
97
+ stages.find((stage) => stage.gateKinds?.some((name) => name === payload?.["gateKind"])));
98
+ }
99
+ function declaredStep(events, stages) {
100
+ const event = events
101
+ .filter((item) => ["effect.requested", "gate.opened"].includes(String(record(item)?.["type"])))
102
+ .toSorted((first, second) => Number(record(second)?.["sequence"]) -
103
+ Number(record(first)?.["sequence"]))[0];
104
+ const stage = declaredStage(event, stages);
105
+ return { name: stage?.label ?? "Other", startedAt: startedAt(event) };
106
+ }
107
+ export function currentStepOf(events, workflow) {
108
+ const { workflowId, stages } = workflow;
109
+ if (workflowId !== "develop-issue" && stages !== undefined)
110
+ return declaredStep(events, stages);
78
111
  const event = chronological(events).findLast((item) => stepName(item, workflowId) !== undefined);
79
112
  return {
80
- name: stepName(event, workflowId) ?? stepNames(workflowId)[0] ?? "Claude turn",
113
+ name: stepName(event, workflowId) ?? stepNames(workflowId)[0] ?? "Agent turn",
81
114
  startedAt: startedAt(event),
82
115
  };
83
116
  }
@@ -96,11 +129,20 @@ function columnOf(run, now) {
96
129
  return "Stopped";
97
130
  return run.outcome === "handoff_requested" ? "Done" : null;
98
131
  }
99
- function cardOf(run, runs) {
132
+ function issueCardDetails(run) {
100
133
  const issue = run.workflowId === "develop-issue";
134
+ return {
135
+ round: issue ? run.round : null,
136
+ greptileScore: issue ? (run.reviews.at(-1)?.score ?? null) : null,
137
+ pullRequestNumber: issue ? (run.pullRequest?.number ?? null) : null,
138
+ };
139
+ }
140
+ function cardOf(run, runs) {
101
141
  return {
102
142
  runId: run.runId,
103
143
  title: run.title,
144
+ ...linksOf(run),
145
+ ...(run.awaitedRunId == null ? {} : { awaitedRunId: run.awaitedRunId }),
104
146
  completionMark: completionMarkOf(run, runs),
105
147
  pullRequestObservation: null,
106
148
  claudeCostUsd: run.claudeCostUsd,
@@ -109,9 +151,7 @@ function cardOf(run, runs) {
109
151
  currentStep: activeRun(run.state) ? run.currentStep : null,
110
152
  endedAt: activeRun(run.state) ? null : run.latestAt,
111
153
  decisionWaiting: run.decisions.length > 0,
112
- round: issue ? run.round : null,
113
- greptileScore: issue ? (run.reviews.at(-1)?.score ?? null) : null,
114
- pullRequestNumber: issue ? (run.pullRequest?.number ?? null) : null,
154
+ ...issueCardDetails(run),
115
155
  };
116
156
  }
117
157
  function stepOrder(first, second) {
@@ -133,7 +173,8 @@ function summaryOf(value) {
133
173
  const latest = fields?.["latestAt"];
134
174
  return {
135
175
  state: String(fields?.["state"]),
136
- waiting: Array.isArray(pending) && pending.length > 0,
176
+ waiting: (Array.isArray(pending) && pending.length > 0) ||
177
+ typeof fields?.["awaitedRunId"] === "string",
137
178
  latestAt: typeof latest === "string" ? latest : null,
138
179
  };
139
180
  }
@@ -143,13 +184,17 @@ export function boardsOf(inputs, runs) {
143
184
  const summaries = inputs.summaries === undefined
144
185
  ? own.map((run) => ({
145
186
  state: run.state,
146
- waiting: run.decisions.length > 0,
187
+ waiting: run.decisions.length > 0 || run.awaitedRunId != null,
147
188
  latestAt: run.latestAt,
148
189
  }))
149
190
  : inputs.summaries
150
191
  .filter((value) => record(value)?.["workflowId"] === workflowId)
151
192
  .map(summaryOf);
152
- const columns = [...stepNames(workflowId), "Done", "Stopped"].map((name) => {
193
+ const columns = [
194
+ ...stepNames(workflowId, stagesFor(inputs.workflowStages, workflowId)),
195
+ "Done",
196
+ "Stopped",
197
+ ].map((name) => {
153
198
  const cards = own
154
199
  .filter((run) => columnOf(run, inputs.updatedAt) === name)
155
200
  .map((run) => cardOf(run, inputs.completionCandidates ?? runs));
@@ -14,7 +14,7 @@ export async function watchCardForms(directory) {
14
14
  if (!isWorkflowDeclaration(value))
15
15
  continue;
16
16
  const entries = Object.entries(value.input.fields);
17
- if (!entries.every(([, rule]) => rule === "string" || rule.type === "string"))
17
+ if (!entries.every(([, rule]) => rule === "string" || rule.type === "string" || rule.type === "ticket"))
18
18
  continue;
19
19
  if (forms.some((form) => form.workflowId === value.workflowId))
20
20
  continue;
@@ -23,7 +23,7 @@ export async function watchCardForms(directory) {
23
23
  source: "input",
24
24
  fields: entries.map(([name, rule]) => ({
25
25
  name,
26
- label: name,
26
+ label: rule !== "string" && rule.type === "ticket" ? "Ticket ID" : name,
27
27
  multiline: false,
28
28
  optional: rule !== "string" && rule.optional === true,
29
29
  })),
@@ -1 +1 @@
1
- export declare const watchClient = "\nconst state = { model: null, stale: false, copied: \"\", label: \"\", run: \"\", loading: false, again: false, columns: {}, cards: {}, start: null, hovered: null, focused: null };\nfunction readPreference(key) {\n try { return JSON.parse(localStorage.getItem(key)); }\n catch { return null; }\n}\nfunction readColumnChoices(key) {\n const value = readPreference(key);\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n return Object.fromEntries(Object.entries(value).filter(([, choice]) => typeof choice === \"boolean\"));\n}\nfunction savePreference(key, value) {\n try { localStorage.setItem(key, JSON.stringify(value)); }\n catch {}\n}\nfunction startControls() {\n if (state.start === null) state.start = readPreference(\"cloving.watch.start\") === true;\n return { shown: state.start, onToggle() {\n state.start = !state.start;\n savePreference(\"cloving.watch.start\", state.start);\n draw();\n } };\n}\nfunction columnControls(model, selected) {\n const workflowId = model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId);\n if (workflowId === null) return undefined;\n const key = \"cloving.watch.columns:\" + workflowId;\n if (!Object.hasOwn(state.columns, workflowId))\n state.columns = { ...state.columns, [workflowId]: readColumnChoices(key) };\n const choices = state.columns[workflowId];\n return { choices, onHover(name) { state.hovered = name; }, onFocus(name) { state.focused = name; }, onToggle(name) {\n const changed = { ...choices, [name]: !columnCollapsed(choices, name) };\n state.columns = { ...state.columns, [workflowId]: changed };\n savePreference(key, changed);\n draw();\n } };\n}\nfunction moved(next, followed) {\n const arrived = next === \"waiting_gate\" && next !== state.run;\n state.run = next;\n if (arrived) scrollTo(0, 0);\n else if (followed && next === \"running\") scrollTo(0, document.body.scrollHeight);\n}\nfunction copy(command) {\n const shown = (label) => {\n state.copied = command;\n state.label = label;\n draw();\n };\n navigator.clipboard.writeText(command).then(\n () => { shown(\"Copied\"); },\n () => { shown(\"Copy failed\"); },\n );\n}\nfunction draw() {\n const { model, stale } = state;\n const selected = location.hash.slice(1);\n const followed = innerHeight + scrollY >= document.body.scrollHeight - 80;\n const copying = { command: state.copied, label: state.label, onCopy: copy };\n const now = new Date().toISOString();\n const columns = columnControls(model, selected);\n const start = model === null ? undefined : startControls();\n const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));\n const page = component(Page, { model, selected, now, stale, copying, columns, start, cards });\n render(page, document.getElementById(\"app\"));\n if (model === null) return;\n document.title = watchTitle(model, selected);\n const { runId } = watchLocation(selected);\n moved(model.runs.find((run) => run.runId === runId)?.state ?? \"\", followed);\n}\nasync function withSelectedRun(model) {\n const { runId } = watchLocation(location.hash);\n if (runId === null || model.runs.some((run) => run.runId === runId)) return model;\n const detail = await fetch(\"data.json?runId=\" + encodeURIComponent(runId), { cache: \"no-store\" });\n if (detail.status === 404) return model;\n if (!detail.ok) throw new Error(\"watch-run-not-available\");\n const { run } = await detail.json();\n if (run?.runId !== runId) throw new Error(\"watch-run-mismatch\");\n return { ...model, runs: [...model.runs, run] };\n}\nasync function load() {\n state.again = state.loading;\n if (state.loading) return;\n state.loading = true;\n try {\n const reply = await fetch(\"data.json\", { cache: \"no-store\" });\n if (!reply.ok) throw new Error(\"watch-not-available\");\n state.model = await withSelectedRun(await reply.json());\n state.stale = false;\n } catch {\n state.stale = true;\n }\n state.loading = false;\n draw();\n if (state.again) load();\n}\nfunction listen() {\n const source = new EventSource(\"events\");\n source.onmessage = () => { load(); };\n source.onerror = () => { state.stale = true; draw(); };\n}\naddEventListener(\"keydown\", (event) => {\n if (event.key !== String.fromCharCode(92) || event.defaultPrevented || event.repeat || event.isComposing) return;\n if (event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) return;\n if (event.target?.closest?.(\"input, textarea, select, [contenteditable]\")) return;\n const target = state.hovered ?? state.focused;\n if (target === null || watchLocation(location.hash).runId !== null) return;\n const controls = columnControls(state.model, location.hash);\n if (controls === undefined) return;\n event.preventDefault();\n controls.onToggle(target);\n});\naddEventListener(\"hashchange\", () => { state.run = \"\"; state.hovered = null; state.focused = null; draw(); load(); });\ndraw();\nlisten();\nsetInterval(draw, 1000);\nsetInterval(load, 15000);\n";
1
+ export declare const watchClient = "\nconst state = { model: null, receivedAt: 0, stale: false, copied: \"\", label: \"\", run: \"\", loading: false, again: false, columns: {}, cards: {}, start: null, hovered: null, focused: null, phonePairing: null, phoneBusy: false, phoneMessage: \"\", phone: null, phoneLoadedAt: 0, phoneAccepted: null, phoneSequence: 0, phoneApplied: 0 };\nfunction readPreference(key) {\n try { return JSON.parse(localStorage.getItem(key)); }\n catch { return null; }\n}\nfunction readColumnChoices(key) {\n const value = readPreference(key);\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n return Object.fromEntries(Object.entries(value).filter(([, choice]) => typeof choice === \"boolean\"));\n}\nfunction savePreference(key, value) {\n try { localStorage.setItem(key, JSON.stringify(value)); }\n catch {}\n}\nfunction startControls() {\n if (state.start === null) state.start = readPreference(\"cloving.watch.start\") === true;\n return { shown: state.start, onToggle() {\n state.start = !state.start;\n savePreference(\"cloving.watch.start\", state.start);\n draw();\n } };\n}\nfunction columnControls(model, selected) {\n const workflowId = model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId);\n if (workflowId === null) return undefined;\n const key = \"cloving.watch.columns:\" + workflowId;\n if (!Object.hasOwn(state.columns, workflowId))\n state.columns = { ...state.columns, [workflowId]: readColumnChoices(key) };\n const choices = state.columns[workflowId];\n return { choices, onHover(name) { state.hovered = name; }, onFocus(name) { state.focused = name; }, onToggle(name) {\n const changed = { ...choices, [name]: !columnCollapsed(choices, name) };\n state.columns = { ...state.columns, [workflowId]: changed };\n savePreference(key, changed);\n draw();\n } };\n}\nfunction moved(next, followed) {\n const arrived = next === \"waiting_gate\" && next !== state.run;\n state.run = next;\n if (arrived) scrollTo(0, 0);\n else if (followed && next === \"running\") scrollTo(0, document.body.scrollHeight);\n}\nfunction copy(command) {\n const shown = (label) => {\n state.copied = command;\n state.label = label;\n draw();\n };\n navigator.clipboard.writeText(command).then(\n () => { shown(\"Copied\"); },\n () => { shown(\"Copy failed\"); },\n );\n}\nfunction draw() {\n const { model, stale } = state;\n const selected = location.hash.slice(1);\n const followed = innerHeight + scrollY >= document.body.scrollHeight - 80;\n const copying = { command: state.copied, label: state.label, onCopy: copy };\n const now = new Date().toISOString();\n const observationNow = model === null ? now : new Date(Date.parse(model.updatedAt) + performance.now() - state.receivedAt).toISOString();\n const columns = columnControls(model, selected);\n const start = model === null ? undefined : startControls();\n const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));\n const phone = model === null ? undefined : phoneControls(now);\n const page = component(Page, { model, selected, now, observationNow, stale, copying, columns, start, cards, phone });\n render(page, document.getElementById(\"app\"));\n if (model === null) return;\n document.title = watchTitle(model, selected);\n const { runId } = watchLocation(selected);\n moved(model.runs.find((run) => run.runId === runId)?.state ?? \"\", followed);\n}\nasync function withSelectedRun(model) {\n const { runId } = watchLocation(location.hash);\n if (runId === null || model.runs.some((run) => run.runId === runId)) return model;\n const detail = await fetch(\"data.json?runId=\" + encodeURIComponent(runId), { cache: \"no-store\" });\n if (detail.status === 404) return model;\n if (!detail.ok) throw new Error(\"watch-run-not-available\");\n const { run } = await detail.json();\n if (run?.runId !== runId) throw new Error(\"watch-run-mismatch\");\n return { ...model, runs: [...model.runs, run] };\n}\nasync function load() {\n state.again = state.loading;\n if (state.loading) return;\n state.loading = true;\n try {\n const reply = await fetch(\"data.json\", { cache: \"no-store\" });\n if (!reply.ok) throw new Error(\"watch-not-available\");\n const model = await reply.json();\n const receivedAt = performance.now();\n state.model = await withSelectedRun(model);\n state.receivedAt = receivedAt;\n state.stale = false;\n } catch {\n state.stale = true;\n }\n state.loading = false;\n draw();\n if (state.again) load();\n}\nfunction listen() {\n const source = new EventSource(\"events\");\n source.onmessage = () => { load(); };\n source.onerror = () => { state.stale = true; draw(); };\n}\naddEventListener(\"keydown\", (event) => {\n if (event.key !== String.fromCharCode(92) || event.defaultPrevented || event.repeat || event.isComposing) return;\n if (event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) return;\n if (event.target?.closest?.(\"input, textarea, select, [contenteditable]\")) return;\n const target = state.hovered ?? state.focused;\n if (target === null || watchLocation(location.hash).runId !== null) return;\n const controls = columnControls(state.model, location.hash);\n if (controls === undefined) return;\n event.preventDefault();\n controls.onToggle(target);\n});\naddEventListener(\"hashchange\", () => { state.run = \"\"; state.hovered = null; state.focused = null; draw(); load(); });\ndraw();\nlisten();\nsetInterval(draw, 1000);\nsetInterval(load, 15000);\nif (actionToken !== null) {\n phoneLoad();\n setInterval(phoneLoad, 2000);\n}\n";
@@ -1,5 +1,5 @@
1
1
  export const watchClient = `
2
- const state = { model: null, stale: false, copied: "", label: "", run: "", loading: false, again: false, columns: {}, cards: {}, start: null, hovered: null, focused: null };
2
+ const state = { model: null, receivedAt: 0, stale: false, copied: "", label: "", run: "", loading: false, again: false, columns: {}, cards: {}, start: null, hovered: null, focused: null, phonePairing: null, phoneBusy: false, phoneMessage: "", phone: null, phoneLoadedAt: 0, phoneAccepted: null, phoneSequence: 0, phoneApplied: 0 };
3
3
  function readPreference(key) {
4
4
  try { return JSON.parse(localStorage.getItem(key)); }
5
5
  catch { return null; }
@@ -58,10 +58,12 @@ function draw() {
58
58
  const followed = innerHeight + scrollY >= document.body.scrollHeight - 80;
59
59
  const copying = { command: state.copied, label: state.label, onCopy: copy };
60
60
  const now = new Date().toISOString();
61
+ const observationNow = model === null ? now : new Date(Date.parse(model.updatedAt) + performance.now() - state.receivedAt).toISOString();
61
62
  const columns = columnControls(model, selected);
62
63
  const start = model === null ? undefined : startControls();
63
64
  const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));
64
- const page = component(Page, { model, selected, now, stale, copying, columns, start, cards });
65
+ const phone = model === null ? undefined : phoneControls(now);
66
+ const page = component(Page, { model, selected, now, observationNow, stale, copying, columns, start, cards, phone });
65
67
  render(page, document.getElementById("app"));
66
68
  if (model === null) return;
67
69
  document.title = watchTitle(model, selected);
@@ -85,7 +87,10 @@ async function load() {
85
87
  try {
86
88
  const reply = await fetch("data.json", { cache: "no-store" });
87
89
  if (!reply.ok) throw new Error("watch-not-available");
88
- state.model = await withSelectedRun(await reply.json());
90
+ const model = await reply.json();
91
+ const receivedAt = performance.now();
92
+ state.model = await withSelectedRun(model);
93
+ state.receivedAt = receivedAt;
89
94
  state.stale = false;
90
95
  } catch {
91
96
  state.stale = true;
@@ -115,4 +120,8 @@ draw();
115
120
  listen();
116
121
  setInterval(draw, 1000);
117
122
  setInterval(load, 15000);
123
+ if (actionToken !== null) {
124
+ phoneLoad();
125
+ setInterval(phoneLoad, 2000);
126
+ }
118
127
  `;
@@ -0,0 +1,27 @@
1
+ import { type PhoneControls } from "./watch-phone-view.ts";
2
+ import { type Shown } from "./watch-element.ts";
3
+ import { type WatchModel } from "./watch-render.ts";
4
+ export interface StartControls {
5
+ readonly shown: boolean;
6
+ readonly onToggle: () => void;
7
+ }
8
+ export interface HeaderProps {
9
+ readonly model: WatchModel | null;
10
+ readonly stale: boolean;
11
+ readonly start?: StartControls;
12
+ readonly phone?: PhoneControls | undefined;
13
+ readonly now?: string;
14
+ }
15
+ export declare const clove: {
16
+ viewBox: string;
17
+ paths: string[];
18
+ };
19
+ export declare function queueLanes(model: WatchModel): string | null;
20
+ export declare function skippedText(value: unknown): string;
21
+ export declare function Queue(props: {
22
+ readonly model: WatchModel;
23
+ }): Shown;
24
+ export declare function Brand(): Shown;
25
+ export declare function HeaderStatus(props: HeaderProps): Shown;
26
+ export declare function HeaderActions(props: HeaderProps): Shown;
27
+ export declare function Header(props: HeaderProps): Shown;
@@ -0,0 +1,116 @@
1
+ import { record } from "../protocol.js";
2
+ import { PhonePanel } from "./watch-phone-view.js";
3
+ import { component, element } from "./watch-element.js";
4
+ import { clockTime, counted } from "./watch-render.js";
5
+ export const clove = {
6
+ viewBox: "0.6625858545303345 0.6630800366401672 46.674827575683594 46.673831939697266",
7
+ paths: [
8
+ "M41.47315,11.48535c-1.20117-0.12305-2.16211-1.08398-2.28418-2.28516c-0.17676-1.7334-1.01758-3.29492-2.36865-4.39648s-3.05078-1.61719-4.7832-1.43359c-3.34277,0.34082-5.86377,3.13086-5.86377,6.49121v14.13867c0,0.27637,0.22363,0.5,0.5,0.5H40.8125c3.59766,0,6.52441-2.92676,6.52441-6.52441C47.33692,14.61523,44.81592,11.82422,41.47315,11.48535z M35.56543,15.81543l-5.85791,5.85742c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648c-0.19531-0.19531-0.19531-0.51172,0-0.70703l5.85791-5.85742c0.19531-0.19531,0.51172-0.19531,0.70703,0C35.76073,15.30372,35.76074,15.62011,35.56543,15.81543z",
9
+ "M15.30225,0.66308c-3.36035,0-6.15088,2.52051-6.49121,5.86328C8.68897,7.72852,7.72852,8.68945,6.52686,8.81152c-1.7334,0.17578-3.29492,1.01758-4.396,2.36816s-1.61035,3.0498-1.43408,4.7832c0.34033,3.34277,3.13086,5.86328,6.49121,5.86328h14.13867c0.27637,0,0.5-0.22363,0.5-0.5V7.18751C21.82666,3.58984,18.8999,0.66308,15.30225,0.66308z M18.99951,19.00001c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648l-5.85742-5.8584c-0.19531-0.19531-0.19531-0.51172,0-0.70703c0.19531-0.19531,0.51172-0.19531,0.70703,0l5.85742,5.8584C19.19482,18.48829,19.19482,18.80469,18.99951,19.00001z",
10
+ "M24,26.17383H9.86133c-3.59766,0-6.52441,2.92676-6.52441,6.52441c0,3.35938,2.52051,6.14941,5.86377,6.49023c1.20117,0.12207,2.16211,1.08301,2.28418,2.28418c0.17676,1.7334,1.01758,3.29492,2.36865,4.39648c1.17529,0.95801,2.61377,1.46777,4.11035,1.46777c0.22314,0,0.44775-0.01074,0.67285-0.03418C21.97949,46.96189,24.5,44.17186,24.5,40.81248V26.67383C24.5,26.39746,24.27637,26.17383,24,26.17383z M21.67334,29.70704l-5.85791,5.8584c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648c-0.19531-0.19531-0.19531-0.51172,0-0.70703L20.9663,29c0.19531-0.19531,0.51172-0.19531,0.70703,0S21.86865,29.51172,21.67334,29.70704z",
11
+ "M47.30322,32.03711c-0.34033-3.34277-3.13086-5.86328-6.49072-5.86328H26.67334c-0.27637,0-0.5,0.22363-0.5,0.5V40.8125c0,3.59766,2.92676,6.52441,6.52442,6.52441c3.36035,0,6.15088-2.52148,6.49121-5.86426c0.12207-1.20117,1.08301-2.16211,2.28418-2.28418c1.7334-0.17578,3.29492-1.01758,4.396-2.36816S47.47949,33.7705,47.30322,32.03711z M35.56543,35.56543c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648l-5.85791-5.8584c-0.19531-0.19531-0.19531-0.51172,0-0.70703s0.51172-0.19531,0.70703,0l5.85791,5.8584C35.76074,35.05371,35.76074,35.37011,35.56543,35.56543z",
12
+ ],
13
+ };
14
+ export function queueLanes(model) {
15
+ const queue = model.queue;
16
+ if (queue === undefined)
17
+ return null;
18
+ return `Queue: ${String(queue["busy"])} of ${String(queue["lanes"])} lanes busy`;
19
+ }
20
+ export function skippedText(value) {
21
+ const ticket = record(value) ?? {};
22
+ const name = `#${String(ticket["ticketId"])}`;
23
+ const dependencies = ticket["dependencies"];
24
+ if (ticket["reason"] === "ticket-dependency-open" &&
25
+ Array.isArray(dependencies))
26
+ return `${name} waits for ${dependencies.map((item) => `#${String(item)}`).join(", ")}`;
27
+ if (ticket["reason"] === "ticket-active")
28
+ return `${name} is in work`;
29
+ return `${name}: ${String(ticket["reason"])}`;
30
+ }
31
+ export function Queue(props) {
32
+ const skipped = props.model.queue?.["skipped"];
33
+ if (!Array.isArray(skipped) || skipped.length === 0)
34
+ return null;
35
+ return element("details", {
36
+ class: "queue-waiting",
37
+ children: [
38
+ element("summary", {
39
+ children: `${counted(skipped.length, "ticket")} skipped`,
40
+ }),
41
+ element("ul", {
42
+ children: skipped.map((value) => element("li", { children: skippedText(value) })),
43
+ }),
44
+ ],
45
+ });
46
+ }
47
+ export function Brand() {
48
+ return element("strong", {
49
+ class: "brand",
50
+ children: [
51
+ element("svg", {
52
+ xmlns: "http://www.w3.org/2000/svg",
53
+ "aria-hidden": "true",
54
+ focusable: "false",
55
+ viewBox: clove.viewBox,
56
+ children: clove.paths.map((d) => element("path", { fill: "currentColor", d })),
57
+ }),
58
+ "cloving",
59
+ ],
60
+ });
61
+ }
62
+ export function HeaderStatus(props) {
63
+ const { model, stale } = props;
64
+ const updated = model === null ? "" : `updated ${clockTime(model.updatedAt)}`;
65
+ const stamp = stale
66
+ ? element("span", {
67
+ class: "bad",
68
+ children: "The watch tool does not answer.",
69
+ })
70
+ : element("span", { children: updated });
71
+ const lanes = model === null ? null : queueLanes(model);
72
+ return element("div", {
73
+ class: "header-status",
74
+ children: [
75
+ stamp,
76
+ lanes === null
77
+ ? null
78
+ : element("span", { class: "queue-lanes", children: lanes }),
79
+ ],
80
+ });
81
+ }
82
+ export function HeaderActions(props) {
83
+ const { start, phone } = props;
84
+ if (start === undefined && phone === undefined)
85
+ return null;
86
+ return element("div", {
87
+ class: "header-actions",
88
+ children: [
89
+ start === undefined
90
+ ? null
91
+ : element("button", {
92
+ type: "button",
93
+ class: "start-toggle",
94
+ "aria-controls": "start-run",
95
+ "aria-expanded": String(start.shown),
96
+ onClick: start.onToggle,
97
+ children: "Start a run",
98
+ }),
99
+ phone === undefined
100
+ ? null
101
+ : component(PhonePanel, {
102
+ phone,
103
+ now: props.now ?? props.model?.updatedAt ?? "",
104
+ }),
105
+ ],
106
+ });
107
+ }
108
+ export function Header(props) {
109
+ return element("header", {
110
+ children: [
111
+ component(Brand, {}),
112
+ component(HeaderStatus, props),
113
+ component(HeaderActions, props),
114
+ ],
115
+ });
116
+ }
@@ -1,4 +1,10 @@
1
+ import type { WorkflowStages } from "../workflow-declaration.ts";
2
+ import { type WorkflowRefusal } from "../workflow-refusals.ts";
1
3
  import type { WatchDecision, WatchItem, WatchModel, WatchTurn } from "./watch-render.ts";
4
+ import { type GithubRecords } from "./watch-pull-request.ts";
5
+ export type { GithubRecords } from "./watch-pull-request.ts";
6
+ import { type PrRepository } from "./watch-pr-identity.ts";
7
+ type Fields = Readonly<Record<string, unknown>>;
2
8
  export declare function activityOf(line: string): WatchItem[];
3
9
  export interface TurnRecords {
4
10
  readonly key: string;
@@ -10,7 +16,11 @@ export interface TurnRecords {
10
16
  export declare function turnOf(records: TurnRecords): WatchTurn;
11
17
  export declare function decisionCommands(decision: unknown, client: string): WatchDecision;
12
18
  export interface WatchInputs {
19
+ readonly queue?: Fields;
20
+ readonly repository?: PrRepository | null;
13
21
  readonly workflows: readonly string[];
22
+ readonly workflowRefusals?: readonly WorkflowRefusal[];
23
+ readonly workflowStages?: WorkflowStages;
14
24
  readonly summaries?: readonly unknown[];
15
25
  readonly home: string;
16
26
  readonly client: string;
@@ -22,8 +32,4 @@ export interface WatchInputs {
22
32
  readonly turns: readonly WatchTurn[];
23
33
  readonly githubRecords: readonly GithubRecords[];
24
34
  }
25
- export interface GithubRecords {
26
- readonly started: unknown;
27
- readonly result: unknown;
28
- }
29
35
  export declare function watchModel(inputs: WatchInputs): WatchModel;