cloving 1.2.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 (518) hide show
  1. package/README.md +525 -185
  2. package/dist/src/agent-harness-shell.d.ts +12 -0
  3. package/dist/src/agent-harness-shell.js +90 -0
  4. package/dist/src/agent-harness-versions.d.ts +8 -0
  5. package/dist/src/agent-harness-versions.js +49 -0
  6. package/dist/src/agent-harnesses.d.ts +4 -0
  7. package/dist/src/agent-harnesses.js +13 -0
  8. package/dist/src/authority/commands.d.ts +1 -0
  9. package/dist/src/authority/commands.js +24 -4
  10. package/dist/src/authority/gate-reduction.d.ts +1 -0
  11. package/dist/src/authority/gate-reduction.js +18 -3
  12. package/dist/src/authority/gates.d.ts +2 -1
  13. package/dist/src/authority/gates.js +5 -1
  14. package/dist/src/authority/operations.js +1 -1
  15. package/dist/src/authority/reduction.d.ts +1 -1
  16. package/dist/src/authority/reduction.js +6 -1
  17. package/dist/src/authority/status-input.d.ts +1 -1
  18. package/dist/src/authority/status.d.ts +1 -0
  19. package/dist/src/authority/status.js +27 -3
  20. package/dist/src/authority/transitions.d.ts +5 -5
  21. package/dist/src/authority/transitions.js +6 -0
  22. package/dist/src/broker/actor/authority-delivery.js +1 -0
  23. package/dist/src/broker/actor/authority-queries.d.ts +7 -1
  24. package/dist/src/broker/actor/authority-queries.js +17 -2
  25. package/dist/src/broker/actor/authority-receipts.js +11 -1
  26. package/dist/src/broker/actor/authority-session.js +2 -2
  27. package/dist/src/broker/actor/authority-settings.js +4 -0
  28. package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
  29. package/dist/src/broker/actor/delivery-intents.js +4 -4
  30. package/dist/src/broker/actor/effect-delivery.js +4 -1
  31. package/dist/src/broker/actor/effect-queries.d.ts +1 -0
  32. package/dist/src/broker/actor/effect-queries.js +7 -0
  33. package/dist/src/broker/actor/pin-check.js +1 -1
  34. package/dist/src/broker/actor/stop-plan.js +1 -1
  35. package/dist/src/broker/actor/turn-state.js +1 -1
  36. package/dist/src/broker/authority-admission.js +22 -9
  37. package/dist/src/broker/authority-restore.js +1 -0
  38. package/dist/src/broker/decision-restore.js +4 -4
  39. package/dist/src/broker/socket-address.d.ts +3 -1
  40. package/dist/src/broker/socket-address.js +2 -2
  41. package/dist/src/cli/arguments.d.ts +11 -13
  42. package/dist/src/cli/arguments.js +37 -107
  43. package/dist/src/cli/command-effects.d.ts +7 -0
  44. package/dist/src/cli/command-effects.js +39 -0
  45. package/dist/src/cli/commands.js +11 -4
  46. package/dist/src/cli/config-arguments.d.ts +11 -0
  47. package/dist/src/cli/config-arguments.js +59 -0
  48. package/dist/src/cli/config-command.d.ts +2 -0
  49. package/dist/src/cli/config-command.js +105 -0
  50. package/dist/src/cli/config-file.d.ts +3 -0
  51. package/dist/src/cli/config-file.js +50 -0
  52. package/dist/src/cli/config-lock.d.ts +7 -0
  53. package/dist/src/cli/config-lock.js +61 -0
  54. package/dist/src/cli/config-notice.d.ts +5 -0
  55. package/dist/src/cli/config-notice.js +46 -0
  56. package/dist/src/cli/doctor-github.d.ts +9 -0
  57. package/dist/src/cli/doctor-github.js +138 -0
  58. package/dist/src/cli/doctor-harness.d.ts +13 -0
  59. package/dist/src/cli/doctor-harness.js +242 -0
  60. package/dist/src/cli/doctor-local.d.ts +18 -0
  61. package/dist/src/cli/doctor-local.js +77 -0
  62. package/dist/src/cli/doctor-runtime.d.ts +15 -0
  63. package/dist/src/cli/doctor-runtime.js +176 -0
  64. package/dist/src/cli/doctor-service.d.ts +1 -0
  65. package/dist/src/cli/doctor-service.js +11 -0
  66. package/dist/src/cli/doctor-workflows.d.ts +3 -0
  67. package/dist/src/cli/doctor-workflows.js +45 -0
  68. package/dist/src/cli/doctor.d.ts +15 -0
  69. package/dist/src/cli/doctor.js +190 -0
  70. package/dist/src/cli/github-ci-progress.d.ts +8 -0
  71. package/dist/src/cli/github-ci-progress.js +83 -0
  72. package/dist/src/cli/github-retry.d.ts +6 -0
  73. package/dist/src/cli/github-retry.js +47 -0
  74. package/dist/src/cli/harness-probes.d.ts +22 -0
  75. package/dist/src/cli/harness-probes.js +183 -0
  76. package/dist/src/cli/main.d.ts +7 -1
  77. package/dist/src/cli/main.js +39 -61
  78. package/dist/src/cli/phone-arguments.d.ts +14 -0
  79. package/dist/src/cli/phone-arguments.js +37 -0
  80. package/dist/src/cli/phone-client.d.ts +2 -0
  81. package/dist/src/cli/phone-client.js +32 -0
  82. package/dist/src/cli/phone-command.d.ts +13 -0
  83. package/dist/src/cli/phone-command.js +101 -0
  84. package/dist/src/cli/probe-command.d.ts +36 -0
  85. package/dist/src/cli/probe-command.js +59 -0
  86. package/dist/src/cli/project-settings.d.ts +4 -0
  87. package/dist/src/cli/project-settings.js +33 -0
  88. package/dist/src/cli/render.d.ts +2 -1
  89. package/dist/src/cli/render.js +44 -28
  90. package/dist/src/cli/report-github.d.ts +18 -0
  91. package/dist/src/cli/report-github.js +200 -0
  92. package/dist/src/cli/report.d.ts +17 -0
  93. package/dist/src/cli/report.js +192 -0
  94. package/dist/src/cli/repository-arguments.d.ts +5 -0
  95. package/dist/src/cli/repository-arguments.js +34 -0
  96. package/dist/src/cli/runtime-arguments.d.ts +4 -0
  97. package/dist/src/cli/runtime-arguments.js +15 -0
  98. package/dist/src/cli/runtime-directory.d.ts +6 -2
  99. package/dist/src/cli/runtime-directory.js +72 -14
  100. package/dist/src/cli/toolchain.d.ts +2 -0
  101. package/dist/src/cli/toolchain.js +22 -2
  102. package/dist/src/cli/usage-render.d.ts +5 -0
  103. package/dist/src/cli/usage-render.js +40 -1
  104. package/dist/src/cli/usage.d.ts +3 -3
  105. package/dist/src/cli/usage.js +70 -44
  106. package/dist/src/cli/watch-actions.d.ts +2 -0
  107. package/dist/src/cli/watch-actions.js +4 -4
  108. package/dist/src/cli/watch-board-view.d.ts +1 -1
  109. package/dist/src/cli/watch-board-view.js +8 -2
  110. package/dist/src/cli/watch-board.js +23 -10
  111. package/dist/src/cli/watch-card-forms.js +2 -2
  112. package/dist/src/cli/watch-client.d.ts +1 -1
  113. package/dist/src/cli/watch-client.js +7 -2
  114. package/dist/src/cli/watch-header-view.d.ts +27 -0
  115. package/dist/src/cli/watch-header-view.js +116 -0
  116. package/dist/src/cli/watch-model.js +17 -4
  117. package/dist/src/cli/watch-page.js +48 -12
  118. package/dist/src/cli/watch-phone-client.d.ts +1 -0
  119. package/dist/src/cli/watch-phone-client.js +84 -0
  120. package/dist/src/cli/watch-phone-view.d.ts +56 -0
  121. package/dist/src/cli/watch-phone-view.js +113 -0
  122. package/dist/src/cli/watch-phone.d.ts +5 -0
  123. package/dist/src/cli/watch-phone.js +53 -0
  124. package/dist/src/cli/watch-pull-request.d.ts +3 -1
  125. package/dist/src/cli/watch-pull-request.js +4 -0
  126. package/dist/src/cli/watch-render.d.ts +9 -1
  127. package/dist/src/cli/watch-server.js +23 -5
  128. package/dist/src/cli/watch-turn.d.ts +4 -1
  129. package/dist/src/cli/watch-turn.js +37 -1
  130. package/dist/src/cli/watch-usage.js +5 -1
  131. package/dist/src/cli/watch-view.d.ts +6 -20
  132. package/dist/src/cli/watch-view.js +14 -106
  133. package/dist/src/cli.js +106 -23
  134. package/dist/src/command-settings.d.ts +16 -0
  135. package/dist/src/command-settings.js +42 -0
  136. package/dist/src/configuration-change.d.ts +11 -0
  137. package/dist/src/configuration-change.js +62 -0
  138. package/dist/src/configuration-display.d.ts +21 -0
  139. package/dist/src/configuration-display.js +69 -0
  140. package/dist/src/configuration-schema.d.ts +49 -0
  141. package/dist/src/configuration-schema.js +159 -0
  142. package/dist/src/daemon/claude-turn.d.ts +19 -5
  143. package/dist/src/daemon/claude-turn.js +116 -53
  144. package/dist/src/daemon/claude-worker.d.ts +3 -3
  145. package/dist/src/daemon/claude-worker.js +65 -76
  146. package/dist/src/daemon/command-journal.d.ts +5 -0
  147. package/dist/src/daemon/command-journal.js +50 -0
  148. package/dist/src/daemon/command-process.d.ts +28 -0
  149. package/dist/src/daemon/command-process.js +164 -0
  150. package/dist/src/daemon/command-worker.d.ts +19 -0
  151. package/dist/src/daemon/command-worker.js +182 -0
  152. package/dist/src/daemon/cursor-stream.d.ts +4 -0
  153. package/dist/src/daemon/cursor-stream.js +154 -0
  154. package/dist/src/daemon/daemon-adapters.d.ts +58 -0
  155. package/dist/src/daemon/daemon-adapters.js +102 -0
  156. package/dist/src/daemon/daemon-loops.d.ts +14 -0
  157. package/dist/src/daemon/daemon-loops.js +39 -0
  158. package/dist/src/daemon/daemon.d.ts +2 -33
  159. package/dist/src/daemon/daemon.js +126 -132
  160. package/dist/src/daemon/declared-input.d.ts +3 -0
  161. package/dist/src/daemon/declared-input.js +9 -0
  162. package/dist/src/daemon/delivery-router.js +1 -1
  163. package/dist/src/daemon/gemini-stream.d.ts +4 -0
  164. package/dist/src/daemon/gemini-stream.js +129 -0
  165. package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
  166. package/dist/src/daemon/github-ci-rerun.js +92 -0
  167. package/dist/src/daemon/github-ci.js +89 -8
  168. package/dist/src/daemon/github-merge-call.d.ts +2 -0
  169. package/dist/src/daemon/github-merge.js +7 -3
  170. package/dist/src/daemon/github-methods.js +10 -0
  171. package/dist/src/daemon/github-operation.d.ts +1 -0
  172. package/dist/src/daemon/github-retry.js +8 -44
  173. package/dist/src/daemon/issue-queue.d.ts +1 -0
  174. package/dist/src/daemon/issue-queue.js +3 -26
  175. package/dist/src/daemon/notify.js +2 -1
  176. package/dist/src/daemon/opencode-stream.d.ts +5 -0
  177. package/dist/src/daemon/opencode-stream.js +87 -0
  178. package/dist/src/daemon/queue-status.d.ts +4 -0
  179. package/dist/src/daemon/queue-status.js +38 -0
  180. package/dist/src/daemon/retry-worktree.d.ts +18 -0
  181. package/dist/src/daemon/retry-worktree.js +139 -0
  182. package/dist/src/daemon/retrying-turn.d.ts +2 -0
  183. package/dist/src/daemon/retrying-turn.js +108 -30
  184. package/dist/src/daemon/schedule-journal.d.ts +19 -0
  185. package/dist/src/daemon/schedule-journal.js +57 -0
  186. package/dist/src/daemon/text-output.d.ts +18 -0
  187. package/dist/src/daemon/text-output.js +44 -0
  188. package/dist/src/daemon/ticket-registration.d.ts +5 -7
  189. package/dist/src/daemon/ticket-registration.js +85 -40
  190. package/dist/src/daemon/turn-command.d.ts +10 -0
  191. package/dist/src/daemon/turn-command.js +33 -0
  192. package/dist/src/daemon/turn-report.d.ts +18 -0
  193. package/dist/src/daemon/turn-report.js +79 -0
  194. package/dist/src/daemon/work-tree.d.ts +2 -1
  195. package/dist/src/daemon/work-tree.js +15 -12
  196. package/dist/src/daemon/workflow-generations.d.ts +32 -0
  197. package/dist/src/daemon/workflow-generations.js +57 -0
  198. package/dist/src/daemon/workflow-replay.d.ts +16 -0
  199. package/dist/src/daemon/workflow-replay.js +58 -0
  200. package/dist/src/daemon/workflow-schedules.d.ts +27 -0
  201. package/dist/src/daemon/workflow-schedules.js +185 -0
  202. package/dist/src/decision-wait.d.ts +1 -0
  203. package/dist/src/decision-wait.js +3 -0
  204. package/dist/src/delivery-backoff.d.ts +1 -0
  205. package/dist/src/delivery-backoff.js +3 -0
  206. package/dist/src/doctor-report.d.ts +24 -0
  207. package/dist/src/doctor-report.js +70 -0
  208. package/dist/src/execution-pin.d.ts +5 -0
  209. package/dist/src/execution-pin.js +67 -4
  210. package/dist/src/grok-result.d.ts +12 -0
  211. package/dist/src/grok-result.js +61 -0
  212. package/dist/src/harness-defaults.d.ts +35 -0
  213. package/dist/src/harness-defaults.js +121 -0
  214. package/dist/src/host/decision-resume.d.ts +35 -0
  215. package/dist/src/host/decision-resume.js +86 -0
  216. package/dist/src/host/gate-bridge.d.ts +48 -0
  217. package/dist/src/host/gate-bridge.js +124 -0
  218. package/dist/src/host/run-wait.d.ts +26 -0
  219. package/dist/src/host/run-wait.js +37 -0
  220. package/dist/src/host/start-delivery.d.ts +1 -1
  221. package/dist/src/host/start-delivery.js +10 -3
  222. package/dist/src/host/step-bridge-host.d.ts +6 -20
  223. package/dist/src/host/step-bridge-host.js +44 -58
  224. package/dist/src/merge-request.d.ts +19 -0
  225. package/dist/src/merge-request.js +32 -0
  226. package/dist/src/phone/canonical-json.d.ts +1 -0
  227. package/dist/src/phone/canonical-json.js +16 -0
  228. package/dist/src/phone/phone-link.d.ts +7 -0
  229. package/dist/src/phone/phone-link.js +21 -0
  230. package/dist/src/phone/qr-data.d.ts +8 -0
  231. package/dist/src/phone/qr-data.js +133 -0
  232. package/dist/src/phone/qr-matrix.d.ts +6 -0
  233. package/dist/src/phone/qr-matrix.js +175 -0
  234. package/dist/src/phone/qr-penalty.d.ts +3 -0
  235. package/dist/src/phone/qr-penalty.js +67 -0
  236. package/dist/src/phone/qr-picture.d.ts +5 -0
  237. package/dist/src/phone/qr-picture.js +24 -0
  238. package/dist/src/private-config.schema.json +263 -0
  239. package/dist/src/project-config.schema.json +65 -0
  240. package/dist/src/project-settings.d.ts +19 -0
  241. package/dist/src/project-settings.js +131 -0
  242. package/dist/src/relay/answer-check.d.ts +24 -0
  243. package/dist/src/relay/answer-check.js +145 -0
  244. package/dist/src/relay/answer-inbox.d.ts +15 -0
  245. package/dist/src/relay/answer-inbox.js +173 -0
  246. package/dist/src/relay/daemon-keys.d.ts +16 -0
  247. package/dist/src/relay/daemon-keys.js +75 -0
  248. package/dist/src/relay/decision-check.d.ts +3 -0
  249. package/dist/src/relay/decision-check.js +77 -0
  250. package/dist/src/relay/decision-close.d.ts +6 -0
  251. package/dist/src/relay/decision-close.js +72 -0
  252. package/dist/src/relay/decision-envelopes.d.ts +29 -0
  253. package/dist/src/relay/decision-envelopes.js +93 -0
  254. package/dist/src/relay/decision-watch.d.ts +14 -0
  255. package/dist/src/relay/decision-watch.js +68 -0
  256. package/dist/src/relay/envelope-post.d.ts +8 -0
  257. package/dist/src/relay/envelope-post.js +71 -0
  258. package/dist/src/relay/envelope.d.ts +28 -0
  259. package/dist/src/relay/envelope.js +53 -0
  260. package/dist/src/relay/hpke.d.ts +25 -0
  261. package/dist/src/relay/hpke.js +108 -0
  262. package/dist/src/relay/pairing-checks.d.ts +42 -0
  263. package/dist/src/relay/pairing-checks.js +172 -0
  264. package/dist/src/relay/pairing-follow.d.ts +8 -0
  265. package/dist/src/relay/pairing-follow.js +95 -0
  266. package/dist/src/relay/pairing-session.d.ts +29 -0
  267. package/dist/src/relay/pairing-session.js +87 -0
  268. package/dist/src/relay/phone-delivery.d.ts +51 -0
  269. package/dist/src/relay/phone-delivery.js +139 -0
  270. package/dist/src/relay/phone-devices.d.ts +36 -0
  271. package/dist/src/relay/phone-devices.js +46 -0
  272. package/dist/src/relay/phone-inbox.d.ts +18 -0
  273. package/dist/src/relay/phone-inbox.js +17 -0
  274. package/dist/src/relay/phone-operations.d.ts +18 -0
  275. package/dist/src/relay/phone-operations.js +121 -0
  276. package/dist/src/relay/phone-outbox.d.ts +21 -0
  277. package/dist/src/relay/phone-outbox.js +25 -0
  278. package/dist/src/relay/phone-socket.d.ts +6 -0
  279. package/dist/src/relay/phone-socket.js +63 -0
  280. package/dist/src/relay/relay-control.d.ts +7 -0
  281. package/dist/src/relay/relay-control.js +24 -0
  282. package/dist/src/relay/relay-files.d.ts +2 -0
  283. package/dist/src/relay/relay-files.js +23 -0
  284. package/dist/src/relay/relay-heartbeat.d.ts +17 -0
  285. package/dist/src/relay/relay-heartbeat.js +81 -0
  286. package/dist/src/relay/relay-http.d.ts +14 -0
  287. package/dist/src/relay/relay-http.js +63 -0
  288. package/dist/src/relay/relay-registration.d.ts +15 -0
  289. package/dist/src/relay/relay-registration.js +63 -0
  290. package/dist/src/relay/relay-service.d.ts +25 -0
  291. package/dist/src/relay/relay-service.js +216 -0
  292. package/dist/src/relay/relay-store.d.ts +48 -0
  293. package/dist/src/relay/relay-store.js +131 -0
  294. package/dist/src/relay/sealed-post.d.ts +25 -0
  295. package/dist/src/relay/sealed-post.js +52 -0
  296. package/dist/src/relay.d.ts +1 -0
  297. package/dist/src/relay.js +8 -0
  298. package/dist/src/report-statistics.d.ts +50 -0
  299. package/dist/src/report-statistics.js +70 -0
  300. package/dist/src/report.d.ts +171 -0
  301. package/dist/src/report.js +119 -0
  302. package/dist/src/repository-identity.d.ts +4 -0
  303. package/dist/src/repository-identity.js +4 -0
  304. package/dist/src/review-subject.d.ts +41 -0
  305. package/dist/src/review-subject.js +91 -0
  306. package/dist/src/run-wait.d.ts +23 -0
  307. package/dist/src/run-wait.js +20 -0
  308. package/dist/src/service/active-tickets.d.ts +4 -0
  309. package/dist/src/service/active-tickets.js +49 -0
  310. package/dist/src/service/command-effects.d.ts +4 -0
  311. package/dist/src/service/command-effects.js +16 -0
  312. package/dist/src/service/decision-handler.d.ts +4 -0
  313. package/dist/src/service/decision-handler.js +39 -4
  314. package/dist/src/service/gateway.js +18 -3
  315. package/dist/src/service/registry.d.ts +16 -3
  316. package/dist/src/service/registry.js +34 -3
  317. package/dist/src/service/replies.d.ts +9 -1
  318. package/dist/src/service/replies.js +12 -0
  319. package/dist/src/service/run-handlers.js +14 -55
  320. package/dist/src/service/run-metadata.d.ts +8 -0
  321. package/dist/src/service/run-metadata.js +53 -0
  322. package/dist/src/service/run-waits.d.ts +3 -0
  323. package/dist/src/service/run-waits.js +41 -0
  324. package/dist/src/service/service.d.ts +18 -2
  325. package/dist/src/service/service.js +23 -7
  326. package/dist/src/service/submission-handler.d.ts +0 -1
  327. package/dist/src/service/submission-handler.js +6 -34
  328. package/dist/src/service/worker-port.d.ts +1 -0
  329. package/dist/src/service/worker-totals.js +8 -23
  330. package/dist/src/step-bridge.d.ts +23 -0
  331. package/dist/src/steps/decision-gate.d.ts +2 -1
  332. package/dist/src/steps/decision-gate.js +7 -0
  333. package/dist/src/steps/merge-by-person.d.ts +2 -0
  334. package/dist/src/steps/merge-by-person.js +18 -0
  335. package/dist/src/steps/merge-when-green.d.ts +2 -0
  336. package/dist/src/steps/merge-when-green.js +62 -0
  337. package/dist/src/steps/review-by-agent.d.ts +5 -0
  338. package/dist/src/steps/review-by-agent.js +124 -0
  339. package/dist/src/steps/review-by-person.d.ts +4 -0
  340. package/dist/src/steps/review-by-person.js +16 -0
  341. package/dist/src/steps/review-subject.d.ts +2 -0
  342. package/dist/src/steps/review-subject.js +11 -0
  343. package/dist/src/steps/run-command.d.ts +2 -0
  344. package/dist/src/steps/run-command.js +15 -0
  345. package/dist/src/steps/sleep.d.ts +3 -0
  346. package/dist/src/steps/sleep.js +19 -0
  347. package/dist/src/steps/wait-for-decision.d.ts +2 -0
  348. package/dist/src/steps/wait-for-decision.js +71 -0
  349. package/dist/src/steps/wait-for-run.d.ts +5 -0
  350. package/dist/src/steps/wait-for-run.js +9 -0
  351. package/dist/src/storage/decision-snapshots.d.ts +1 -0
  352. package/dist/src/storage/decision-snapshots.js +7 -1
  353. package/dist/src/submission.d.ts +4 -0
  354. package/dist/src/submission.js +6 -2
  355. package/dist/src/testing.d.ts +29 -0
  356. package/dist/src/testing.js +264 -0
  357. package/dist/src/ticket-status-stream.d.ts +9 -0
  358. package/dist/src/ticket-status-stream.js +94 -0
  359. package/dist/src/token-prices.d.ts +12 -4
  360. package/dist/src/token-prices.js +15 -2
  361. package/dist/src/turn-profile.d.ts +1 -0
  362. package/dist/src/turn-profile.js +8 -1
  363. package/dist/src/worker-usage.d.ts +16 -0
  364. package/dist/src/worker-usage.js +57 -0
  365. package/dist/src/workflow-admission.d.ts +5 -0
  366. package/dist/src/workflow-candidate.d.ts +7 -2
  367. package/dist/src/workflow-candidate.js +47 -5
  368. package/dist/src/workflow-declaration.d.ts +21 -3
  369. package/dist/src/workflow-declaration.js +77 -9
  370. package/dist/src/workflow-discovery.d.ts +2 -1
  371. package/dist/src/workflow-discovery.js +4 -1
  372. package/dist/src/workflow-refusals.js +3 -0
  373. package/dist/src/workflow-schedule.d.ts +22 -0
  374. package/dist/src/workflow-schedule.js +53 -0
  375. package/dist/src/workflows.d.ts +11 -1
  376. package/dist/src/workflows.js +8 -0
  377. package/dist/tools/admit-workflow.d.ts +1 -0
  378. package/dist/tools/admit-workflow.js +18 -5
  379. package/dist/tools/doctor-adoption.d.ts +1 -0
  380. package/dist/tools/doctor-adoption.js +11 -0
  381. package/dist/tools/project-configuration.d.ts +4 -0
  382. package/dist/tools/project-configuration.js +47 -0
  383. package/dist/tools/self-host-processes.d.ts +1 -0
  384. package/dist/tools/self-host-processes.js +33 -22
  385. package/dist/tools/self-host-project.d.ts +4 -0
  386. package/dist/tools/self-host-project.js +61 -14
  387. package/dist/tools/self-host-runtime.d.ts +16 -0
  388. package/dist/tools/self-host-runtime.js +60 -0
  389. package/dist/tools/self-host-workflows.d.ts +1 -0
  390. package/dist/tools/self-host-workflows.js +36 -1
  391. package/dist/tools/self-host.js +86 -61
  392. package/dist/tools/workflow-candidate-counts.d.ts +6 -2
  393. package/dist/tools/workflow-candidate-counts.js +31 -16
  394. package/dist/tools/workflow-candidate-fields.d.ts +5 -0
  395. package/dist/tools/workflow-candidate-fields.js +24 -0
  396. package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
  397. package/dist/tools/workflow-candidate-helper-counts.js +129 -0
  398. package/dist/tools/workflow-candidate-program.d.ts +2 -0
  399. package/dist/tools/workflow-candidate-program.js +36 -8
  400. package/dist/tools/workflow-candidate-source.js +77 -15
  401. package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
  402. package/dist/tools/workflow-candidate-syntax.js +70 -26
  403. package/dist/tools/workflow-command.d.ts +1 -0
  404. package/dist/tools/workflow-command.js +143 -0
  405. package/dist/tools/workflow-folder-capture.d.ts +1 -0
  406. package/dist/tools/workflow-folder-capture.js +47 -2
  407. package/dist/tools/workflow-folders.d.ts +17 -1
  408. package/dist/tools/workflow-folders.js +59 -6
  409. package/dist/tools/workflow-test-hook.d.ts +7 -0
  410. package/dist/tools/workflow-test-hook.js +16 -0
  411. package/dist/tools/workflow-test-loader.d.ts +1 -0
  412. package/dist/tools/workflow-test-loader.js +10 -0
  413. package/dist/workflows/develop-ticket.js +1 -1
  414. package/dist/workflows/ticket-prompts.js +5 -1
  415. package/package.json +46 -4
  416. package/templates/develop/README.md +78 -0
  417. package/templates/develop/develop/accept.ts +11 -0
  418. package/templates/develop/develop/flow-tests.ts +357 -0
  419. package/templates/develop/develop/local.ts +40 -0
  420. package/templates/develop/develop/option-tests.ts +174 -0
  421. package/templates/develop/develop/partial-choice.ts +29 -0
  422. package/templates/develop/develop/partial.ts +28 -0
  423. package/templates/develop/develop/pull.ts +152 -0
  424. package/templates/develop/develop/queue-partial.ts +39 -0
  425. package/templates/develop/develop/refusal-tests.ts +174 -0
  426. package/templates/develop/develop/report.ts +156 -0
  427. package/templates/develop/develop/round.ts +40 -0
  428. package/templates/develop/develop/scenarios.ts +87 -0
  429. package/templates/develop/develop/turn.ts +67 -0
  430. package/templates/develop/develop.declaration.json +24 -0
  431. package/templates/develop/develop.test.ts +287 -0
  432. package/templates/develop/develop.ts +30 -0
  433. package/templates/develop/template.json +153 -0
  434. package/dist/src/chats/analysis-batches.d.ts +0 -42
  435. package/dist/src/chats/analysis-batches.js +0 -97
  436. package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
  437. package/dist/src/chats/analysis-checkpoint.js +0 -31
  438. package/dist/src/chats/analysis-contract.d.ts +0 -80
  439. package/dist/src/chats/analysis-contract.js +0 -16
  440. package/dist/src/chats/analysis-data.d.ts +0 -3
  441. package/dist/src/chats/analysis-data.js +0 -85
  442. package/dist/src/chats/analysis-input.d.ts +0 -18
  443. package/dist/src/chats/analysis-input.js +0 -97
  444. package/dist/src/chats/analysis-links.d.ts +0 -2
  445. package/dist/src/chats/analysis-links.js +0 -25
  446. package/dist/src/chats/analysis-merge.d.ts +0 -16
  447. package/dist/src/chats/analysis-merge.js +0 -134
  448. package/dist/src/chats/analysis-prompt.d.ts +0 -18
  449. package/dist/src/chats/analysis-prompt.js +0 -42
  450. package/dist/src/chats/analysis-proposal.d.ts +0 -4
  451. package/dist/src/chats/analysis-proposal.js +0 -41
  452. package/dist/src/chats/analysis-provenance.d.ts +0 -4
  453. package/dist/src/chats/analysis-provenance.js +0 -99
  454. package/dist/src/chats/analysis-shape.d.ts +0 -4
  455. package/dist/src/chats/analysis-shape.js +0 -235
  456. package/dist/src/chats/analysis.d.ts +0 -3
  457. package/dist/src/chats/analysis.js +0 -42
  458. package/dist/src/chats/corpus-input.d.ts +0 -5
  459. package/dist/src/chats/corpus-input.js +0 -288
  460. package/dist/src/chats/destination.d.ts +0 -4
  461. package/dist/src/chats/destination.js +0 -96
  462. package/dist/src/chats/import.d.ts +0 -15
  463. package/dist/src/chats/import.js +0 -243
  464. package/dist/src/chats/input-file.d.ts +0 -3
  465. package/dist/src/chats/input-file.js +0 -32
  466. package/dist/src/chats/normalize.d.ts +0 -29
  467. package/dist/src/chats/normalize.js +0 -155
  468. package/dist/src/chats/previous-import.d.ts +0 -5
  469. package/dist/src/chats/previous-import.js +0 -34
  470. package/dist/src/chats/reader.d.ts +0 -21
  471. package/dist/src/chats/reader.js +0 -118
  472. package/dist/src/chats/redact-import.d.ts +0 -14
  473. package/dist/src/chats/redact-import.js +0 -141
  474. package/dist/src/chats/redaction.d.ts +0 -41
  475. package/dist/src/chats/redaction.js +0 -161
  476. package/dist/src/chats/reference-mapping.d.ts +0 -16
  477. package/dist/src/chats/reference-mapping.js +0 -153
  478. package/dist/src/chats/revision-input.d.ts +0 -3
  479. package/dist/src/chats/revision-input.js +0 -180
  480. package/dist/src/chats/revision.d.ts +0 -48
  481. package/dist/src/chats/revision.js +0 -94
  482. package/dist/src/chats/selection.d.ts +0 -25
  483. package/dist/src/chats/selection.js +0 -109
  484. package/dist/src/chats/source.d.ts +0 -23
  485. package/dist/src/chats/source.js +0 -135
  486. package/dist/src/chats/structure.d.ts +0 -57
  487. package/dist/src/chats/structure.js +0 -216
  488. package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
  489. package/dist/src/chats/workflow-generation-projection.js +0 -75
  490. package/dist/src/chats/workflow-generation-source.d.ts +0 -25
  491. package/dist/src/chats/workflow-generation-source.js +0 -124
  492. package/dist/src/chats/workflow-generation-text.d.ts +0 -23
  493. package/dist/src/chats/workflow-generation-text.js +0 -74
  494. package/dist/src/chats/workflow-generation.d.ts +0 -69
  495. package/dist/src/chats/workflow-generation.js +0 -142
  496. package/dist/src/daemon/analysis-launch.d.ts +0 -5
  497. package/dist/src/daemon/analysis-launch.js +0 -81
  498. package/dist/src/daemon/analysis-token.d.ts +0 -6
  499. package/dist/src/daemon/analysis-token.js +0 -88
  500. package/dist/src/daemon/analysis-worker.d.ts +0 -20
  501. package/dist/src/daemon/analysis-worker.js +0 -271
  502. package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
  503. package/dist/src/daemon/chats-batch-binding.js +0 -99
  504. package/dist/src/daemon/chats-capture.d.ts +0 -18
  505. package/dist/src/daemon/chats-capture.js +0 -194
  506. package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
  507. package/dist/src/daemon/chats-checkpoints.js +0 -186
  508. package/dist/src/daemon/chats-files.d.ts +0 -42
  509. package/dist/src/daemon/chats-files.js +0 -252
  510. package/dist/src/daemon/chats-follow-up.d.ts +0 -38
  511. package/dist/src/daemon/chats-follow-up.js +0 -180
  512. package/dist/src/daemon/chats-question.d.ts +0 -15
  513. package/dist/src/daemon/chats-question.js +0 -93
  514. package/dist/src/daemon/chats-worker.d.ts +0 -13
  515. package/dist/src/daemon/chats-worker.js +0 -201
  516. package/dist/workflows/analyze-chats.d.ts +0 -15
  517. package/dist/workflows/analyze-chats.declaration.json +0 -22
  518. package/dist/workflows/analyze-chats.js +0 -250
