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
@@ -1,10 +1,16 @@
1
+ import { operationalDecision } from "../decision-visibility.js";
2
+ import { workflowRefusals, } from "../workflow-refusals.js";
1
3
  import { isTicketStatus } from "../ticket-status.js";
4
+ import { isPromotionId } from "../workflow-contracts.js";
2
5
  import { priceFields, statusTurns } from "./watch-usage.js";
3
- import { priceOf, usageOf } from "../worker-usage.js";
6
+ import { priceOf, usageOf, attemptFields } from "../worker-usage.js";
4
7
  import { priceText } from "./usage-render.js";
5
- import { boardsOf, currentStepOf, roundOf, startWorkflowOf, } from "./watch-board.js";
8
+ import { boardsOf, currentStepOf, roundOf, stagesFor, startWorkflowOf, } from "./watch-board.js";
6
9
  import { decisionOf, phasesOf } from "./watch-phases.js";
10
+ import { pullOf } from "./watch-pull-request.js";
11
+ import { establishedIssue } from "./watch-pr-identity.js";
7
12
  import { displayRun } from "./watch-paths.js";
13
+ import { shownCommands } from "./command-effects.js";
8
14
  const textLimit = 600;
9
15
  const activityLimit = 400;
10
16
  function record(value) {
@@ -114,7 +120,10 @@ export function turnOf(records) {
114
120
  const result = record(records.result);
115
121
  const outcome = text(result["outcome"]);
116
122
  const report = record(parsed(text(result["result"])));
123
+ const harness = text(started["harness"]) || text(report["harness"]);
117
124
  return {
125
+ ...attemptFields(report["attempts"]),
126
+ ...(harness === "" ? {} : { harness }),
118
127
  key: records.key,
119
128
  operationId: text(started["operationId"]),
120
129
  usage: usageOf(report["usage"]),
@@ -156,54 +165,6 @@ export function decisionCommands(decision, client) {
156
165
  deny: `${client} deny ${decisionId} --text "<feedback>" ${binding}`,
157
166
  };
158
167
  }
159
- function githubOf(records) {
160
- const started = record(records.started);
161
- const operation = list(parsed(text(started["operationId"])));
162
- const result = record(records.result);
163
- const completed = result["outcome"] === "completed";
164
- return {
165
- runId: text(operation[2]),
166
- round: Number(operation[1]),
167
- method: text(started["method"]),
168
- report: completed ? record(parsed(text(result["result"]))) : {},
169
- };
170
- }
171
- function pullRequestOf(results) {
172
- const opened = results
173
- .filter((item) => item.method === "open-pr")
174
- .map((item) => item.report)
175
- .findLast((report) => text(report["url"]).startsWith("https://"));
176
- if (opened === undefined)
177
- return null;
178
- return { number: Number(opened["number"]), url: text(opened["url"]) };
179
- }
180
- function reviewsOf(results) {
181
- return results
182
- .filter((item) => item.method === "wait-review")
183
- .flatMap(({ round, report }) => {
184
- const score = count(report["score"]);
185
- if (score === null)
186
- return [];
187
- return [{ round, commit: text(report["commit"]), score }];
188
- });
189
- }
190
- function mergeCommitOf(results) {
191
- const merged = results
192
- .filter((item) => item.method === "merge")
193
- .map((item) => stamp(item.report["merged"]));
194
- return merged.find((commit) => commit !== null) ?? null;
195
- }
196
- function pullOf(inputs, runId) {
197
- const results = inputs.githubRecords
198
- .map(githubOf)
199
- .filter((item) => item.runId === runId)
200
- .toSorted((first, second) => first.round - second.round);
201
- return {
202
- pullRequest: pullRequestOf(results),
203
- reviews: reviewsOf(results),
204
- mergeCommit: mergeCommitOf(results),
205
- };
206
- }
207
168
  function feedbackOf(value) {
208
169
  const fields = record(value);
209
170
  return {
@@ -219,28 +180,49 @@ function eventOf(value) {
219
180
  type: text(fields["type"]),
220
181
  };
221
182
  }
183
+ function outcomeOf(value) {
184
+ const fields = record(value);
185
+ const { promotionId, ticketStatus, issueUpdate } = fields;
186
+ return {
187
+ outcome: stamp(fields["kind"]),
188
+ ...(isPromotionId(promotionId) ? { promotionId } : {}),
189
+ ...(isTicketStatus(ticketStatus) ? { ticketStatus } : {}),
190
+ ...(issueUpdate === "failed" ? { issueUpdate } : {}),
191
+ };
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
+ }
222
201
  function runOf(inputs, value) {
223
202
  const status = record(record(value)["status"]);
224
203
  const runId = text(status["runId"]);
225
204
  const workflowId = text(status["workflowId"]);
226
205
  const budget = record(status["budget"]);
227
206
  const ticketId = text(status["ticketId"]);
228
- const ticketStatus = record(status["outcome"])["ticketStatus"];
207
+ const issue = workflowId === "develop-issue"
208
+ ? establishedIssue(inputs.repository ?? null, status["issueIdentity"])
209
+ : null;
229
210
  return {
230
211
  runId,
231
212
  workflowId,
213
+ ...runLinksOf(status),
232
214
  ticketId: ticketId === "" ? null : ticketId,
215
+ ...(issue === null ? {} : { issueIdentity: issue }),
233
216
  title: stamp(status["title"]),
234
- outcome: stamp(record(status["outcome"])["kind"]),
235
- ...(isTicketStatus(ticketStatus) ? { ticketStatus } : {}),
236
- ...(record(status["outcome"])["issueUpdate"] === "failed"
237
- ? { issueUpdate: "failed" }
238
- : {}),
217
+ ...outcomeOf(status["outcome"]),
239
218
  latestAt: stamp(status["latestAt"]),
240
219
  claudeCostUsd: priceOf(status["claudeCostUsd"]),
241
220
  estimatedCostUsd: priceOf(status["estimatedCostUsd"]),
242
221
  usage: usageOf(status["usage"]),
243
- currentStep: currentStepOf(list(record(value)["events"]), workflowId),
222
+ currentStep: currentStepOf(list(record(value)["events"]), {
223
+ workflowId,
224
+ stages: stagesFor(inputs.workflowStages, workflowId),
225
+ }),
244
226
  round: roundOf(list(record(value)["events"])),
245
227
  state: text(status["state"]),
246
228
  code: text(record(status["reason"])["code"]),
@@ -249,13 +231,19 @@ function runOf(inputs, value) {
249
231
  limit: count(budget["limit"]),
250
232
  decisions: inputs.decisions
251
233
  .filter((decision) => record(decision)["runId"] === runId)
252
- .map((decision) => decisionCommands(decision, inputs.client)),
234
+ .map((decision) => decisionCommands(operationalDecision(record(decision), workflowId), inputs.client)),
253
235
  events: list(record(value)["events"]).map(eventOf),
254
236
  turns: statusTurns(inputs.turns, status),
237
+ ...(status["commandEffects"] === undefined
238
+ ? {}
239
+ : { commandEffects: shownCommands(status["commandEffects"]) }),
255
240
  phases: phasesOf(list(record(value)["events"]), workflowId),
256
241
  decision: decisionOf(list(record(value)["events"])),
257
242
  feedback: list(status["feedback"]).map(feedbackOf),
258
- ...pullOf(inputs, runId),
243
+ ...pullOf({
244
+ records: inputs.githubRecords,
245
+ repository: workflowId === "develop-issue" ? (inputs.repository ?? null) : null,
246
+ }, runId),
259
247
  };
260
248
  }
261
249
  function began(run) {
@@ -270,6 +258,8 @@ export function watchModel(inputs) {
270
258
  const workflows = boardsOf({ ...inputs, completionCandidates: candidates }, runs);
271
259
  return {
272
260
  workflows,
261
+ ...(inputs.queue === undefined ? {} : { queue: inputs.queue }),
262
+ workflowRefusals: workflowRefusals(inputs.workflowRefusals),
273
263
  startWorkflowId: startWorkflowOf(workflows),
274
264
  updatedAt: inputs.updatedAt,
275
265
  service: inputs.service,
@@ -1,16 +1,30 @@
1
1
  import { cardReply } from "./watch-card-reply.js";
2
+ import { record } from "../protocol.js";
3
+ import { Commands, commandText } from "./command-effects.js";
2
4
  import { watchCardClient } from "./watch-card-client.js";
3
5
  import { AddCard, CardInput, cardKey, cardSubmitKey, } from "./watch-card-view.js";
4
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";
5
9
  import { priceOf, tokenCount, usageOf } from "../worker-usage.js";
6
- import { priceText, usageText, totalsSuffix } from "./usage-render.js";
10
+ import { priceText, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
7
11
  import { startPrompts, StartCard, StartRun } from "./watch-start-view.js";
8
- import { Board, boardSizing, Card, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, } from "./watch-board-view.js";
12
+ import { Board, boardSizing, Card, HandoffLinks, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, observationText, staleObservation, } from "./watch-board-view.js";
9
13
  import { boardWorkflow, watchHash, watchLocation, watchTitle, } from "./watch-navigation.js";
10
14
  import { clockTime, completedDetail, counted, elapsed, groupActivity, pageTitle, phaseTime, runName, runTone, selectedRun, toneOf, turnTime, waitingDetail, } from "./watch-render.js";
11
15
  import { Command, Decision, Events, Group, Item, Turn, Work, } from "./watch-turn.js";
12
- import { clove, Banner, BannerDetail, BoardPage, Header, Page, Phases, PullRequest, Review, 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";
13
18
  const functions = [
19
+ record,
20
+ commandText,
21
+ Commands,
22
+ queueLanes,
23
+ skippedText,
24
+ Queue,
25
+ Brand,
26
+ HeaderStatus,
27
+ HeaderActions,
14
28
  cardReply,
15
29
  cardSubmitKey,
16
30
  cardKey,
@@ -21,6 +35,7 @@ const functions = [
21
35
  usageOf,
22
36
  priceText,
23
37
  usageText,
38
+ attemptText,
24
39
  totalsSuffix,
25
40
  watchHash,
26
41
  watchLocation,
@@ -29,8 +44,11 @@ const functions = [
29
44
  cardReview,
30
45
  cardStep,
31
46
  completionMark,
47
+ observationText,
48
+ staleObservation,
32
49
  CardReview,
33
50
  Card,
51
+ HandoffLinks,
34
52
  Column,
35
53
  columnCollapsed,
36
54
  WorkflowList,
@@ -64,7 +82,16 @@ const functions = [
64
82
  PullRequest,
65
83
  Review,
66
84
  Run,
85
+ timeLeft,
86
+ refusalText,
87
+ phoneButton,
88
+ phoneNotices,
89
+ PhoneCode,
90
+ PhoneAsk,
91
+ PhoneList,
92
+ PhonePanel,
67
93
  Header,
94
+ RefusedWorkflows,
68
95
  BoardPage,
69
96
  Page,
70
97
  ];
@@ -93,6 +120,15 @@ const dark = `
93
120
  --bad: #FF7B72; --bad-tint: rgba(255,123,114,0.14);
94
121
  `;
95
122
  const style = `
123
+ @font-face { font-family: "Fira Code"; font-style: normal; font-weight: 400; font-display: swap; src: url("/watch-fonts-v1/fira-code-latin-400-normal.woff2") format("woff2"); }
124
+ @font-face { font-family: "Fira Code"; font-style: normal; font-weight: 500; font-display: swap; src: url("/watch-fonts-v1/fira-code-latin-500-normal.woff2") format("woff2"); }
125
+ @font-face { font-family: "Heebo"; font-style: normal; font-weight: 500; font-display: swap; src: url("/watch-fonts-v1/heebo-latin-500-normal.woff2") format("woff2"); }
126
+ @font-face { font-family: "Heebo"; font-style: normal; font-weight: 700; font-display: swap; src: url("/watch-fonts-v1/heebo-latin-700-normal.woff2") format("woff2"); }
127
+ @font-face { font-family: "Heebo"; font-style: normal; font-weight: 800; font-display: swap; src: url("/watch-fonts-v1/heebo-latin-800-normal.woff2") format("woff2"); }
128
+ @font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 400; font-display: swap; src: url("/watch-fonts-v1/space-grotesk-latin-400-normal.woff2") format("woff2"); }
129
+ @font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 500; font-display: swap; src: url("/watch-fonts-v1/space-grotesk-latin-500-normal.woff2") format("woff2"); }
130
+ @font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 600; font-display: swap; src: url("/watch-fonts-v1/space-grotesk-latin-600-normal.woff2") format("woff2"); }
131
+ @font-face { font-family: "Space Grotesk"; font-style: normal; font-weight: 700; font-display: swap; src: url("/watch-fonts-v1/space-grotesk-latin-700-normal.woff2") format("woff2"); }
96
132
  :root {${light}
97
133
  --heading-font: "Heebo", system-ui, sans-serif;
98
134
  --body-font: "Space Grotesk", system-ui, sans-serif;
@@ -111,8 +147,23 @@ body:has(.board-page) { padding-bottom: 0; overflow: hidden; }
111
147
  .board-page { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
112
148
  .board-page > header, .board-page > .down { flex-shrink: 0; }
113
149
  .start-run { flex-shrink: 0; max-height: 45dvh; overflow-y: auto; }
150
+ .workflow-refusals { flex-shrink: 0; max-height: 25dvh; overflow-y: auto; overflow-wrap: anywhere; }
151
+ .workflow-refusals h2 { margin: 8px 0; }
114
152
  a { color: var(--accent-strong); }
115
- 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; }
116
167
  .brand { display: inline-flex; align-items: center; gap: 9px; color: var(--ink); font: 800 26px/1.2 var(--heading-font); }
117
168
  .brand svg { width: 30px; height: 30px; color: var(--accent); }
118
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); }
@@ -129,43 +180,45 @@ h2, h3 { font-family: var(--heading-font); font-weight: 700; }
129
180
  .workflows a[aria-current="page"] { border-bottom-color: var(--accent); background: var(--surface); border-radius: 8px 8px 0 0; }
130
181
  .workflows span, .card small { color: var(--muted); font-size: 12px; }
131
182
  .board { width: 100%; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
132
- .board h2 { margin: 0 0 8px; font-size: 24px; flex-shrink: 0; }
133
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); }
134
184
  @supports selector(::-webkit-scrollbar) { .columns { scrollbar-color: auto; } }
135
185
  .columns::-webkit-scrollbar { height: 12px; }
136
186
  .columns::-webkit-scrollbar-track { background: var(--surface-2); }
137
187
  .columns::-webkit-scrollbar-thumb { background: var(--muted); border-radius: 6px; }
138
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); }
139
- .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; }
140
191
  .column-name > span:first-child { flex: 1; }
141
192
  .column-cards { min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
142
193
  .column.collapsed { flex: 0 0 ${String(boardSizing.collapsedColumnWidth)}px; min-width: ${String(boardSizing.collapsedColumnWidth)}px; padding: 6px; }
143
194
  .collapsed .column-name { writing-mode: vertical-rl; padding: 0; }
144
- .column-name button, .start-toggle { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
145
- .column-name button:hover, .start-toggle: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); }
146
197
  .add-card, .add-card-form button { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 4px 8px 4px 0; }
147
- .add-card { width: 100%; text-align: left; }
198
+ .add-card { width: 100%; text-align: left; margin: 4px 0; }
148
199
  .add-card-form { padding: 8px 0; overflow-wrap: anywhere; }
149
200
  .add-card-form label { display: block; color: var(--ink); margin-bottom: 8px; }
150
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); }
151
202
  .add-card-form textarea { resize: vertical; }
152
203
  .add-card-form button:disabled { opacity: 0.6; cursor: default; }
153
204
  .add-card-form p { font-size: 12px; margin: 8px 0; }
154
- .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); }
155
206
  .card:hover { outline: 1px solid var(--accent-strong); }
156
207
  .card-run { display: grid; gap: 4px; min-width: 0; color: inherit; text-decoration: none; }
157
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; }
158
209
  .completion-mark { font-size: 12px; }
159
- .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); }
160
212
  .card-step, .card-review { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
161
213
  .card-step { color: var(--muted); }
162
214
  .card-step.active { color: var(--accent-strong); }
163
215
  .card-review { color: var(--muted); }
164
216
  .review-pill { display: inline-block; padding: 1px 5px; border-radius: 5px; box-shadow: inset 0 0 0 1px var(--line); }
165
- .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); }
166
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); }
167
220
  .stopped .column-name { color: var(--bad); background: var(--surface); border-radius: 6px; }
168
- .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); }
169
222
  .back { display: block; width: fit-content; margin: 16px 0; }
170
223
  .icon { font-weight: 700; color: var(--muted); }
171
224
  .good .icon, .phase.done .mark, p.good { color: var(--accent-strong); }
@@ -243,13 +296,13 @@ export function pageDocument(actionToken = null) {
243
296
  `const actionToken = ${JSON.stringify(actionToken)};`,
244
297
  ...functions.map((item) => item.toString()),
245
298
  watchCardClient,
299
+ watchPhoneClient,
246
300
  watchClient,
247
301
  ].join("\n");
248
302
  return [
249
303
  "<!doctype html>",
250
304
  '<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Cloving</title>',
251
305
  `<link rel="icon" href="data:image/svg+xml,${encodeURIComponent(icon)}">`,
252
- '<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&amp;family=Heebo:wght@500;700;800&amp;family=Space+Grotesk:wght@400..700&amp;display=swap" media="print" onload="this.media=\'all\'">',
253
306
  `<style>${style}</style></head><body>`,
254
307
  '<div id="app"></div>',
255
308
  `<script type="module">${script}</script></body></html>`,
@@ -8,9 +8,9 @@ const effect = { open: "effect.requested", close: "effect.reported" };
8
8
  const issueWorkflow = "develop-issue";
9
9
  export const issueSteps = [
10
10
  { name: "Work tree", operation: "github-prepare" },
11
- { name: "Claude turn", operation: "claude-turn" },
11
+ { name: "Agent turn", operation: "claude-turn" },
12
12
  { name: "Pull request", operation: "github-open-pr" },
13
- { name: "Greptile review", operation: "github-wait-review" },
13
+ { name: "Code review", operation: "github-wait-review" },
14
14
  { name: "Merge", operation: "github-merge" },
15
15
  ];
16
16
  const verdicts = {
@@ -56,7 +56,7 @@ function ticketSpans(events) {
56
56
  return [
57
57
  ...admission(events),
58
58
  {
59
- name: "Claude turn",
59
+ name: "Agent turn",
60
60
  startedAt: firstAt(events, effect.open),
61
61
  endedAt: closedAt(events, effect),
62
62
  ending: "done",
@@ -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>;