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.
- package/README.md +584 -144
- package/assets/watch-fonts/fira-code-OFL.md +93 -0
- package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-OFL.md +93 -0
- package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
- package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
- package/assets/watch-fonts/manifest.json +112 -0
- package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
- package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
- package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- package/dist/src/agent-harness-shell.d.ts +12 -0
- package/dist/src/agent-harness-shell.js +90 -0
- package/dist/src/agent-harness-versions.d.ts +8 -0
- package/dist/src/agent-harness-versions.js +49 -0
- package/dist/src/agent-harnesses.d.ts +4 -0
- package/dist/src/agent-harnesses.js +13 -0
- package/dist/src/authority/commands.d.ts +2 -0
- package/dist/src/authority/commands.js +49 -8
- package/dist/src/authority/dispatch-decision.d.ts +1 -0
- package/dist/src/authority/dispatch-decision.js +7 -4
- package/dist/src/authority/events.js +2 -2
- package/dist/src/authority/gate-reduction.d.ts +1 -0
- package/dist/src/authority/gate-reduction.js +18 -3
- package/dist/src/authority/gates.d.ts +2 -1
- package/dist/src/authority/gates.js +5 -1
- package/dist/src/authority/handoff-chain.d.ts +24 -0
- package/dist/src/authority/handoff-chain.js +46 -0
- package/dist/src/authority/operations.js +1 -1
- package/dist/src/authority/reconciliation.d.ts +1 -0
- package/dist/src/authority/reconciliation.js +18 -11
- package/dist/src/authority/reduction.d.ts +1 -1
- package/dist/src/authority/reduction.js +6 -1
- package/dist/src/authority/status-input.d.ts +1 -1
- package/dist/src/authority/status.d.ts +1 -0
- package/dist/src/authority/status.js +27 -3
- package/dist/src/authority/transitions.d.ts +5 -5
- package/dist/src/authority/transitions.js +9 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +11 -1
- package/dist/src/broker/actor/authority-queries.js +67 -3
- package/dist/src/broker/actor/authority-receipts.js +11 -1
- package/dist/src/broker/actor/authority-session.js +2 -2
- package/dist/src/broker/actor/authority-settings.js +4 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +3 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +13 -1
- package/dist/src/broker/actor/effect-queries.d.ts +1 -0
- package/dist/src/broker/actor/effect-queries.js +7 -0
- package/dist/src/broker/actor/pin-check.js +1 -1
- package/dist/src/broker/actor/stop-plan.js +1 -1
- package/dist/src/broker/actor/turn-state.js +1 -1
- package/dist/src/broker/authority-admission.js +26 -5
- package/dist/src/broker/authority-restore.js +1 -0
- package/dist/src/broker/decision-restore.js +4 -4
- package/dist/src/broker/socket-address.d.ts +3 -1
- package/dist/src/broker/socket-address.js +2 -2
- package/dist/src/cli/arguments.d.ts +11 -13
- package/dist/src/cli/arguments.js +37 -107
- package/dist/src/cli/command-effects.d.ts +7 -0
- package/dist/src/cli/command-effects.js +39 -0
- package/dist/src/cli/commands.js +11 -4
- package/dist/src/cli/config-arguments.d.ts +11 -0
- package/dist/src/cli/config-arguments.js +59 -0
- package/dist/src/cli/config-command.d.ts +2 -0
- package/dist/src/cli/config-command.js +105 -0
- package/dist/src/cli/config-file.d.ts +3 -0
- package/dist/src/cli/config-file.js +50 -0
- package/dist/src/cli/config-lock.d.ts +7 -0
- package/dist/src/cli/config-lock.js +61 -0
- package/dist/src/cli/config-notice.d.ts +5 -0
- package/dist/src/cli/config-notice.js +46 -0
- package/dist/src/cli/doctor-github.d.ts +9 -0
- package/dist/src/cli/doctor-github.js +138 -0
- package/dist/src/cli/doctor-harness.d.ts +13 -0
- package/dist/src/cli/doctor-harness.js +242 -0
- package/dist/src/cli/doctor-local.d.ts +18 -0
- package/dist/src/cli/doctor-local.js +77 -0
- package/dist/src/cli/doctor-runtime.d.ts +15 -0
- package/dist/src/cli/doctor-runtime.js +176 -0
- package/dist/src/cli/doctor-service.d.ts +1 -0
- package/dist/src/cli/doctor-service.js +11 -0
- package/dist/src/cli/doctor-workflows.d.ts +3 -0
- package/dist/src/cli/doctor-workflows.js +45 -0
- package/dist/src/cli/doctor.d.ts +15 -0
- package/dist/src/cli/doctor.js +190 -0
- package/dist/src/cli/github-ci-progress.d.ts +8 -0
- package/dist/src/cli/github-ci-progress.js +83 -0
- package/dist/src/cli/github-retry.d.ts +6 -0
- package/dist/src/cli/github-retry.js +47 -0
- package/dist/src/cli/harness-probes.d.ts +22 -0
- package/dist/src/cli/harness-probes.js +183 -0
- package/dist/src/cli/main.d.ts +7 -1
- package/dist/src/cli/main.js +39 -61
- package/dist/src/cli/phone-arguments.d.ts +14 -0
- package/dist/src/cli/phone-arguments.js +37 -0
- package/dist/src/cli/phone-client.d.ts +2 -0
- package/dist/src/cli/phone-client.js +32 -0
- package/dist/src/cli/phone-command.d.ts +13 -0
- package/dist/src/cli/phone-command.js +101 -0
- package/dist/src/cli/probe-command.d.ts +36 -0
- package/dist/src/cli/probe-command.js +59 -0
- package/dist/src/cli/project-settings.d.ts +4 -0
- package/dist/src/cli/project-settings.js +33 -0
- package/dist/src/cli/render.d.ts +3 -1
- package/dist/src/cli/render.js +102 -39
- package/dist/src/cli/report-github.d.ts +18 -0
- package/dist/src/cli/report-github.js +200 -0
- package/dist/src/cli/report.d.ts +17 -0
- package/dist/src/cli/report.js +192 -0
- package/dist/src/cli/repository-arguments.d.ts +5 -0
- package/dist/src/cli/repository-arguments.js +34 -0
- package/dist/src/cli/runtime-arguments.d.ts +4 -0
- package/dist/src/cli/runtime-arguments.js +15 -0
- package/dist/src/cli/runtime-directory.d.ts +6 -2
- package/dist/src/cli/runtime-directory.js +72 -14
- package/dist/src/cli/toolchain.d.ts +2 -0
- package/dist/src/cli/toolchain.js +22 -2
- package/dist/src/cli/usage-render.d.ts +5 -0
- package/dist/src/cli/usage-render.js +40 -1
- package/dist/src/cli/usage.d.ts +3 -3
- package/dist/src/cli/usage.js +74 -45
- package/dist/src/cli/watch-actions.d.ts +2 -0
- package/dist/src/cli/watch-actions.js +4 -4
- package/dist/src/cli/watch-board-view.d.ts +12 -1
- package/dist/src/cli/watch-board-view.js +64 -12
- package/dist/src/cli/watch-board.d.ts +7 -1
- package/dist/src/cli/watch-board.js +61 -16
- package/dist/src/cli/watch-card-forms.js +2 -2
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +12 -3
- package/dist/src/cli/watch-header-view.d.ts +27 -0
- package/dist/src/cli/watch-header-view.js +116 -0
- package/dist/src/cli/watch-model.d.ts +10 -4
- package/dist/src/cli/watch-model.js +49 -59
- package/dist/src/cli/watch-page.js +67 -14
- package/dist/src/cli/watch-phases.js +3 -3
- package/dist/src/cli/watch-phone-client.d.ts +1 -0
- package/dist/src/cli/watch-phone-client.js +84 -0
- package/dist/src/cli/watch-phone-view.d.ts +56 -0
- package/dist/src/cli/watch-phone-view.js +113 -0
- package/dist/src/cli/watch-phone.d.ts +5 -0
- package/dist/src/cli/watch-phone.js +53 -0
- package/dist/src/cli/watch-pr-command.d.ts +5 -2
- package/dist/src/cli/watch-pr-command.js +41 -4
- package/dist/src/cli/watch-pr-identity.d.ts +14 -2
- package/dist/src/cli/watch-pr-identity.js +25 -0
- package/dist/src/cli/watch-pr-observer.d.ts +1 -0
- package/dist/src/cli/watch-pr-observer.js +48 -6
- package/dist/src/cli/watch-pull-request.d.ts +12 -0
- package/dist/src/cli/watch-pull-request.js +134 -0
- package/dist/src/cli/watch-reads.d.ts +7 -1
- package/dist/src/cli/watch-reads.js +42 -20
- package/dist/src/cli/watch-render.d.ts +23 -2
- package/dist/src/cli/watch-render.js +2 -1
- package/dist/src/cli/watch-server.js +56 -7
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +38 -2
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +10 -17
- package/dist/src/cli/watch-view.js +33 -77
- package/dist/src/cli.js +106 -23
- package/dist/src/command-settings.d.ts +16 -0
- package/dist/src/command-settings.js +42 -0
- package/dist/src/configuration-change.d.ts +11 -0
- package/dist/src/configuration-change.js +62 -0
- package/dist/src/configuration-display.d.ts +21 -0
- package/dist/src/configuration-display.js +69 -0
- package/dist/src/configuration-schema.d.ts +49 -0
- package/dist/src/configuration-schema.js +159 -0
- package/dist/src/daemon/claude-turn.d.ts +20 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -5
- package/dist/src/daemon/claude-worker.js +64 -80
- package/dist/src/daemon/command-journal.d.ts +5 -0
- package/dist/src/daemon/command-journal.js +50 -0
- package/dist/src/daemon/command-process.d.ts +28 -0
- package/dist/src/daemon/command-process.js +164 -0
- package/dist/src/daemon/command-worker.d.ts +19 -0
- package/dist/src/daemon/command-worker.js +182 -0
- package/dist/src/daemon/cursor-stream.d.ts +4 -0
- package/dist/src/daemon/cursor-stream.js +154 -0
- package/dist/src/daemon/daemon-adapters.d.ts +58 -0
- package/dist/src/daemon/daemon-adapters.js +102 -0
- package/dist/src/daemon/daemon-loops.d.ts +14 -0
- package/dist/src/daemon/daemon-loops.js +39 -0
- package/dist/src/daemon/daemon.d.ts +3 -30
- package/dist/src/daemon/daemon.js +132 -110
- package/dist/src/daemon/declared-input.d.ts +3 -0
- package/dist/src/daemon/declared-input.js +9 -0
- package/dist/src/daemon/delivery-router.js +7 -1
- package/dist/src/daemon/gemini-stream.d.ts +4 -0
- package/dist/src/daemon/gemini-stream.js +129 -0
- package/dist/src/daemon/github-calls.d.ts +4 -0
- package/dist/src/daemon/github-calls.js +16 -7
- package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.d.ts +6 -0
- package/dist/src/daemon/github-ci.js +251 -0
- package/dist/src/daemon/github-merge-call.d.ts +16 -0
- package/dist/src/daemon/github-merge-call.js +73 -0
- package/dist/src/daemon/github-merge.d.ts +3 -5
- package/dist/src/daemon/github-merge.js +59 -98
- package/dist/src/daemon/github-methods.d.ts +28 -0
- package/dist/src/daemon/github-methods.js +90 -16
- package/dist/src/daemon/github-operation.d.ts +3 -0
- package/dist/src/daemon/github-retry.d.ts +6 -0
- package/dist/src/daemon/github-retry.js +13 -0
- package/dist/src/daemon/github-ticket-status.js +27 -1
- package/dist/src/daemon/github-worker.js +2 -1
- package/dist/src/daemon/handoff-worker.d.ts +10 -0
- package/dist/src/daemon/handoff-worker.js +232 -0
- package/dist/src/daemon/issue-queue.d.ts +2 -0
- package/dist/src/daemon/issue-queue.js +92 -63
- package/dist/src/daemon/notify-journal.d.ts +18 -0
- package/dist/src/daemon/notify-journal.js +108 -0
- package/dist/src/daemon/notify-message.js +2 -1
- package/dist/src/daemon/notify.js +177 -37
- package/dist/src/daemon/opencode-stream.d.ts +5 -0
- package/dist/src/daemon/opencode-stream.js +87 -0
- package/dist/src/daemon/queue-status.d.ts +4 -0
- package/dist/src/daemon/queue-status.js +38 -0
- package/dist/src/daemon/retry-worktree.d.ts +18 -0
- package/dist/src/daemon/retry-worktree.js +139 -0
- package/dist/src/daemon/retrying-turn.d.ts +5 -0
- package/dist/src/daemon/retrying-turn.js +145 -21
- package/dist/src/daemon/schedule-journal.d.ts +19 -0
- package/dist/src/daemon/schedule-journal.js +57 -0
- package/dist/src/daemon/text-output.d.ts +18 -0
- package/dist/src/daemon/text-output.js +44 -0
- package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
- package/dist/src/daemon/ticket-dependency-waits.js +60 -0
- package/dist/src/daemon/ticket-registration.d.ts +10 -8
- package/dist/src/daemon/ticket-registration.js +146 -47
- package/dist/src/daemon/ticket-source.d.ts +4 -1
- package/dist/src/daemon/ticket-source.js +8 -2
- package/dist/src/daemon/turn-command.d.ts +10 -0
- package/dist/src/daemon/turn-command.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +18 -0
- package/dist/src/daemon/turn-report.js +79 -0
- package/dist/src/daemon/work-tree.d.ts +2 -1
- package/dist/src/daemon/work-tree.js +15 -12
- package/dist/src/daemon/workflow-generations.d.ts +32 -0
- package/dist/src/daemon/workflow-generations.js +57 -0
- package/dist/src/daemon/workflow-replay.d.ts +16 -0
- package/dist/src/daemon/workflow-replay.js +58 -0
- package/dist/src/daemon/workflow-schedules.d.ts +27 -0
- package/dist/src/daemon/workflow-schedules.js +185 -0
- package/dist/src/decision-visibility.d.ts +2 -0
- package/dist/src/decision-visibility.js +10 -0
- package/dist/src/decision-wait.d.ts +1 -0
- package/dist/src/decision-wait.js +3 -0
- package/dist/src/delivery-backoff.d.ts +1 -0
- package/dist/src/delivery-backoff.js +3 -0
- package/dist/src/doctor-report.d.ts +24 -0
- package/dist/src/doctor-report.js +70 -0
- package/dist/src/execution-pin.d.ts +9 -0
- package/dist/src/execution-pin.js +86 -2
- package/dist/src/grok-result.d.ts +12 -0
- package/dist/src/grok-result.js +61 -0
- package/dist/src/harness-defaults.d.ts +35 -0
- package/dist/src/harness-defaults.js +121 -0
- package/dist/src/host/decision-resume.d.ts +35 -0
- package/dist/src/host/decision-resume.js +86 -0
- package/dist/src/host/gate-bridge.d.ts +48 -0
- package/dist/src/host/gate-bridge.js +124 -0
- package/dist/src/host/run-wait.d.ts +26 -0
- package/dist/src/host/run-wait.js +37 -0
- package/dist/src/host/start-delivery.d.ts +3 -2
- package/dist/src/host/start-delivery.js +11 -4
- package/dist/src/host/step-bridge-host.d.ts +6 -19
- package/dist/src/host/step-bridge-host.js +57 -55
- package/dist/src/host/world-reconciliation.d.ts +1 -0
- package/dist/src/host/world-reconciliation.js +3 -0
- package/dist/src/host/world-runs.js +5 -0
- package/dist/src/issue-identity.d.ts +6 -0
- package/dist/src/issue-identity.js +23 -0
- package/dist/src/merge-request.d.ts +19 -0
- package/dist/src/merge-request.js +32 -0
- package/dist/src/phone/canonical-json.d.ts +1 -0
- package/dist/src/phone/canonical-json.js +16 -0
- package/dist/src/phone/phone-link.d.ts +7 -0
- package/dist/src/phone/phone-link.js +21 -0
- package/dist/src/phone/qr-data.d.ts +8 -0
- package/dist/src/phone/qr-data.js +133 -0
- package/dist/src/phone/qr-matrix.d.ts +6 -0
- package/dist/src/phone/qr-matrix.js +175 -0
- package/dist/src/phone/qr-penalty.d.ts +3 -0
- package/dist/src/phone/qr-penalty.js +67 -0
- package/dist/src/phone/qr-picture.d.ts +5 -0
- package/dist/src/phone/qr-picture.js +24 -0
- package/dist/src/private-config.schema.json +263 -0
- package/dist/src/project-config.schema.json +65 -0
- package/dist/src/project-settings.d.ts +19 -0
- package/dist/src/project-settings.js +131 -0
- package/dist/src/relay/answer-check.d.ts +24 -0
- package/dist/src/relay/answer-check.js +145 -0
- package/dist/src/relay/answer-inbox.d.ts +15 -0
- package/dist/src/relay/answer-inbox.js +173 -0
- package/dist/src/relay/daemon-keys.d.ts +16 -0
- package/dist/src/relay/daemon-keys.js +75 -0
- package/dist/src/relay/decision-check.d.ts +3 -0
- package/dist/src/relay/decision-check.js +77 -0
- package/dist/src/relay/decision-close.d.ts +6 -0
- package/dist/src/relay/decision-close.js +72 -0
- package/dist/src/relay/decision-envelopes.d.ts +29 -0
- package/dist/src/relay/decision-envelopes.js +93 -0
- package/dist/src/relay/decision-watch.d.ts +14 -0
- package/dist/src/relay/decision-watch.js +68 -0
- package/dist/src/relay/envelope-post.d.ts +8 -0
- package/dist/src/relay/envelope-post.js +71 -0
- package/dist/src/relay/envelope.d.ts +28 -0
- package/dist/src/relay/envelope.js +53 -0
- package/dist/src/relay/hpke.d.ts +25 -0
- package/dist/src/relay/hpke.js +108 -0
- package/dist/src/relay/pairing-checks.d.ts +42 -0
- package/dist/src/relay/pairing-checks.js +172 -0
- package/dist/src/relay/pairing-follow.d.ts +8 -0
- package/dist/src/relay/pairing-follow.js +95 -0
- package/dist/src/relay/pairing-session.d.ts +29 -0
- package/dist/src/relay/pairing-session.js +87 -0
- package/dist/src/relay/phone-delivery.d.ts +51 -0
- package/dist/src/relay/phone-delivery.js +139 -0
- package/dist/src/relay/phone-devices.d.ts +36 -0
- package/dist/src/relay/phone-devices.js +46 -0
- package/dist/src/relay/phone-inbox.d.ts +18 -0
- package/dist/src/relay/phone-inbox.js +17 -0
- package/dist/src/relay/phone-operations.d.ts +18 -0
- package/dist/src/relay/phone-operations.js +121 -0
- package/dist/src/relay/phone-outbox.d.ts +21 -0
- package/dist/src/relay/phone-outbox.js +25 -0
- package/dist/src/relay/phone-socket.d.ts +6 -0
- package/dist/src/relay/phone-socket.js +63 -0
- package/dist/src/relay/relay-control.d.ts +7 -0
- package/dist/src/relay/relay-control.js +24 -0
- package/dist/src/relay/relay-files.d.ts +2 -0
- package/dist/src/relay/relay-files.js +23 -0
- package/dist/src/relay/relay-heartbeat.d.ts +17 -0
- package/dist/src/relay/relay-heartbeat.js +81 -0
- package/dist/src/relay/relay-http.d.ts +14 -0
- package/dist/src/relay/relay-http.js +63 -0
- package/dist/src/relay/relay-registration.d.ts +15 -0
- package/dist/src/relay/relay-registration.js +63 -0
- package/dist/src/relay/relay-service.d.ts +25 -0
- package/dist/src/relay/relay-service.js +216 -0
- package/dist/src/relay/relay-store.d.ts +48 -0
- package/dist/src/relay/relay-store.js +131 -0
- package/dist/src/relay/sealed-post.d.ts +25 -0
- package/dist/src/relay/sealed-post.js +52 -0
- package/dist/src/relay.d.ts +1 -0
- package/dist/src/relay.js +8 -0
- package/dist/src/report-statistics.d.ts +50 -0
- package/dist/src/report-statistics.js +70 -0
- package/dist/src/report.d.ts +171 -0
- package/dist/src/report.js +119 -0
- package/dist/src/repository-identity.d.ts +4 -0
- package/dist/src/repository-identity.js +4 -0
- package/dist/src/review-subject.d.ts +41 -0
- package/dist/src/review-subject.js +91 -0
- package/dist/src/run-wait.d.ts +23 -0
- package/dist/src/run-wait.js +20 -0
- package/dist/src/service/active-tickets.d.ts +4 -0
- package/dist/src/service/active-tickets.js +49 -0
- package/dist/src/service/command-effects.d.ts +4 -0
- package/dist/src/service/command-effects.js +16 -0
- package/dist/src/service/decision-handler.d.ts +4 -0
- package/dist/src/service/decision-handler.js +39 -4
- package/dist/src/service/gateway.js +18 -3
- package/dist/src/service/queue-runs.d.ts +3 -0
- package/dist/src/service/queue-runs.js +39 -0
- package/dist/src/service/registry.d.ts +22 -3
- package/dist/src/service/registry.js +51 -8
- package/dist/src/service/replies.d.ts +10 -0
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +45 -54
- package/dist/src/service/run-metadata.d.ts +8 -0
- package/dist/src/service/run-metadata.js +53 -0
- package/dist/src/service/run-waits.d.ts +3 -0
- package/dist/src/service/run-waits.js +41 -0
- package/dist/src/service/service.d.ts +21 -2
- package/dist/src/service/service.js +23 -5
- package/dist/src/service/submission-handler.js +70 -19
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +10 -1
- package/dist/src/step-bridge.d.ts +32 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -0
- package/dist/src/steps/handoff.d.ts +2 -0
- package/dist/src/steps/handoff.js +13 -0
- package/dist/src/steps/merge-by-person.d.ts +2 -0
- package/dist/src/steps/merge-by-person.js +18 -0
- package/dist/src/steps/merge-when-green.d.ts +2 -0
- package/dist/src/steps/merge-when-green.js +62 -0
- package/dist/src/steps/review-by-agent.d.ts +5 -0
- package/dist/src/steps/review-by-agent.js +124 -0
- package/dist/src/steps/review-by-person.d.ts +4 -0
- package/dist/src/steps/review-by-person.js +16 -0
- package/dist/src/steps/review-subject.d.ts +2 -0
- package/dist/src/steps/review-subject.js +11 -0
- package/dist/src/steps/run-command.d.ts +2 -0
- package/dist/src/steps/run-command.js +15 -0
- package/dist/src/steps/sleep.d.ts +3 -0
- package/dist/src/steps/sleep.js +19 -0
- package/dist/src/steps/wait-for-decision.d.ts +2 -0
- package/dist/src/steps/wait-for-decision.js +71 -0
- package/dist/src/steps/wait-for-run.d.ts +5 -0
- package/dist/src/steps/wait-for-run.js +9 -0
- package/dist/src/storage/decision-snapshots.d.ts +1 -0
- package/dist/src/storage/decision-snapshots.js +7 -1
- package/dist/src/submission.d.ts +4 -0
- package/dist/src/submission.js +6 -2
- package/dist/src/testing.d.ts +29 -0
- package/dist/src/testing.js +264 -0
- package/dist/src/ticket-dependencies.d.ts +1 -0
- package/dist/src/ticket-dependencies.js +15 -0
- package/dist/src/ticket-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/ticket-status.js +7 -4
- package/dist/src/token-prices.d.ts +14 -4
- package/dist/src/token-prices.js +56 -11
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +25 -0
- package/dist/src/worker-usage.js +58 -1
- package/dist/src/workflow-admission.d.ts +6 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +48 -5
- package/dist/src/workflow-contracts.d.ts +2 -0
- package/dist/src/workflow-contracts.js +8 -3
- package/dist/src/workflow-declaration.d.ts +31 -2
- package/dist/src/workflow-declaration.js +140 -16
- package/dist/src/workflow-discovery.d.ts +19 -0
- package/dist/src/workflow-discovery.js +36 -0
- package/dist/src/workflow-refusals.d.ts +6 -0
- package/dist/src/workflow-refusals.js +42 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +12 -1
- package/dist/src/workflows.js +9 -0
- package/dist/tools/admit-workflow.d.ts +14 -0
- package/dist/tools/admit-workflow.js +107 -0
- package/dist/tools/doctor-adoption.d.ts +1 -0
- package/dist/tools/doctor-adoption.js +11 -0
- package/dist/tools/project-configuration.d.ts +4 -0
- package/dist/tools/project-configuration.js +47 -0
- package/dist/tools/self-host-processes.d.ts +1 -0
- package/dist/tools/self-host-processes.js +33 -22
- package/dist/tools/self-host-project.d.ts +21 -0
- package/dist/tools/self-host-project.js +224 -0
- package/dist/tools/self-host-runtime.d.ts +16 -0
- package/dist/tools/self-host-runtime.js +60 -0
- package/dist/tools/self-host-workflows.d.ts +1 -0
- package/dist/tools/self-host-workflows.js +36 -1
- package/dist/tools/self-host.js +106 -135
- package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
- package/dist/tools/workflow-bundle-dependencies.js +93 -0
- package/dist/tools/workflow-bundles.d.ts +20 -0
- package/dist/tools/workflow-bundles.js +173 -0
- package/dist/tools/workflow-candidate-counts.d.ts +12 -0
- package/dist/tools/workflow-candidate-counts.js +266 -0
- package/dist/tools/workflow-candidate-fields.d.ts +5 -0
- package/dist/tools/workflow-candidate-fields.js +24 -0
- package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
- package/dist/tools/workflow-candidate-helper-counts.js +129 -0
- package/dist/tools/workflow-candidate-program.d.ts +13 -0
- package/dist/tools/workflow-candidate-program.js +106 -0
- package/dist/tools/workflow-candidate-source.d.ts +6 -0
- package/dist/tools/workflow-candidate-source.js +169 -0
- package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
- package/dist/tools/workflow-candidate-syntax.js +263 -0
- package/dist/tools/workflow-command.d.ts +1 -0
- package/dist/tools/workflow-command.js +143 -0
- package/dist/tools/workflow-folder-capture.d.ts +18 -0
- package/dist/tools/workflow-folder-capture.js +261 -0
- package/dist/tools/workflow-folders.d.ts +49 -0
- package/dist/tools/workflow-folders.js +203 -0
- package/dist/tools/workflow-source-effects.d.ts +10 -0
- package/dist/tools/workflow-source-effects.js +213 -0
- package/dist/tools/workflow-test-hook.d.ts +7 -0
- package/dist/tools/workflow-test-hook.js +16 -0
- package/dist/tools/workflow-test-loader.d.ts +1 -0
- package/dist/tools/workflow-test-loader.js +10 -0
- package/dist/workflows/develop-prd.js +71 -3
- package/dist/workflows/develop-ticket.js +6 -1
- package/dist/workflows/ticket-prompts.js +17 -3
- package/package.json +66 -6
- package/templates/develop/README.md +78 -0
- package/templates/develop/develop/accept.ts +11 -0
- package/templates/develop/develop/flow-tests.ts +357 -0
- package/templates/develop/develop/local.ts +40 -0
- package/templates/develop/develop/option-tests.ts +174 -0
- package/templates/develop/develop/partial-choice.ts +29 -0
- package/templates/develop/develop/partial.ts +28 -0
- package/templates/develop/develop/pull.ts +152 -0
- package/templates/develop/develop/queue-partial.ts +39 -0
- package/templates/develop/develop/refusal-tests.ts +174 -0
- package/templates/develop/develop/report.ts +156 -0
- package/templates/develop/develop/round.ts +40 -0
- package/templates/develop/develop/scenarios.ts +87 -0
- package/templates/develop/develop/turn.ts +67 -0
- package/templates/develop/develop.declaration.json +24 -0
- package/templates/develop/develop.test.ts +287 -0
- package/templates/develop/develop.ts +30 -0
- package/templates/develop/template.json +153 -0
- package/dist/src/chats/analysis-batches.d.ts +0 -24
- package/dist/src/chats/analysis-batches.js +0 -83
- package/dist/src/chats/analysis-contract.d.ts +0 -80
- package/dist/src/chats/analysis-contract.js +0 -16
- package/dist/src/chats/analysis-data.d.ts +0 -3
- package/dist/src/chats/analysis-data.js +0 -85
- package/dist/src/chats/analysis-input.d.ts +0 -12
- package/dist/src/chats/analysis-input.js +0 -83
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-prompt.d.ts +0 -10
- package/dist/src/chats/analysis-prompt.js +0 -16
- package/dist/src/chats/analysis-proposal.d.ts +0 -2
- package/dist/src/chats/analysis-proposal.js +0 -32
- package/dist/src/chats/analysis-provenance.d.ts +0 -4
- package/dist/src/chats/analysis-provenance.js +0 -99
- package/dist/src/chats/analysis-shape.d.ts +0 -3
- package/dist/src/chats/analysis-shape.js +0 -228
- package/dist/src/chats/analysis.d.ts +0 -3
- package/dist/src/chats/analysis.js +0 -42
- package/dist/src/chats/corpus-input.d.ts +0 -5
- package/dist/src/chats/corpus-input.js +0 -288
- package/dist/src/chats/destination.d.ts +0 -4
- package/dist/src/chats/destination.js +0 -96
- package/dist/src/chats/import.d.ts +0 -15
- package/dist/src/chats/import.js +0 -243
- package/dist/src/chats/input-file.d.ts +0 -3
- package/dist/src/chats/input-file.js +0 -32
- package/dist/src/chats/normalize.d.ts +0 -29
- package/dist/src/chats/normalize.js +0 -155
- package/dist/src/chats/previous-import.d.ts +0 -5
- package/dist/src/chats/previous-import.js +0 -34
- package/dist/src/chats/reader.d.ts +0 -21
- package/dist/src/chats/reader.js +0 -118
- package/dist/src/chats/redact-import.d.ts +0 -14
- package/dist/src/chats/redact-import.js +0 -141
- package/dist/src/chats/redaction.d.ts +0 -41
- package/dist/src/chats/redaction.js +0 -161
- package/dist/src/chats/revision-input.d.ts +0 -3
- package/dist/src/chats/revision-input.js +0 -180
- package/dist/src/chats/revision.d.ts +0 -48
- package/dist/src/chats/revision.js +0 -94
- package/dist/src/chats/selection.d.ts +0 -25
- package/dist/src/chats/selection.js +0 -109
- package/dist/src/chats/source.d.ts +0 -23
- package/dist/src/chats/source.js +0 -135
- package/dist/src/chats/structure.d.ts +0 -57
- package/dist/src/chats/structure.js +0 -216
- package/dist/src/daemon/analysis-launch.d.ts +0 -5
- package/dist/src/daemon/analysis-launch.js +0 -81
- package/dist/src/daemon/analysis-token.d.ts +0 -6
- package/dist/src/daemon/analysis-token.js +0 -88
- package/dist/src/daemon/analysis-worker.d.ts +0 -22
- package/dist/src/daemon/analysis-worker.js +0 -219
- package/dist/src/daemon/chats-files.d.ts +0 -15
- package/dist/src/daemon/chats-files.js +0 -113
- package/dist/src/daemon/chats-worker.d.ts +0 -12
- package/dist/src/daemon/chats-worker.js +0 -200
- package/dist/workflows/analyze-chats.d.ts +0 -10
- package/dist/workflows/analyze-chats.declaration.json +0 -9
- 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
|
|
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
|
-
|
|
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"]),
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
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:
|
|
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-
|
|
145
|
-
.column-name button:hover, .start-
|
|
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)
|
|
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
|
|
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:
|
|
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)
|
|
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&family=Heebo:wght@500;700;800&family=Space+Grotesk:wght@400..700&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: "
|
|
11
|
+
{ name: "Agent turn", operation: "claude-turn" },
|
|
12
12
|
{ name: "Pull request", operation: "github-open-pr" },
|
|
13
|
-
{ name: "
|
|
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: "
|
|
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>;
|