@@ -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
+ }
@@ -3,13 +3,14 @@ import { workflowRefusals, } from "../workflow-refusals.js";
3
3
  import { isTicketStatus } from "../ticket-status.js";
4
4
  import { isPromotionId } from "../workflow-contracts.js";
5
5
  import { priceFields, statusTurns } from "./watch-usage.js";
6
- import { priceOf, usageOf } from "../worker-usage.js";
6
+ import { priceOf, usageOf, attemptFields } from "../worker-usage.js";
7
7
  import { priceText } from "./usage-render.js";
8
8
  import { boardsOf, currentStepOf, roundOf, stagesFor, startWorkflowOf, } from "./watch-board.js";
9
9
  import { decisionOf, phasesOf } from "./watch-phases.js";
10
10
  import { pullOf } from "./watch-pull-request.js";
11
11
  import { establishedIssue } from "./watch-pr-identity.js";
12
12
  import { displayRun } from "./watch-paths.js";
13
+ import { shownCommands } from "./command-effects.js";
13
14
  const textLimit = 600;
14
15
  const activityLimit = 400;
15
16
  function record(value) {
@@ -119,7 +120,10 @@ export function turnOf(records) {
119
120
  const result = record(records.result);
120
121
  const outcome = text(result["outcome"]);
121
122
  const report = record(parsed(text(result["result"])));
123
+ const harness = text(started["harness"]) || text(report["harness"]);
122
124
  return {
125
+ ...attemptFields(report["attempts"]),
126
+ ...(harness === "" ? {} : { harness }),
123
127
  key: records.key,
124
128
  operationId: text(started["operationId"]),
125
129
  usage: usageOf(report["usage"]),
@@ -186,6 +190,14 @@ function outcomeOf(value) {
186
190
  ...(issueUpdate === "failed" ? { issueUpdate } : {}),
187
191
  };
188
192
  }
193
+ function runLinksOf(status) {
194
+ return {
195
+ parentRunId: stamp(status["parentRunId"]),
196
+ chainId: stamp(status["chainId"]) ?? text(status["runId"]),
197
+ childRunIds: texts(status["childRunIds"]),
198
+ awaitedRunId: stamp(status["awaitedRunId"]),
199
+ };
200
+ }
189
201
  function runOf(inputs, value) {
190
202
  const status = record(record(value)["status"]);
191
203
  const runId = text(status["runId"]);
@@ -198,9 +210,7 @@ function runOf(inputs, value) {
198
210
  return {
199
211
  runId,
200
212
  workflowId,
201
- parentRunId: stamp(status["parentRunId"]),
202
- chainId: stamp(status["chainId"]) ?? runId,
203
- childRunIds: texts(status["childRunIds"]),
213
+ ...runLinksOf(status),
204
214
  ticketId: ticketId === "" ? null : ticketId,
205
215
  ...(issue === null ? {} : { issueIdentity: issue }),
206
216
  title: stamp(status["title"]),
@@ -224,6 +234,9 @@ function runOf(inputs, value) {
224
234
  .map((decision) => decisionCommands(operationalDecision(record(decision), workflowId), inputs.client)),
225
235
  events: list(record(value)["events"]).map(eventOf),
226
236
  turns: statusTurns(inputs.turns, status),
237
+ ...(status["commandEffects"] === undefined
238
+ ? {}
239
+ : { commandEffects: shownCommands(status["commandEffects"]) }),
227
240
  phases: phasesOf(list(record(value)["events"]), workflowId),
228
241
  decision: decisionOf(list(record(value)["events"])),
229
242
  feedback: list(status["feedback"]).map(feedbackOf),
@@ -1,19 +1,30 @@
1
1
  import { cardReply } from "./watch-card-reply.js";
2
2
  import { record } from "../protocol.js";
3
+ import { Commands, commandText } from "./command-effects.js";
3
4
  import { watchCardClient } from "./watch-card-client.js";
4
5
  import { AddCard, CardInput, cardKey, cardSubmitKey, } from "./watch-card-view.js";
5
6
  import { watchClient } from "./watch-client.js";
7
+ import { watchPhoneClient } from "./watch-phone-client.js";
8
+ import { PhoneAsk, PhoneCode, PhoneList, PhonePanel, phoneButton, phoneNotices, refusalText, timeLeft, } from "./watch-phone-view.js";
6
9
  import { priceOf, tokenCount, usageOf } from "../worker-usage.js";
7
- import { priceText, usageText, totalsSuffix } from "./usage-render.js";
10
+ import { priceText, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
8
11
  import { startPrompts, StartCard, StartRun } from "./watch-start-view.js";
9
12
  import { Board, boardSizing, Card, HandoffLinks, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, observationText, staleObservation, } from "./watch-board-view.js";
10
13
  import { boardWorkflow, watchHash, watchLocation, watchTitle, } from "./watch-navigation.js";
11
14
  import { clockTime, completedDetail, counted, elapsed, groupActivity, pageTitle, phaseTime, runName, runTone, selectedRun, toneOf, turnTime, waitingDetail, } from "./watch-render.js";
12
15
  import { Command, Decision, Events, Group, Item, Turn, Work, } from "./watch-turn.js";
13
- import { clove, Banner, BannerDetail, BoardPage, Header, Page, Phases, PullRequest, Review, RefusedWorkflows, Queue, Run, } from "./watch-view.js";
16
+ import { Banner, BannerDetail, BoardPage, Page, Phases, PullRequest, Review, RefusedWorkflows, Run, } from "./watch-view.js";
17
+ import { Brand, clove, Header, HeaderActions, HeaderStatus, Queue, queueLanes, skippedText, } from "./watch-header-view.js";
14
18
  const functions = [
15
19
  record,
20
+ commandText,
21
+ Commands,
22
+ queueLanes,
23
+ skippedText,
16
24
  Queue,
25
+ Brand,
26
+ HeaderStatus,
27
+ HeaderActions,
17
28
  cardReply,
18
29
  cardSubmitKey,
19
30
  cardKey,
@@ -24,6 +35,7 @@ const functions = [
24
35
  usageOf,
25
36
  priceText,
26
37
  usageText,
38
+ attemptText,
27
39
  totalsSuffix,
28
40
  watchHash,
29
41
  watchLocation,
@@ -70,6 +82,14 @@ const functions = [
70
82
  PullRequest,
71
83
  Review,
72
84
  Run,
85
+ timeLeft,
86
+ refusalText,
87
+ phoneButton,
88
+ phoneNotices,
89
+ PhoneCode,
90
+ PhoneAsk,
91
+ PhoneList,
92
+ PhonePanel,
73
93
  Header,
74
94
  RefusedWorkflows,
75
95
  BoardPage,
@@ -130,7 +150,20 @@ body:has(.board-page) { padding-bottom: 0; overflow: hidden; }
130
150
  .workflow-refusals { flex-shrink: 0; max-height: 25dvh; overflow-y: auto; overflow-wrap: anywhere; }
131
151
  .workflow-refusals h2 { margin: 8px 0; }
132
152
  a { color: var(--accent-strong); }
133
- header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; padding: 22px 0 10px; color: var(--muted); font-size: 12px; }
153
+ .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
154
+ .header-status { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
155
+ .queue-lanes { padding: 2px 8px; border-radius: 999px; background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); font-variant-numeric: tabular-nums; }
156
+ .header-actions { margin-left: auto; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
157
+ .queue-waiting { flex-shrink: 0; margin: 0 0 4px; color: var(--muted); font-size: 12px; }
158
+ .queue-waiting ul { margin: 6px 0 0; padding: 0 0 0 18px; columns: 220px; column-gap: 24px; max-height: 25dvh; overflow-y: auto; }
159
+ .phone { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 0; }
160
+ .phone-pairing { flex-basis: 100%; }
161
+ .phone-pairing div { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
162
+ .phone-qr { width: 196px; height: 196px; border-radius: 8px; }
163
+ .phone-ask { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
164
+ .phone-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
165
+ .phone-list li { display: flex; gap: 8px; align-items: center; color: var(--ink); }
166
+ header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; padding: 18px 0 12px; color: var(--muted); font-size: 12px; }
134
167
  .brand { display: inline-flex; align-items: center; gap: 9px; color: var(--ink); font: 800 26px/1.2 var(--heading-font); }
135
168
  .brand svg { width: 30px; height: 30px; color: var(--accent); }
136
169
  a:focus-visible, button:focus-visible, summary:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 6px var(--code-bg); }
@@ -147,43 +180,45 @@ h2, h3 { font-family: var(--heading-font); font-weight: 700; }
147
180
  .workflows a[aria-current="page"] { border-bottom-color: var(--accent); background: var(--surface); border-radius: 8px 8px 0 0; }
148
181
  .workflows span, .card small { color: var(--muted); font-size: 12px; }
149
182
  .board { width: 100%; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
150
- .board h2 { margin: 0 0 8px; font-size: 24px; flex-shrink: 0; }
151
183
  .columns { display: flex; align-items: flex-start; gap: ${String(boardSizing.gap)}px; flex: 1; min-height: 0; overflow-x: scroll; overflow-y: hidden; padding: 6px 6px 12px; scrollbar-color: var(--muted) var(--surface-2); }
152
184
  @supports selector(::-webkit-scrollbar) { .columns { scrollbar-color: auto; } }
153
185
  .columns::-webkit-scrollbar { height: 12px; }
154
186
  .columns::-webkit-scrollbar-track { background: var(--surface-2); }
155
187
  .columns::-webkit-scrollbar-thumb { background: var(--muted); border-radius: 6px; }
156
188
  .column { flex: 1 0 ${String(boardSizing.minimumColumnWidth)}px; min-width: ${String(boardSizing.minimumColumnWidth)}px; max-height: 100%; display: flex; flex-direction: column; overflow: hidden; padding: 10px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line); background: var(--surface-2); }
157
- .column-name { display: flex; align-items: center; gap: 6px; flex-shrink: 0; margin: 0; padding: 4px 0 10px; color: var(--muted); font: 500 12px/1.5 var(--code-font); }
189
+ .column-name { display: flex; align-items: center; gap: 6px; flex-shrink: 0; margin: 0; padding: 4px 0 10px; color: var(--muted); font: 600 13px/1.5 var(--body-font); }
190
+ .column-count { font-variant-numeric: tabular-nums; }
158
191
  .column-name > span:first-child { flex: 1; }
159
192
  .column-cards { min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
160
193
  .column.collapsed { flex: 0 0 ${String(boardSizing.collapsedColumnWidth)}px; min-width: ${String(boardSizing.collapsedColumnWidth)}px; padding: 6px; }
161
194
  .collapsed .column-name { writing-mode: vertical-rl; padding: 0; }
162
- .column-name button, .start-toggle { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
163
- .column-name button:hover, .start-toggle:hover, .add-card:hover, .add-card-form button:hover { background: var(--surface); }
195
+ header button, .phone button, .column-name button, .add-card, .add-card-form button, .start-card button { font: 500 13px/1.4 var(--body-font); color: var(--ink); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
196
+ header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover, .start-card button:hover { background: var(--surface-2); }
164
197
  .add-card, .add-card-form button { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 4px 8px 4px 0; }
165
- .add-card { width: 100%; text-align: left; }
198
+ .add-card { width: 100%; text-align: left; margin: 4px 0; }
166
199
  .add-card-form { padding: 8px 0; overflow-wrap: anywhere; }
167
200
  .add-card-form label { display: block; color: var(--ink); margin-bottom: 8px; }
168
201
  .add-card-form input, .add-card-form textarea { display: block; width: 100%; min-width: 0; box-sizing: border-box; padding: 8px; border: 1px solid var(--line); border-radius: 6px; font: inherit; color: var(--ink); background: var(--surface); }
169
202
  .add-card-form textarea { resize: vertical; }
170
203
  .add-card-form button:disabled { opacity: 0.6; cursor: default; }
171
204
  .add-card-form p { font-size: 12px; margin: 8px 0; }
172
- .card { display: grid; gap: 6px; margin-bottom: 10px; padding: 12px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line), var(--shadow); color: var(--ink); overflow-wrap: anywhere; background: var(--surface); }
205
+ .card { display: grid; gap: 6px; margin-bottom: 10px; padding: 12px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line); color: var(--ink); overflow-wrap: anywhere; background: var(--surface); }
173
206
  .card:hover { outline: 1px solid var(--accent-strong); }
174
207
  .card-run { display: grid; gap: 4px; min-width: 0; color: inherit; text-decoration: none; }
175
208
  .card-run strong { font-family: var(--heading-font); font-weight: 700; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
176
209
  .completion-mark { font-size: 12px; }
177
- .card-step, .card-review, .card-cost, .card small { font: 400 12px/1.6 var(--code-font); font-variant-numeric: tabular-nums; }
210
+ .card-step, .card-review, .card-cost { font: 400 12px/1.6 var(--body-font); font-variant-numeric: tabular-nums; }
211
+ .card small { font: 400 11px/1.6 var(--code-font); }
178
212
  .card-step, .card-review { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
179
213
  .card-step { color: var(--muted); }
180
214
  .card-step.active { color: var(--accent-strong); }
181
215
  .card-review { color: var(--muted); }
182
216
  .review-pill { display: inline-block; padding: 1px 5px; border-radius: 5px; box-shadow: inset 0 0 0 1px var(--line); }
183
- .decision-mark { width: fit-content; padding: 3px 7px; border-radius: 6px; background: linear-gradient(var(--warn-tint), var(--warn-tint)), var(--surface); color: var(--warn); font: 500 12px/1.6 var(--code-font); }
217
+ .decision-mark { width: fit-content; padding: 3px 7px; border-radius: 6px; background: linear-gradient(var(--warn-tint), var(--warn-tint)), var(--surface); color: var(--warn); font: 600 12px/1.6 var(--body-font); }
184
218
  .column.stopped { background: var(--surface); box-shadow: inset 0 0 0 1px var(--bad), inset 0 0 0 100vmax var(--bad-tint); }
219
+ .column.stopped.collapsed { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); }
185
220
  .stopped .column-name { color: var(--bad); background: var(--surface); border-radius: 6px; }
186
- .stopped .card { background: linear-gradient(var(--bad-tint), var(--bad-tint)), var(--surface); box-shadow: inset 0 0 0 1px var(--bad), var(--shadow); }
221
+ .stopped .card { background: linear-gradient(var(--bad-tint), var(--bad-tint)), var(--surface); box-shadow: inset 0 0 0 1px var(--bad); }
187
222
  .back { display: block; width: fit-content; margin: 16px 0; }
188
223
  .icon { font-weight: 700; color: var(--muted); }
189
224
  .good .icon, .phase.done .mark, p.good { color: var(--accent-strong); }
@@ -261,6 +296,7 @@ export function pageDocument(actionToken = null) {
261
296
  `const actionToken = ${JSON.stringify(actionToken)};`,
262
297
  ...functions.map((item) => item.toString()),
263
298
  watchCardClient,
299
+ watchPhoneClient,
264
300
  watchClient,
265
301
  ].join("\n");
266
302
  return [
@@ -0,0 +1 @@
1
+ export declare const watchPhoneClient = "\nasync function phoneLoad() {\n const sent = Date.now();\n const sequence = ++state.phoneSequence;\n try {\n const reply = await fetch(\"phone.json\", { cache: \"no-store\" });\n const phone = reply.ok ? await reply.json() : null;\n if (phone !== null && sequence > state.phoneApplied) {\n state.phoneApplied = sequence;\n state.phone = phone;\n state.phoneLoadedAt = sent;\n }\n } catch {}\n draw();\n}\nasync function phonePost(action, body = {}) {\n state.phoneBusy = true;\n state.phoneMessage = \"\";\n draw();\n let reply;\n try {\n const response = await fetch(\"actions/phone/\" + action, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-cloving-token\": actionToken },\n body: JSON.stringify(body),\n });\n reply = response.ok ? await response.json() : { error: { detail: \"The watch page refused the request. Refresh the page.\" } };\n } catch {\n reply = { error: { detail: \"The watch tool does not answer.\" } };\n }\n state.phoneBusy = false;\n state.phoneMessage = reply.error?.detail ?? reply.warning ?? \"\";\n return reply;\n}\nfunction phoneSession(now) {\n const pairing = state.phonePairing;\n const live = state.phone?.pairing ?? null;\n const ended = live === null && state.phoneLoadedAt > (pairing?.at ?? 0);\n if (pairing !== null && (ended || Date.parse(pairing.expiresAt) <= Date.parse(now))) state.phonePairing = null;\n const accepted = state.phoneAccepted;\n const device = (state.phone?.devices ?? []).find((item) => item.deviceId === accepted?.deviceId);\n const shown = device?.state === \"connected\" && device.removedAt === null;\n return { live, connected: shown ? device.name : null };\n}\nfunction phoneControls(now) {\n if (actionToken === null) return undefined;\n const { live, connected } = phoneSession(now);\n return {\n pairing: state.phonePairing,\n request: live?.request ?? null,\n stage: live?.stage ?? null,\n connected,\n refusal: state.phone?.refusal ?? null,\n reason: state.phone?.reason ?? null,\n devices: state.phone?.devices ?? [],\n busy: state.phoneBusy,\n message: state.phoneMessage,\n async onPair() {\n state.phoneAccepted = null;\n const reply = await phonePost(\"pair\");\n if (!reply.error) state.phonePairing = { ...reply, at: Date.now() };\n await phoneLoad();\n },\n async onCancel() {\n state.phonePairing = null;\n await phonePost(\"cancel\");\n await phoneLoad();\n },\n async onAccept() {\n state.phoneAccepted = live?.request ?? null;\n await phonePost(\"accept\", { pairingId: live?.pairingId });\n await phoneLoad();\n },\n async onDeny() {\n await phonePost(\"deny\", { pairingId: live?.pairingId });\n await phoneLoad();\n },\n async onRemove(deviceId) {\n await phonePost(\"remove\", { deviceId });\n await phoneLoad();\n },\n };\n}\n";
@@ -0,0 +1,84 @@
1
+ export const watchPhoneClient = `
2
+ async function phoneLoad() {
3
+ const sent = Date.now();
4
+ const sequence = ++state.phoneSequence;
5
+ try {
6
+ const reply = await fetch("phone.json", { cache: "no-store" });
7
+ const phone = reply.ok ? await reply.json() : null;
8
+ if (phone !== null && sequence > state.phoneApplied) {
9
+ state.phoneApplied = sequence;
10
+ state.phone = phone;
11
+ state.phoneLoadedAt = sent;
12
+ }
13
+ } catch {}
14
+ draw();
15
+ }
16
+ async function phonePost(action, body = {}) {
17
+ state.phoneBusy = true;
18
+ state.phoneMessage = "";
19
+ draw();
20
+ let reply;
21
+ try {
22
+ const response = await fetch("actions/phone/" + action, {
23
+ method: "POST",
24
+ headers: { "content-type": "application/json", "x-cloving-token": actionToken },
25
+ body: JSON.stringify(body),
26
+ });
27
+ reply = response.ok ? await response.json() : { error: { detail: "The watch page refused the request. Refresh the page." } };
28
+ } catch {
29
+ reply = { error: { detail: "The watch tool does not answer." } };
30
+ }
31
+ state.phoneBusy = false;
32
+ state.phoneMessage = reply.error?.detail ?? reply.warning ?? "";
33
+ return reply;
34
+ }
35
+ function phoneSession(now) {
36
+ const pairing = state.phonePairing;
37
+ const live = state.phone?.pairing ?? null;
38
+ const ended = live === null && state.phoneLoadedAt > (pairing?.at ?? 0);
39
+ if (pairing !== null && (ended || Date.parse(pairing.expiresAt) <= Date.parse(now))) state.phonePairing = null;
40
+ const accepted = state.phoneAccepted;
41
+ const device = (state.phone?.devices ?? []).find((item) => item.deviceId === accepted?.deviceId);
42
+ const shown = device?.state === "connected" && device.removedAt === null;
43
+ return { live, connected: shown ? device.name : null };
44
+ }
45
+ function phoneControls(now) {
46
+ if (actionToken === null) return undefined;
47
+ const { live, connected } = phoneSession(now);
48
+ return {
49
+ pairing: state.phonePairing,
50
+ request: live?.request ?? null,
51
+ stage: live?.stage ?? null,
52
+ connected,
53
+ refusal: state.phone?.refusal ?? null,
54
+ reason: state.phone?.reason ?? null,
55
+ devices: state.phone?.devices ?? [],
56
+ busy: state.phoneBusy,
57
+ message: state.phoneMessage,
58
+ async onPair() {
59
+ state.phoneAccepted = null;
60
+ const reply = await phonePost("pair");
61
+ if (!reply.error) state.phonePairing = { ...reply, at: Date.now() };
62
+ await phoneLoad();
63
+ },
64
+ async onCancel() {
65
+ state.phonePairing = null;
66
+ await phonePost("cancel");
67
+ await phoneLoad();
68
+ },
69
+ async onAccept() {
70
+ state.phoneAccepted = live?.request ?? null;
71
+ await phonePost("accept", { pairingId: live?.pairingId });
72
+ await phoneLoad();
73
+ },
74
+ async onDeny() {
75
+ await phonePost("deny", { pairingId: live?.pairingId });
76
+ await phoneLoad();
77
+ },
78
+ async onRemove(deviceId) {
79
+ await phonePost("remove", { deviceId });
80
+ await phoneLoad();
81
+ },
82
+ };
83
+ }
84
+ `;
@@ -0,0 +1,56 @@
1
+ import { type Shown } from "./watch-element.ts";
2
+ export interface PhonePicture {
3
+ readonly size: number;
4
+ readonly path: string;
5
+ }
6
+ export interface PhonePairing {
7
+ readonly link: string;
8
+ readonly expiresAt: string;
9
+ readonly picture: PhonePicture;
10
+ }
11
+ export interface PhoneRequest {
12
+ readonly deviceId: string;
13
+ readonly name: string;
14
+ readonly platform: string;
15
+ readonly code: string;
16
+ }
17
+ export interface PhoneDevice {
18
+ readonly deviceId: string;
19
+ readonly name: string;
20
+ readonly platform: string;
21
+ readonly state: string;
22
+ readonly removedAt: string | null;
23
+ }
24
+ export interface PhoneControls {
25
+ readonly pairing: PhonePairing | null;
26
+ readonly request: PhoneRequest | null;
27
+ readonly stage: string | null;
28
+ readonly connected: string | null;
29
+ readonly refusal: string | null;
30
+ readonly reason: string | null;
31
+ readonly devices: readonly PhoneDevice[];
32
+ readonly busy: boolean;
33
+ readonly message: string;
34
+ readonly onPair: () => void;
35
+ readonly onCancel: () => void;
36
+ readonly onAccept: () => void;
37
+ readonly onDeny: () => void;
38
+ readonly onRemove: (deviceId: string) => void;
39
+ }
40
+ export declare function timeLeft(expiresAt: string, now: string): string;
41
+ export declare function refusalText(code: string): string;
42
+ export declare function PhoneCode(props: {
43
+ readonly picture: PhonePicture;
44
+ }): Shown;
45
+ export declare function phoneButton(label: string, onClick: () => void): Shown;
46
+ export declare function PhoneAsk(props: {
47
+ readonly phone: PhoneControls;
48
+ }): Shown;
49
+ export declare function PhoneList(props: {
50
+ readonly phone: PhoneControls;
51
+ }): Shown;
52
+ export declare function phoneNotices(phone: PhoneControls): Shown;
53
+ export declare function PhonePanel(props: {
54
+ readonly phone: PhoneControls;
55
+ readonly now: string;
56
+ }): Shown;
@@ -0,0 +1,113 @@
1
+ import { component, element } from "./watch-element.js";
2
+ export function timeLeft(expiresAt, now) {
3
+ const seconds = Math.max(0, Math.ceil((Date.parse(expiresAt) - Date.parse(now)) / 1000));
4
+ return `${String(Math.floor(seconds / 60))}:${String(seconds % 60).padStart(2, "0")} left`;
5
+ }
6
+ export function refusalText(code) {
7
+ const texts = {
8
+ "pairing-mac-invalid": "The phone sent a request that does not agree with the QR code.",
9
+ "pairing-key-invalid": "The phone sent a key that is not valid.",
10
+ "pairing-request-invalid": "The phone sent a request that is not valid.",
11
+ "pairing-device-revoked": "This phone was removed. Connect it again as a new phone.",
12
+ "pairing-expired": "The connection request expired. Click Connect a phone again.",
13
+ "pairing-check-invalid": "The phone did not confirm the connection. Remove it and connect again.",
14
+ };
15
+ return texts[code] ?? `The connection did not work (${code}).`;
16
+ }
17
+ export function PhoneCode(props) {
18
+ const { size, path } = props.picture;
19
+ return element("svg", {
20
+ xmlns: "http://www.w3.org/2000/svg",
21
+ class: "phone-qr",
22
+ viewBox: `0 0 ${String(size)} ${String(size)}`,
23
+ role: "img",
24
+ "aria-label": "Pairing QR code",
25
+ "shape-rendering": "crispEdges",
26
+ children: [
27
+ element("rect", { width: size, height: size, fill: "#ffffff" }),
28
+ element("path", { d: path, fill: "#000000" }),
29
+ ],
30
+ });
31
+ }
32
+ export function phoneButton(label, onClick) {
33
+ return element("button", { type: "button", onClick, children: label });
34
+ }
35
+ export function PhoneAsk(props) {
36
+ const { phone } = props;
37
+ const request = phone.request;
38
+ if (request === null)
39
+ return null;
40
+ if (phone.stage === "checking")
41
+ return element("p", { children: `Checking ${request.name}` });
42
+ return element("div", {
43
+ class: "phone-ask",
44
+ children: [
45
+ element("strong", {
46
+ children: `Connect "${request.name}" (${request.platform})? Code ${request.code}`,
47
+ }),
48
+ phoneButton("Accept", phone.onAccept),
49
+ phoneButton("Deny", phone.onDeny),
50
+ ],
51
+ });
52
+ }
53
+ export function PhoneList(props) {
54
+ const { phone } = props;
55
+ if (phone.devices.length === 0)
56
+ return null;
57
+ return element("ul", {
58
+ class: "phone-list",
59
+ children: phone.devices.map((device) => element("li", {
60
+ key: device.deviceId,
61
+ children: [
62
+ `${device.name} (${device.platform}) ${device.removedAt === null ? device.state : "removed"}`,
63
+ device.removedAt === null
64
+ ? phoneButton("Remove", () => {
65
+ phone.onRemove(device.deviceId);
66
+ })
67
+ : null,
68
+ ],
69
+ })),
70
+ });
71
+ }
72
+ export function phoneNotices(phone) {
73
+ const lines = [
74
+ phone.reason === "registration-lost" ? "Connect your phones again." : null,
75
+ phone.connected === null ? null : `Connected: ${phone.connected}`,
76
+ phone.refusal === null ? null : refusalText(phone.refusal),
77
+ phone.message === "" ? null : phone.message,
78
+ ];
79
+ return lines.map((line) => line === null ? null : element("p", { role: "status", children: line }));
80
+ }
81
+ export function PhonePanel(props) {
82
+ const { phone, now } = props;
83
+ const waiting = phone.request === null ? phone.pairing : null;
84
+ return element("section", {
85
+ class: waiting === null ? "phone" : "phone phone-pairing",
86
+ children: [
87
+ waiting === null
88
+ ? null
89
+ : component(PhoneCode, { picture: waiting.picture }),
90
+ element("div", {
91
+ children: [
92
+ waiting === null
93
+ ? null
94
+ : [
95
+ element("strong", { children: "Scan with your phone camera" }),
96
+ element("span", { children: timeLeft(waiting.expiresAt, now) }),
97
+ ],
98
+ component(PhoneAsk, { phone }),
99
+ phone.pairing === null
100
+ ? element("button", {
101
+ type: "button",
102
+ disabled: phone.busy,
103
+ onClick: phone.onPair,
104
+ children: "Connect a phone",
105
+ })
106
+ : phoneButton("Cancel", phone.onCancel),
107
+ phoneNotices(phone),
108
+ ],
109
+ }),
110
+ component(PhoneList, { phone }),
111
+ ],
112
+ });
113
+ }
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ import { type WatchActions } from "./watch-actions.ts";
3
+ export declare function isPhoneAction(path: string): boolean;
4
+ export declare function phoneAction(actions: WatchActions, request: IncomingMessage): Promise<string | null>;
5
+ export declare function phoneRead(runtimeDirectory: string): Promise<string>;
@@ -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,10 +1,12 @@
1
+ import type { CiRerunNotice } from "./github-ci-progress.ts";
1
2
  import type { WatchRun } from "./watch-render.ts";
2
3
  import { type PrRepository } from "./watch-pr-identity.ts";
3
4
  export interface GithubRecords {
4
5
  readonly started: unknown;
5
6
  readonly result: unknown;
7
+ readonly ciReruns?: readonly CiRerunNotice[];
6
8
  }
7
9
  export declare function pullOf(inputs: {
8
10
  readonly records: readonly GithubRecords[];
9
11
  readonly repository: PrRepository | null;
10
- }, runId: string): Pick<WatchRun, "pullRequest" | "reviews" | "mergeCommit" | "mergeProof">;
12
+ }, runId: string): Pick<WatchRun, "pullRequest" | "reviews" | "mergeCommit" | "mergeProof" | "ciReruns">;