cloving 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +525 -185
- 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 +1 -0
- package/dist/src/authority/commands.js +24 -4
- 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/operations.js +1 -1
- 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 +6 -0
- package/dist/src/broker/actor/authority-delivery.js +1 -0
- package/dist/src/broker/actor/authority-queries.d.ts +7 -1
- package/dist/src/broker/actor/authority-queries.js +17 -2
- 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 +2 -1
- package/dist/src/broker/actor/delivery-intents.js +4 -4
- package/dist/src/broker/actor/effect-delivery.js +4 -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 +22 -9
- 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 +2 -1
- package/dist/src/cli/render.js +44 -28
- 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 +70 -44
- 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 +1 -1
- package/dist/src/cli/watch-board-view.js +8 -2
- package/dist/src/cli/watch-board.js +23 -10
- 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 +7 -2
- 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.js +17 -4
- package/dist/src/cli/watch-page.js +48 -12
- 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-pull-request.d.ts +3 -1
- package/dist/src/cli/watch-pull-request.js +4 -0
- package/dist/src/cli/watch-render.d.ts +9 -1
- package/dist/src/cli/watch-server.js +23 -5
- package/dist/src/cli/watch-turn.d.ts +4 -1
- package/dist/src/cli/watch-turn.js +37 -1
- package/dist/src/cli/watch-usage.js +5 -1
- package/dist/src/cli/watch-view.d.ts +6 -20
- package/dist/src/cli/watch-view.js +14 -106
- 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 +19 -5
- package/dist/src/daemon/claude-turn.js +116 -53
- package/dist/src/daemon/claude-worker.d.ts +3 -3
- package/dist/src/daemon/claude-worker.js +65 -76
- 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 +2 -33
- package/dist/src/daemon/daemon.js +126 -132
- 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 +1 -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-ci-rerun.d.ts +26 -0
- package/dist/src/daemon/github-ci-rerun.js +92 -0
- package/dist/src/daemon/github-ci.js +89 -8
- package/dist/src/daemon/github-merge-call.d.ts +2 -0
- package/dist/src/daemon/github-merge.js +7 -3
- package/dist/src/daemon/github-methods.js +10 -0
- package/dist/src/daemon/github-operation.d.ts +1 -0
- package/dist/src/daemon/github-retry.js +8 -44
- package/dist/src/daemon/issue-queue.d.ts +1 -0
- package/dist/src/daemon/issue-queue.js +3 -26
- package/dist/src/daemon/notify.js +2 -1
- 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 +2 -0
- package/dist/src/daemon/retrying-turn.js +108 -30
- 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-registration.d.ts +5 -7
- package/dist/src/daemon/ticket-registration.js +85 -40
- 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-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 +5 -0
- package/dist/src/execution-pin.js +67 -4
- 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 +1 -1
- package/dist/src/host/start-delivery.js +10 -3
- package/dist/src/host/step-bridge-host.d.ts +6 -20
- package/dist/src/host/step-bridge-host.js +44 -58
- 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/registry.d.ts +16 -3
- package/dist/src/service/registry.js +34 -3
- package/dist/src/service/replies.d.ts +9 -1
- package/dist/src/service/replies.js +12 -0
- package/dist/src/service/run-handlers.js +14 -55
- 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 +18 -2
- package/dist/src/service/service.js +23 -7
- package/dist/src/service/submission-handler.d.ts +0 -1
- package/dist/src/service/submission-handler.js +6 -34
- package/dist/src/service/worker-port.d.ts +1 -0
- package/dist/src/service/worker-totals.js +8 -23
- package/dist/src/step-bridge.d.ts +23 -0
- package/dist/src/steps/decision-gate.d.ts +2 -1
- package/dist/src/steps/decision-gate.js +7 -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-status-stream.d.ts +9 -0
- package/dist/src/ticket-status-stream.js +94 -0
- package/dist/src/token-prices.d.ts +12 -4
- package/dist/src/token-prices.js +15 -2
- package/dist/src/turn-profile.d.ts +1 -0
- package/dist/src/turn-profile.js +8 -1
- package/dist/src/worker-usage.d.ts +16 -0
- package/dist/src/worker-usage.js +57 -0
- package/dist/src/workflow-admission.d.ts +5 -0
- package/dist/src/workflow-candidate.d.ts +7 -2
- package/dist/src/workflow-candidate.js +47 -5
- package/dist/src/workflow-declaration.d.ts +21 -3
- package/dist/src/workflow-declaration.js +77 -9
- package/dist/src/workflow-discovery.d.ts +2 -1
- package/dist/src/workflow-discovery.js +4 -1
- package/dist/src/workflow-refusals.js +3 -0
- package/dist/src/workflow-schedule.d.ts +22 -0
- package/dist/src/workflow-schedule.js +53 -0
- package/dist/src/workflows.d.ts +11 -1
- package/dist/src/workflows.js +8 -0
- package/dist/tools/admit-workflow.d.ts +1 -0
- package/dist/tools/admit-workflow.js +18 -5
- 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 +4 -0
- package/dist/tools/self-host-project.js +61 -14
- 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 +86 -61
- package/dist/tools/workflow-candidate-counts.d.ts +6 -2
- package/dist/tools/workflow-candidate-counts.js +31 -16
- 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 +2 -0
- package/dist/tools/workflow-candidate-program.js +36 -8
- package/dist/tools/workflow-candidate-source.js +77 -15
- package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
- package/dist/tools/workflow-candidate-syntax.js +70 -26
- 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 +1 -0
- package/dist/tools/workflow-folder-capture.js +47 -2
- package/dist/tools/workflow-folders.d.ts +17 -1
- package/dist/tools/workflow-folders.js +59 -6
- 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-ticket.js +1 -1
- package/dist/workflows/ticket-prompts.js +5 -1
- package/package.json +46 -4
- 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 -42
- package/dist/src/chats/analysis-batches.js +0 -97
- package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
- package/dist/src/chats/analysis-checkpoint.js +0 -31
- 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 -18
- package/dist/src/chats/analysis-input.js +0 -97
- package/dist/src/chats/analysis-links.d.ts +0 -2
- package/dist/src/chats/analysis-links.js +0 -25
- package/dist/src/chats/analysis-merge.d.ts +0 -16
- package/dist/src/chats/analysis-merge.js +0 -134
- package/dist/src/chats/analysis-prompt.d.ts +0 -18
- package/dist/src/chats/analysis-prompt.js +0 -42
- package/dist/src/chats/analysis-proposal.d.ts +0 -4
- package/dist/src/chats/analysis-proposal.js +0 -41
- 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 -4
- package/dist/src/chats/analysis-shape.js +0 -235
- 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/reference-mapping.d.ts +0 -16
- package/dist/src/chats/reference-mapping.js +0 -153
- 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/chats/workflow-generation-projection.d.ts +0 -8
- package/dist/src/chats/workflow-generation-projection.js +0 -75
- package/dist/src/chats/workflow-generation-source.d.ts +0 -25
- package/dist/src/chats/workflow-generation-source.js +0 -124
- package/dist/src/chats/workflow-generation-text.d.ts +0 -23
- package/dist/src/chats/workflow-generation-text.js +0 -74
- package/dist/src/chats/workflow-generation.d.ts +0 -69
- package/dist/src/chats/workflow-generation.js +0 -142
- 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 -20
- package/dist/src/daemon/analysis-worker.js +0 -271
- package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
- package/dist/src/daemon/chats-batch-binding.js +0 -99
- package/dist/src/daemon/chats-capture.d.ts +0 -18
- package/dist/src/daemon/chats-capture.js +0 -194
- package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
- package/dist/src/daemon/chats-checkpoints.js +0 -186
- package/dist/src/daemon/chats-files.d.ts +0 -42
- package/dist/src/daemon/chats-files.js +0 -252
- package/dist/src/daemon/chats-follow-up.d.ts +0 -38
- package/dist/src/daemon/chats-follow-up.js +0 -180
- package/dist/src/daemon/chats-question.d.ts +0 -15
- package/dist/src/daemon/chats-question.js +0 -93
- package/dist/src/daemon/chats-worker.d.ts +0 -13
- package/dist/src/daemon/chats-worker.js +0 -201
- package/dist/workflows/analyze-chats.d.ts +0 -15
- package/dist/workflows/analyze-chats.declaration.json +0 -22
- package/dist/workflows/analyze-chats.js +0 -250
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { record } from "../protocol.js";
|
|
2
|
+
import { PhonePanel } from "./watch-phone-view.js";
|
|
3
|
+
import { component, element } from "./watch-element.js";
|
|
4
|
+
import { clockTime, counted } from "./watch-render.js";
|
|
5
|
+
export const clove = {
|
|
6
|
+
viewBox: "0.6625858545303345 0.6630800366401672 46.674827575683594 46.673831939697266",
|
|
7
|
+
paths: [
|
|
8
|
+
"M41.47315,11.48535c-1.20117-0.12305-2.16211-1.08398-2.28418-2.28516c-0.17676-1.7334-1.01758-3.29492-2.36865-4.39648s-3.05078-1.61719-4.7832-1.43359c-3.34277,0.34082-5.86377,3.13086-5.86377,6.49121v14.13867c0,0.27637,0.22363,0.5,0.5,0.5H40.8125c3.59766,0,6.52441-2.92676,6.52441-6.52441C47.33692,14.61523,44.81592,11.82422,41.47315,11.48535z M35.56543,15.81543l-5.85791,5.85742c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648c-0.19531-0.19531-0.19531-0.51172,0-0.70703l5.85791-5.85742c0.19531-0.19531,0.51172-0.19531,0.70703,0C35.76073,15.30372,35.76074,15.62011,35.56543,15.81543z",
|
|
9
|
+
"M15.30225,0.66308c-3.36035,0-6.15088,2.52051-6.49121,5.86328C8.68897,7.72852,7.72852,8.68945,6.52686,8.81152c-1.7334,0.17578-3.29492,1.01758-4.396,2.36816s-1.61035,3.0498-1.43408,4.7832c0.34033,3.34277,3.13086,5.86328,6.49121,5.86328h14.13867c0.27637,0,0.5-0.22363,0.5-0.5V7.18751C21.82666,3.58984,18.8999,0.66308,15.30225,0.66308z M18.99951,19.00001c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648l-5.85742-5.8584c-0.19531-0.19531-0.19531-0.51172,0-0.70703c0.19531-0.19531,0.51172-0.19531,0.70703,0l5.85742,5.8584C19.19482,18.48829,19.19482,18.80469,18.99951,19.00001z",
|
|
10
|
+
"M24,26.17383H9.86133c-3.59766,0-6.52441,2.92676-6.52441,6.52441c0,3.35938,2.52051,6.14941,5.86377,6.49023c1.20117,0.12207,2.16211,1.08301,2.28418,2.28418c0.17676,1.7334,1.01758,3.29492,2.36865,4.39648c1.17529,0.95801,2.61377,1.46777,4.11035,1.46777c0.22314,0,0.44775-0.01074,0.67285-0.03418C21.97949,46.96189,24.5,44.17186,24.5,40.81248V26.67383C24.5,26.39746,24.27637,26.17383,24,26.17383z M21.67334,29.70704l-5.85791,5.8584c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648c-0.19531-0.19531-0.19531-0.51172,0-0.70703L20.9663,29c0.19531-0.19531,0.51172-0.19531,0.70703,0S21.86865,29.51172,21.67334,29.70704z",
|
|
11
|
+
"M47.30322,32.03711c-0.34033-3.34277-3.13086-5.86328-6.49072-5.86328H26.67334c-0.27637,0-0.5,0.22363-0.5,0.5V40.8125c0,3.59766,2.92676,6.52441,6.52442,6.52441c3.36035,0,6.15088-2.52148,6.49121-5.86426c0.12207-1.20117,1.08301-2.16211,2.28418-2.28418c1.7334-0.17578,3.29492-1.01758,4.396-2.36816S47.47949,33.7705,47.30322,32.03711z M35.56543,35.56543c-0.09766,0.09766-0.22559,0.14648-0.35352,0.14648s-0.25586-0.04883-0.35352-0.14648l-5.85791-5.8584c-0.19531-0.19531-0.19531-0.51172,0-0.70703s0.51172-0.19531,0.70703,0l5.85791,5.8584C35.76074,35.05371,35.76074,35.37011,35.56543,35.56543z",
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
export function queueLanes(model) {
|
|
15
|
+
const queue = model.queue;
|
|
16
|
+
if (queue === undefined)
|
|
17
|
+
return null;
|
|
18
|
+
return `Queue: ${String(queue["busy"])} of ${String(queue["lanes"])} lanes busy`;
|
|
19
|
+
}
|
|
20
|
+
export function skippedText(value) {
|
|
21
|
+
const ticket = record(value) ?? {};
|
|
22
|
+
const name = `#${String(ticket["ticketId"])}`;
|
|
23
|
+
const dependencies = ticket["dependencies"];
|
|
24
|
+
if (ticket["reason"] === "ticket-dependency-open" &&
|
|
25
|
+
Array.isArray(dependencies))
|
|
26
|
+
return `${name} waits for ${dependencies.map((item) => `#${String(item)}`).join(", ")}`;
|
|
27
|
+
if (ticket["reason"] === "ticket-active")
|
|
28
|
+
return `${name} is in work`;
|
|
29
|
+
return `${name}: ${String(ticket["reason"])}`;
|
|
30
|
+
}
|
|
31
|
+
export function Queue(props) {
|
|
32
|
+
const skipped = props.model.queue?.["skipped"];
|
|
33
|
+
if (!Array.isArray(skipped) || skipped.length === 0)
|
|
34
|
+
return null;
|
|
35
|
+
return element("details", {
|
|
36
|
+
class: "queue-waiting",
|
|
37
|
+
children: [
|
|
38
|
+
element("summary", {
|
|
39
|
+
children: `${counted(skipped.length, "ticket")} skipped`,
|
|
40
|
+
}),
|
|
41
|
+
element("ul", {
|
|
42
|
+
children: skipped.map((value) => element("li", { children: skippedText(value) })),
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function Brand() {
|
|
48
|
+
return element("strong", {
|
|
49
|
+
class: "brand",
|
|
50
|
+
children: [
|
|
51
|
+
element("svg", {
|
|
52
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
53
|
+
"aria-hidden": "true",
|
|
54
|
+
focusable: "false",
|
|
55
|
+
viewBox: clove.viewBox,
|
|
56
|
+
children: clove.paths.map((d) => element("path", { fill: "currentColor", d })),
|
|
57
|
+
}),
|
|
58
|
+
"cloving",
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export function HeaderStatus(props) {
|
|
63
|
+
const { model, stale } = props;
|
|
64
|
+
const updated = model === null ? "" : `updated ${clockTime(model.updatedAt)}`;
|
|
65
|
+
const stamp = stale
|
|
66
|
+
? element("span", {
|
|
67
|
+
class: "bad",
|
|
68
|
+
children: "The watch tool does not answer.",
|
|
69
|
+
})
|
|
70
|
+
: element("span", { children: updated });
|
|
71
|
+
const lanes = model === null ? null : queueLanes(model);
|
|
72
|
+
return element("div", {
|
|
73
|
+
class: "header-status",
|
|
74
|
+
children: [
|
|
75
|
+
stamp,
|
|
76
|
+
lanes === null
|
|
77
|
+
? null
|
|
78
|
+
: element("span", { class: "queue-lanes", children: lanes }),
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function HeaderActions(props) {
|
|
83
|
+
const { start, phone } = props;
|
|
84
|
+
if (start === undefined && phone === undefined)
|
|
85
|
+
return null;
|
|
86
|
+
return element("div", {
|
|
87
|
+
class: "header-actions",
|
|
88
|
+
children: [
|
|
89
|
+
start === undefined
|
|
90
|
+
? null
|
|
91
|
+
: element("button", {
|
|
92
|
+
type: "button",
|
|
93
|
+
class: "start-toggle",
|
|
94
|
+
"aria-controls": "start-run",
|
|
95
|
+
"aria-expanded": String(start.shown),
|
|
96
|
+
onClick: start.onToggle,
|
|
97
|
+
children: "Start a run",
|
|
98
|
+
}),
|
|
99
|
+
phone === undefined
|
|
100
|
+
? null
|
|
101
|
+
: component(PhonePanel, {
|
|
102
|
+
phone,
|
|
103
|
+
now: props.now ?? props.model?.updatedAt ?? "",
|
|
104
|
+
}),
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export function Header(props) {
|
|
109
|
+
return element("header", {
|
|
110
|
+
children: [
|
|
111
|
+
component(Brand, {}),
|
|
112
|
+
component(HeaderStatus, props),
|
|
113
|
+
component(HeaderActions, props),
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
}
|
|
@@ -3,13 +3,14 @@ import { workflowRefusals, } from "../workflow-refusals.js";
|
|
|
3
3
|
import { isTicketStatus } from "../ticket-status.js";
|
|
4
4
|
import { isPromotionId } from "../workflow-contracts.js";
|
|
5
5
|
import { priceFields, statusTurns } from "./watch-usage.js";
|
|
6
|
-
import { priceOf, usageOf } from "../worker-usage.js";
|
|
6
|
+
import { priceOf, usageOf, attemptFields } from "../worker-usage.js";
|
|
7
7
|
import { priceText } from "./usage-render.js";
|
|
8
8
|
import { boardsOf, currentStepOf, roundOf, stagesFor, startWorkflowOf, } from "./watch-board.js";
|
|
9
9
|
import { decisionOf, phasesOf } from "./watch-phases.js";
|
|
10
10
|
import { pullOf } from "./watch-pull-request.js";
|
|
11
11
|
import { establishedIssue } from "./watch-pr-identity.js";
|
|
12
12
|
import { displayRun } from "./watch-paths.js";
|
|
13
|
+
import { shownCommands } from "./command-effects.js";
|
|
13
14
|
const textLimit = 600;
|
|
14
15
|
const activityLimit = 400;
|
|
15
16
|
function record(value) {
|
|
@@ -119,7 +120,10 @@ export function turnOf(records) {
|
|
|
119
120
|
const result = record(records.result);
|
|
120
121
|
const outcome = text(result["outcome"]);
|
|
121
122
|
const report = record(parsed(text(result["result"])));
|
|
123
|
+
const harness = text(started["harness"]) || text(report["harness"]);
|
|
122
124
|
return {
|
|
125
|
+
...attemptFields(report["attempts"]),
|
|
126
|
+
...(harness === "" ? {} : { harness }),
|
|
123
127
|
key: records.key,
|
|
124
128
|
operationId: text(started["operationId"]),
|
|
125
129
|
usage: usageOf(report["usage"]),
|
|
@@ -186,6 +190,14 @@ function outcomeOf(value) {
|
|
|
186
190
|
...(issueUpdate === "failed" ? { issueUpdate } : {}),
|
|
187
191
|
};
|
|
188
192
|
}
|
|
193
|
+
function runLinksOf(status) {
|
|
194
|
+
return {
|
|
195
|
+
parentRunId: stamp(status["parentRunId"]),
|
|
196
|
+
chainId: stamp(status["chainId"]) ?? text(status["runId"]),
|
|
197
|
+
childRunIds: texts(status["childRunIds"]),
|
|
198
|
+
awaitedRunId: stamp(status["awaitedRunId"]),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
189
201
|
function runOf(inputs, value) {
|
|
190
202
|
const status = record(record(value)["status"]);
|
|
191
203
|
const runId = text(status["runId"]);
|
|
@@ -198,9 +210,7 @@ function runOf(inputs, value) {
|
|
|
198
210
|
return {
|
|
199
211
|
runId,
|
|
200
212
|
workflowId,
|
|
201
|
-
|
|
202
|
-
chainId: stamp(status["chainId"]) ?? runId,
|
|
203
|
-
childRunIds: texts(status["childRunIds"]),
|
|
213
|
+
...runLinksOf(status),
|
|
204
214
|
ticketId: ticketId === "" ? null : ticketId,
|
|
205
215
|
...(issue === null ? {} : { issueIdentity: issue }),
|
|
206
216
|
title: stamp(status["title"]),
|
|
@@ -224,6 +234,9 @@ function runOf(inputs, value) {
|
|
|
224
234
|
.map((decision) => decisionCommands(operationalDecision(record(decision), workflowId), inputs.client)),
|
|
225
235
|
events: list(record(value)["events"]).map(eventOf),
|
|
226
236
|
turns: statusTurns(inputs.turns, status),
|
|
237
|
+
...(status["commandEffects"] === undefined
|
|
238
|
+
? {}
|
|
239
|
+
: { commandEffects: shownCommands(status["commandEffects"]) }),
|
|
227
240
|
phases: phasesOf(list(record(value)["events"]), workflowId),
|
|
228
241
|
decision: decisionOf(list(record(value)["events"])),
|
|
229
242
|
feedback: list(status["feedback"]).map(feedbackOf),
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { cardReply } from "./watch-card-reply.js";
|
|
2
2
|
import { record } from "../protocol.js";
|
|
3
|
+
import { Commands, commandText } from "./command-effects.js";
|
|
3
4
|
import { watchCardClient } from "./watch-card-client.js";
|
|
4
5
|
import { AddCard, CardInput, cardKey, cardSubmitKey, } from "./watch-card-view.js";
|
|
5
6
|
import { watchClient } from "./watch-client.js";
|
|
7
|
+
import { watchPhoneClient } from "./watch-phone-client.js";
|
|
8
|
+
import { PhoneAsk, PhoneCode, PhoneList, PhonePanel, phoneButton, phoneNotices, refusalText, timeLeft, } from "./watch-phone-view.js";
|
|
6
9
|
import { priceOf, tokenCount, usageOf } from "../worker-usage.js";
|
|
7
|
-
import { priceText, usageText, totalsSuffix } from "./usage-render.js";
|
|
10
|
+
import { priceText, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
|
|
8
11
|
import { startPrompts, StartCard, StartRun } from "./watch-start-view.js";
|
|
9
12
|
import { Board, boardSizing, Card, HandoffLinks, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, observationText, staleObservation, } from "./watch-board-view.js";
|
|
10
13
|
import { boardWorkflow, watchHash, watchLocation, watchTitle, } from "./watch-navigation.js";
|
|
11
14
|
import { clockTime, completedDetail, counted, elapsed, groupActivity, pageTitle, phaseTime, runName, runTone, selectedRun, toneOf, turnTime, waitingDetail, } from "./watch-render.js";
|
|
12
15
|
import { Command, Decision, Events, Group, Item, Turn, Work, } from "./watch-turn.js";
|
|
13
|
-
import {
|
|
16
|
+
import { Banner, BannerDetail, BoardPage, Page, Phases, PullRequest, Review, RefusedWorkflows, Run, } from "./watch-view.js";
|
|
17
|
+
import { Brand, clove, Header, HeaderActions, HeaderStatus, Queue, queueLanes, skippedText, } from "./watch-header-view.js";
|
|
14
18
|
const functions = [
|
|
15
19
|
record,
|
|
20
|
+
commandText,
|
|
21
|
+
Commands,
|
|
22
|
+
queueLanes,
|
|
23
|
+
skippedText,
|
|
16
24
|
Queue,
|
|
25
|
+
Brand,
|
|
26
|
+
HeaderStatus,
|
|
27
|
+
HeaderActions,
|
|
17
28
|
cardReply,
|
|
18
29
|
cardSubmitKey,
|
|
19
30
|
cardKey,
|
|
@@ -24,6 +35,7 @@ const functions = [
|
|
|
24
35
|
usageOf,
|
|
25
36
|
priceText,
|
|
26
37
|
usageText,
|
|
38
|
+
attemptText,
|
|
27
39
|
totalsSuffix,
|
|
28
40
|
watchHash,
|
|
29
41
|
watchLocation,
|
|
@@ -70,6 +82,14 @@ const functions = [
|
|
|
70
82
|
PullRequest,
|
|
71
83
|
Review,
|
|
72
84
|
Run,
|
|
85
|
+
timeLeft,
|
|
86
|
+
refusalText,
|
|
87
|
+
phoneButton,
|
|
88
|
+
phoneNotices,
|
|
89
|
+
PhoneCode,
|
|
90
|
+
PhoneAsk,
|
|
91
|
+
PhoneList,
|
|
92
|
+
PhonePanel,
|
|
73
93
|
Header,
|
|
74
94
|
RefusedWorkflows,
|
|
75
95
|
BoardPage,
|
|
@@ -130,7 +150,20 @@ body:has(.board-page) { padding-bottom: 0; overflow: hidden; }
|
|
|
130
150
|
.workflow-refusals { flex-shrink: 0; max-height: 25dvh; overflow-y: auto; overflow-wrap: anywhere; }
|
|
131
151
|
.workflow-refusals h2 { margin: 8px 0; }
|
|
132
152
|
a { color: var(--accent-strong); }
|
|
133
|
-
|
|
153
|
+
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
154
|
+
.header-status { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
|
|
155
|
+
.queue-lanes { padding: 2px 8px; border-radius: 999px; background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); font-variant-numeric: tabular-nums; }
|
|
156
|
+
.header-actions { margin-left: auto; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
|
|
157
|
+
.queue-waiting { flex-shrink: 0; margin: 0 0 4px; color: var(--muted); font-size: 12px; }
|
|
158
|
+
.queue-waiting ul { margin: 6px 0 0; padding: 0 0 0 18px; columns: 220px; column-gap: 24px; max-height: 25dvh; overflow-y: auto; }
|
|
159
|
+
.phone { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin: 0; }
|
|
160
|
+
.phone-pairing { flex-basis: 100%; }
|
|
161
|
+
.phone-pairing div { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
|
|
162
|
+
.phone-qr { width: 196px; height: 196px; border-radius: 8px; }
|
|
163
|
+
.phone-ask { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
164
|
+
.phone-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
165
|
+
.phone-list li { display: flex; gap: 8px; align-items: center; color: var(--ink); }
|
|
166
|
+
header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; padding: 18px 0 12px; color: var(--muted); font-size: 12px; }
|
|
134
167
|
.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--ink); font: 800 26px/1.2 var(--heading-font); }
|
|
135
168
|
.brand svg { width: 30px; height: 30px; color: var(--accent); }
|
|
136
169
|
a:focus-visible, button:focus-visible, summary:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 6px var(--code-bg); }
|
|
@@ -147,43 +180,45 @@ h2, h3 { font-family: var(--heading-font); font-weight: 700; }
|
|
|
147
180
|
.workflows a[aria-current="page"] { border-bottom-color: var(--accent); background: var(--surface); border-radius: 8px 8px 0 0; }
|
|
148
181
|
.workflows span, .card small { color: var(--muted); font-size: 12px; }
|
|
149
182
|
.board { width: 100%; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
|
|
150
|
-
.board h2 { margin: 0 0 8px; font-size: 24px; flex-shrink: 0; }
|
|
151
183
|
.columns { display: flex; align-items: flex-start; gap: ${String(boardSizing.gap)}px; flex: 1; min-height: 0; overflow-x: scroll; overflow-y: hidden; padding: 6px 6px 12px; scrollbar-color: var(--muted) var(--surface-2); }
|
|
152
184
|
@supports selector(::-webkit-scrollbar) { .columns { scrollbar-color: auto; } }
|
|
153
185
|
.columns::-webkit-scrollbar { height: 12px; }
|
|
154
186
|
.columns::-webkit-scrollbar-track { background: var(--surface-2); }
|
|
155
187
|
.columns::-webkit-scrollbar-thumb { background: var(--muted); border-radius: 6px; }
|
|
156
188
|
.column { flex: 1 0 ${String(boardSizing.minimumColumnWidth)}px; min-width: ${String(boardSizing.minimumColumnWidth)}px; max-height: 100%; display: flex; flex-direction: column; overflow: hidden; padding: 10px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line); background: var(--surface-2); }
|
|
157
|
-
.column-name { display: flex; align-items: center; gap: 6px; flex-shrink: 0; margin: 0; padding: 4px 0 10px; color: var(--muted); font:
|
|
189
|
+
.column-name { display: flex; align-items: center; gap: 6px; flex-shrink: 0; margin: 0; padding: 4px 0 10px; color: var(--muted); font: 600 13px/1.5 var(--body-font); }
|
|
190
|
+
.column-count { font-variant-numeric: tabular-nums; }
|
|
158
191
|
.column-name > span:first-child { flex: 1; }
|
|
159
192
|
.column-cards { min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
|
|
160
193
|
.column.collapsed { flex: 0 0 ${String(boardSizing.collapsedColumnWidth)}px; min-width: ${String(boardSizing.collapsedColumnWidth)}px; padding: 6px; }
|
|
161
194
|
.collapsed .column-name { writing-mode: vertical-rl; padding: 0; }
|
|
162
|
-
.column-name button, .start-
|
|
163
|
-
.
|
|
195
|
+
header button, .phone button, .column-name button, .add-card, .add-card-form button, .start-card button { font: 500 13px/1.4 var(--body-font); color: var(--ink); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
|
|
196
|
+
header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover, .start-card button:hover { background: var(--surface-2); }
|
|
164
197
|
.add-card, .add-card-form button { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 4px 8px 4px 0; }
|
|
165
|
-
.add-card { width: 100%; text-align: left; }
|
|
198
|
+
.add-card { width: 100%; text-align: left; margin: 4px 0; }
|
|
166
199
|
.add-card-form { padding: 8px 0; overflow-wrap: anywhere; }
|
|
167
200
|
.add-card-form label { display: block; color: var(--ink); margin-bottom: 8px; }
|
|
168
201
|
.add-card-form input, .add-card-form textarea { display: block; width: 100%; min-width: 0; box-sizing: border-box; padding: 8px; border: 1px solid var(--line); border-radius: 6px; font: inherit; color: var(--ink); background: var(--surface); }
|
|
169
202
|
.add-card-form textarea { resize: vertical; }
|
|
170
203
|
.add-card-form button:disabled { opacity: 0.6; cursor: default; }
|
|
171
204
|
.add-card-form p { font-size: 12px; margin: 8px 0; }
|
|
172
|
-
.card { display: grid; gap: 6px; margin-bottom: 10px; padding: 12px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line)
|
|
205
|
+
.card { display: grid; gap: 6px; margin-bottom: 10px; padding: 12px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--line); color: var(--ink); overflow-wrap: anywhere; background: var(--surface); }
|
|
173
206
|
.card:hover { outline: 1px solid var(--accent-strong); }
|
|
174
207
|
.card-run { display: grid; gap: 4px; min-width: 0; color: inherit; text-decoration: none; }
|
|
175
208
|
.card-run strong { font-family: var(--heading-font); font-weight: 700; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
|
|
176
209
|
.completion-mark { font-size: 12px; }
|
|
177
|
-
.card-step, .card-review, .card-cost
|
|
210
|
+
.card-step, .card-review, .card-cost { font: 400 12px/1.6 var(--body-font); font-variant-numeric: tabular-nums; }
|
|
211
|
+
.card small { font: 400 11px/1.6 var(--code-font); }
|
|
178
212
|
.card-step, .card-review { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
179
213
|
.card-step { color: var(--muted); }
|
|
180
214
|
.card-step.active { color: var(--accent-strong); }
|
|
181
215
|
.card-review { color: var(--muted); }
|
|
182
216
|
.review-pill { display: inline-block; padding: 1px 5px; border-radius: 5px; box-shadow: inset 0 0 0 1px var(--line); }
|
|
183
|
-
.decision-mark { width: fit-content; padding: 3px 7px; border-radius: 6px; background: linear-gradient(var(--warn-tint), var(--warn-tint)), var(--surface); color: var(--warn); font:
|
|
217
|
+
.decision-mark { width: fit-content; padding: 3px 7px; border-radius: 6px; background: linear-gradient(var(--warn-tint), var(--warn-tint)), var(--surface); color: var(--warn); font: 600 12px/1.6 var(--body-font); }
|
|
184
218
|
.column.stopped { background: var(--surface); box-shadow: inset 0 0 0 1px var(--bad), inset 0 0 0 100vmax var(--bad-tint); }
|
|
219
|
+
.column.stopped.collapsed { background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); }
|
|
185
220
|
.stopped .column-name { color: var(--bad); background: var(--surface); border-radius: 6px; }
|
|
186
|
-
.stopped .card { background: linear-gradient(var(--bad-tint), var(--bad-tint)), var(--surface); box-shadow: inset 0 0 0 1px var(--bad)
|
|
221
|
+
.stopped .card { background: linear-gradient(var(--bad-tint), var(--bad-tint)), var(--surface); box-shadow: inset 0 0 0 1px var(--bad); }
|
|
187
222
|
.back { display: block; width: fit-content; margin: 16px 0; }
|
|
188
223
|
.icon { font-weight: 700; color: var(--muted); }
|
|
189
224
|
.good .icon, .phase.done .mark, p.good { color: var(--accent-strong); }
|
|
@@ -261,6 +296,7 @@ export function pageDocument(actionToken = null) {
|
|
|
261
296
|
`const actionToken = ${JSON.stringify(actionToken)};`,
|
|
262
297
|
...functions.map((item) => item.toString()),
|
|
263
298
|
watchCardClient,
|
|
299
|
+
watchPhoneClient,
|
|
264
300
|
watchClient,
|
|
265
301
|
].join("\n");
|
|
266
302
|
return [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const watchPhoneClient = "\nasync function phoneLoad() {\n const sent = Date.now();\n const sequence = ++state.phoneSequence;\n try {\n const reply = await fetch(\"phone.json\", { cache: \"no-store\" });\n const phone = reply.ok ? await reply.json() : null;\n if (phone !== null && sequence > state.phoneApplied) {\n state.phoneApplied = sequence;\n state.phone = phone;\n state.phoneLoadedAt = sent;\n }\n } catch {}\n draw();\n}\nasync function phonePost(action, body = {}) {\n state.phoneBusy = true;\n state.phoneMessage = \"\";\n draw();\n let reply;\n try {\n const response = await fetch(\"actions/phone/\" + action, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-cloving-token\": actionToken },\n body: JSON.stringify(body),\n });\n reply = response.ok ? await response.json() : { error: { detail: \"The watch page refused the request. Refresh the page.\" } };\n } catch {\n reply = { error: { detail: \"The watch tool does not answer.\" } };\n }\n state.phoneBusy = false;\n state.phoneMessage = reply.error?.detail ?? reply.warning ?? \"\";\n return reply;\n}\nfunction phoneSession(now) {\n const pairing = state.phonePairing;\n const live = state.phone?.pairing ?? null;\n const ended = live === null && state.phoneLoadedAt > (pairing?.at ?? 0);\n if (pairing !== null && (ended || Date.parse(pairing.expiresAt) <= Date.parse(now))) state.phonePairing = null;\n const accepted = state.phoneAccepted;\n const device = (state.phone?.devices ?? []).find((item) => item.deviceId === accepted?.deviceId);\n const shown = device?.state === \"connected\" && device.removedAt === null;\n return { live, connected: shown ? device.name : null };\n}\nfunction phoneControls(now) {\n if (actionToken === null) return undefined;\n const { live, connected } = phoneSession(now);\n return {\n pairing: state.phonePairing,\n request: live?.request ?? null,\n stage: live?.stage ?? null,\n connected,\n refusal: state.phone?.refusal ?? null,\n reason: state.phone?.reason ?? null,\n devices: state.phone?.devices ?? [],\n busy: state.phoneBusy,\n message: state.phoneMessage,\n async onPair() {\n state.phoneAccepted = null;\n const reply = await phonePost(\"pair\");\n if (!reply.error) state.phonePairing = { ...reply, at: Date.now() };\n await phoneLoad();\n },\n async onCancel() {\n state.phonePairing = null;\n await phonePost(\"cancel\");\n await phoneLoad();\n },\n async onAccept() {\n state.phoneAccepted = live?.request ?? null;\n await phonePost(\"accept\", { pairingId: live?.pairingId });\n await phoneLoad();\n },\n async onDeny() {\n await phonePost(\"deny\", { pairingId: live?.pairingId });\n await phoneLoad();\n },\n async onRemove(deviceId) {\n await phonePost(\"remove\", { deviceId });\n await phoneLoad();\n },\n };\n}\n";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export const watchPhoneClient = `
|
|
2
|
+
async function phoneLoad() {
|
|
3
|
+
const sent = Date.now();
|
|
4
|
+
const sequence = ++state.phoneSequence;
|
|
5
|
+
try {
|
|
6
|
+
const reply = await fetch("phone.json", { cache: "no-store" });
|
|
7
|
+
const phone = reply.ok ? await reply.json() : null;
|
|
8
|
+
if (phone !== null && sequence > state.phoneApplied) {
|
|
9
|
+
state.phoneApplied = sequence;
|
|
10
|
+
state.phone = phone;
|
|
11
|
+
state.phoneLoadedAt = sent;
|
|
12
|
+
}
|
|
13
|
+
} catch {}
|
|
14
|
+
draw();
|
|
15
|
+
}
|
|
16
|
+
async function phonePost(action, body = {}) {
|
|
17
|
+
state.phoneBusy = true;
|
|
18
|
+
state.phoneMessage = "";
|
|
19
|
+
draw();
|
|
20
|
+
let reply;
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch("actions/phone/" + action, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "content-type": "application/json", "x-cloving-token": actionToken },
|
|
25
|
+
body: JSON.stringify(body),
|
|
26
|
+
});
|
|
27
|
+
reply = response.ok ? await response.json() : { error: { detail: "The watch page refused the request. Refresh the page." } };
|
|
28
|
+
} catch {
|
|
29
|
+
reply = { error: { detail: "The watch tool does not answer." } };
|
|
30
|
+
}
|
|
31
|
+
state.phoneBusy = false;
|
|
32
|
+
state.phoneMessage = reply.error?.detail ?? reply.warning ?? "";
|
|
33
|
+
return reply;
|
|
34
|
+
}
|
|
35
|
+
function phoneSession(now) {
|
|
36
|
+
const pairing = state.phonePairing;
|
|
37
|
+
const live = state.phone?.pairing ?? null;
|
|
38
|
+
const ended = live === null && state.phoneLoadedAt > (pairing?.at ?? 0);
|
|
39
|
+
if (pairing !== null && (ended || Date.parse(pairing.expiresAt) <= Date.parse(now))) state.phonePairing = null;
|
|
40
|
+
const accepted = state.phoneAccepted;
|
|
41
|
+
const device = (state.phone?.devices ?? []).find((item) => item.deviceId === accepted?.deviceId);
|
|
42
|
+
const shown = device?.state === "connected" && device.removedAt === null;
|
|
43
|
+
return { live, connected: shown ? device.name : null };
|
|
44
|
+
}
|
|
45
|
+
function phoneControls(now) {
|
|
46
|
+
if (actionToken === null) return undefined;
|
|
47
|
+
const { live, connected } = phoneSession(now);
|
|
48
|
+
return {
|
|
49
|
+
pairing: state.phonePairing,
|
|
50
|
+
request: live?.request ?? null,
|
|
51
|
+
stage: live?.stage ?? null,
|
|
52
|
+
connected,
|
|
53
|
+
refusal: state.phone?.refusal ?? null,
|
|
54
|
+
reason: state.phone?.reason ?? null,
|
|
55
|
+
devices: state.phone?.devices ?? [],
|
|
56
|
+
busy: state.phoneBusy,
|
|
57
|
+
message: state.phoneMessage,
|
|
58
|
+
async onPair() {
|
|
59
|
+
state.phoneAccepted = null;
|
|
60
|
+
const reply = await phonePost("pair");
|
|
61
|
+
if (!reply.error) state.phonePairing = { ...reply, at: Date.now() };
|
|
62
|
+
await phoneLoad();
|
|
63
|
+
},
|
|
64
|
+
async onCancel() {
|
|
65
|
+
state.phonePairing = null;
|
|
66
|
+
await phonePost("cancel");
|
|
67
|
+
await phoneLoad();
|
|
68
|
+
},
|
|
69
|
+
async onAccept() {
|
|
70
|
+
state.phoneAccepted = live?.request ?? null;
|
|
71
|
+
await phonePost("accept", { pairingId: live?.pairingId });
|
|
72
|
+
await phoneLoad();
|
|
73
|
+
},
|
|
74
|
+
async onDeny() {
|
|
75
|
+
await phonePost("deny", { pairingId: live?.pairingId });
|
|
76
|
+
await phoneLoad();
|
|
77
|
+
},
|
|
78
|
+
async onRemove(deviceId) {
|
|
79
|
+
await phonePost("remove", { deviceId });
|
|
80
|
+
await phoneLoad();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Shown } from "./watch-element.ts";
|
|
2
|
+
export interface PhonePicture {
|
|
3
|
+
readonly size: number;
|
|
4
|
+
readonly path: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PhonePairing {
|
|
7
|
+
readonly link: string;
|
|
8
|
+
readonly expiresAt: string;
|
|
9
|
+
readonly picture: PhonePicture;
|
|
10
|
+
}
|
|
11
|
+
export interface PhoneRequest {
|
|
12
|
+
readonly deviceId: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly platform: string;
|
|
15
|
+
readonly code: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PhoneDevice {
|
|
18
|
+
readonly deviceId: string;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly platform: string;
|
|
21
|
+
readonly state: string;
|
|
22
|
+
readonly removedAt: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface PhoneControls {
|
|
25
|
+
readonly pairing: PhonePairing | null;
|
|
26
|
+
readonly request: PhoneRequest | null;
|
|
27
|
+
readonly stage: string | null;
|
|
28
|
+
readonly connected: string | null;
|
|
29
|
+
readonly refusal: string | null;
|
|
30
|
+
readonly reason: string | null;
|
|
31
|
+
readonly devices: readonly PhoneDevice[];
|
|
32
|
+
readonly busy: boolean;
|
|
33
|
+
readonly message: string;
|
|
34
|
+
readonly onPair: () => void;
|
|
35
|
+
readonly onCancel: () => void;
|
|
36
|
+
readonly onAccept: () => void;
|
|
37
|
+
readonly onDeny: () => void;
|
|
38
|
+
readonly onRemove: (deviceId: string) => void;
|
|
39
|
+
}
|
|
40
|
+
export declare function timeLeft(expiresAt: string, now: string): string;
|
|
41
|
+
export declare function refusalText(code: string): string;
|
|
42
|
+
export declare function PhoneCode(props: {
|
|
43
|
+
readonly picture: PhonePicture;
|
|
44
|
+
}): Shown;
|
|
45
|
+
export declare function phoneButton(label: string, onClick: () => void): Shown;
|
|
46
|
+
export declare function PhoneAsk(props: {
|
|
47
|
+
readonly phone: PhoneControls;
|
|
48
|
+
}): Shown;
|
|
49
|
+
export declare function PhoneList(props: {
|
|
50
|
+
readonly phone: PhoneControls;
|
|
51
|
+
}): Shown;
|
|
52
|
+
export declare function phoneNotices(phone: PhoneControls): Shown;
|
|
53
|
+
export declare function PhonePanel(props: {
|
|
54
|
+
readonly phone: PhoneControls;
|
|
55
|
+
readonly now: string;
|
|
56
|
+
}): Shown;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { component, element } from "./watch-element.js";
|
|
2
|
+
export function timeLeft(expiresAt, now) {
|
|
3
|
+
const seconds = Math.max(0, Math.ceil((Date.parse(expiresAt) - Date.parse(now)) / 1000));
|
|
4
|
+
return `${String(Math.floor(seconds / 60))}:${String(seconds % 60).padStart(2, "0")} left`;
|
|
5
|
+
}
|
|
6
|
+
export function refusalText(code) {
|
|
7
|
+
const texts = {
|
|
8
|
+
"pairing-mac-invalid": "The phone sent a request that does not agree with the QR code.",
|
|
9
|
+
"pairing-key-invalid": "The phone sent a key that is not valid.",
|
|
10
|
+
"pairing-request-invalid": "The phone sent a request that is not valid.",
|
|
11
|
+
"pairing-device-revoked": "This phone was removed. Connect it again as a new phone.",
|
|
12
|
+
"pairing-expired": "The connection request expired. Click Connect a phone again.",
|
|
13
|
+
"pairing-check-invalid": "The phone did not confirm the connection. Remove it and connect again.",
|
|
14
|
+
};
|
|
15
|
+
return texts[code] ?? `The connection did not work (${code}).`;
|
|
16
|
+
}
|
|
17
|
+
export function PhoneCode(props) {
|
|
18
|
+
const { size, path } = props.picture;
|
|
19
|
+
return element("svg", {
|
|
20
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
21
|
+
class: "phone-qr",
|
|
22
|
+
viewBox: `0 0 ${String(size)} ${String(size)}`,
|
|
23
|
+
role: "img",
|
|
24
|
+
"aria-label": "Pairing QR code",
|
|
25
|
+
"shape-rendering": "crispEdges",
|
|
26
|
+
children: [
|
|
27
|
+
element("rect", { width: size, height: size, fill: "#ffffff" }),
|
|
28
|
+
element("path", { d: path, fill: "#000000" }),
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function phoneButton(label, onClick) {
|
|
33
|
+
return element("button", { type: "button", onClick, children: label });
|
|
34
|
+
}
|
|
35
|
+
export function PhoneAsk(props) {
|
|
36
|
+
const { phone } = props;
|
|
37
|
+
const request = phone.request;
|
|
38
|
+
if (request === null)
|
|
39
|
+
return null;
|
|
40
|
+
if (phone.stage === "checking")
|
|
41
|
+
return element("p", { children: `Checking ${request.name}` });
|
|
42
|
+
return element("div", {
|
|
43
|
+
class: "phone-ask",
|
|
44
|
+
children: [
|
|
45
|
+
element("strong", {
|
|
46
|
+
children: `Connect "${request.name}" (${request.platform})? Code ${request.code}`,
|
|
47
|
+
}),
|
|
48
|
+
phoneButton("Accept", phone.onAccept),
|
|
49
|
+
phoneButton("Deny", phone.onDeny),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function PhoneList(props) {
|
|
54
|
+
const { phone } = props;
|
|
55
|
+
if (phone.devices.length === 0)
|
|
56
|
+
return null;
|
|
57
|
+
return element("ul", {
|
|
58
|
+
class: "phone-list",
|
|
59
|
+
children: phone.devices.map((device) => element("li", {
|
|
60
|
+
key: device.deviceId,
|
|
61
|
+
children: [
|
|
62
|
+
`${device.name} (${device.platform}) ${device.removedAt === null ? device.state : "removed"}`,
|
|
63
|
+
device.removedAt === null
|
|
64
|
+
? phoneButton("Remove", () => {
|
|
65
|
+
phone.onRemove(device.deviceId);
|
|
66
|
+
})
|
|
67
|
+
: null,
|
|
68
|
+
],
|
|
69
|
+
})),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export function phoneNotices(phone) {
|
|
73
|
+
const lines = [
|
|
74
|
+
phone.reason === "registration-lost" ? "Connect your phones again." : null,
|
|
75
|
+
phone.connected === null ? null : `Connected: ${phone.connected}`,
|
|
76
|
+
phone.refusal === null ? null : refusalText(phone.refusal),
|
|
77
|
+
phone.message === "" ? null : phone.message,
|
|
78
|
+
];
|
|
79
|
+
return lines.map((line) => line === null ? null : element("p", { role: "status", children: line }));
|
|
80
|
+
}
|
|
81
|
+
export function PhonePanel(props) {
|
|
82
|
+
const { phone, now } = props;
|
|
83
|
+
const waiting = phone.request === null ? phone.pairing : null;
|
|
84
|
+
return element("section", {
|
|
85
|
+
class: waiting === null ? "phone" : "phone phone-pairing",
|
|
86
|
+
children: [
|
|
87
|
+
waiting === null
|
|
88
|
+
? null
|
|
89
|
+
: component(PhoneCode, { picture: waiting.picture }),
|
|
90
|
+
element("div", {
|
|
91
|
+
children: [
|
|
92
|
+
waiting === null
|
|
93
|
+
? null
|
|
94
|
+
: [
|
|
95
|
+
element("strong", { children: "Scan with your phone camera" }),
|
|
96
|
+
element("span", { children: timeLeft(waiting.expiresAt, now) }),
|
|
97
|
+
],
|
|
98
|
+
component(PhoneAsk, { phone }),
|
|
99
|
+
phone.pairing === null
|
|
100
|
+
? element("button", {
|
|
101
|
+
type: "button",
|
|
102
|
+
disabled: phone.busy,
|
|
103
|
+
onClick: phone.onPair,
|
|
104
|
+
children: "Connect a phone",
|
|
105
|
+
})
|
|
106
|
+
: phoneButton("Cancel", phone.onCancel),
|
|
107
|
+
phoneNotices(phone),
|
|
108
|
+
],
|
|
109
|
+
}),
|
|
110
|
+
component(PhoneList, { phone }),
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
import { type WatchActions } from "./watch-actions.ts";
|
|
3
|
+
export declare function isPhoneAction(path: string): boolean;
|
|
4
|
+
export declare function phoneAction(actions: WatchActions, request: IncomingMessage): Promise<string | null>;
|
|
5
|
+
export declare function phoneRead(runtimeDirectory: string): Promise<string>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { qrMatrix } from "../phone/qr-matrix.js";
|
|
2
|
+
import { qrPicture } from "../phone/qr-picture.js";
|
|
3
|
+
import { phoneRequest } from "./phone-client.js";
|
|
4
|
+
import { actionAllowed, actionBody, } from "./watch-actions.js";
|
|
5
|
+
const operations = {
|
|
6
|
+
"/actions/phone/pair": "phone-pair-start",
|
|
7
|
+
"/actions/phone/cancel": "phone-pair-cancel",
|
|
8
|
+
"/actions/phone/accept": "phone-pair-accept",
|
|
9
|
+
"/actions/phone/deny": "phone-pair-deny",
|
|
10
|
+
"/actions/phone/remove": "phone-remove",
|
|
11
|
+
};
|
|
12
|
+
export function isPhoneAction(path) {
|
|
13
|
+
return Object.hasOwn(operations, path);
|
|
14
|
+
}
|
|
15
|
+
function withPicture(result) {
|
|
16
|
+
const link = result["link"];
|
|
17
|
+
return typeof link === "string"
|
|
18
|
+
? { ...result, picture: qrPicture(qrMatrix(link).modules) }
|
|
19
|
+
: result;
|
|
20
|
+
}
|
|
21
|
+
export async function phoneAction(actions, request) {
|
|
22
|
+
const operation = operations[new URL(String(request.url), "http://localhost").pathname];
|
|
23
|
+
if (operation === undefined || !actionAllowed(actions, request))
|
|
24
|
+
return null;
|
|
25
|
+
const body = await actionBody(request);
|
|
26
|
+
if (typeof body !== "object" || body === null || Array.isArray(body))
|
|
27
|
+
return null;
|
|
28
|
+
const reply = await phoneRequest(actions.runtimeDirectory, {
|
|
29
|
+
operation,
|
|
30
|
+
parameters: { ...body },
|
|
31
|
+
});
|
|
32
|
+
if (reply === undefined)
|
|
33
|
+
return JSON.stringify({
|
|
34
|
+
error: {
|
|
35
|
+
code: "phone-relay-off",
|
|
36
|
+
detail: "The phone relay is off or not started.",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
return JSON.stringify(reply.kind === "result"
|
|
40
|
+
? withPicture(reply.result)
|
|
41
|
+
: { error: reply.error });
|
|
42
|
+
}
|
|
43
|
+
export async function phoneRead(runtimeDirectory) {
|
|
44
|
+
const reply = await phoneRequest(runtimeDirectory, {
|
|
45
|
+
operation: "phone-state",
|
|
46
|
+
parameters: {},
|
|
47
|
+
});
|
|
48
|
+
if (reply === undefined)
|
|
49
|
+
return JSON.stringify({ relay: "off" });
|
|
50
|
+
return JSON.stringify(reply.kind === "result"
|
|
51
|
+
? { relay: "on", ...reply.result }
|
|
52
|
+
: { relay: "on", error: reply.error });
|
|
53
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import type { CiRerunNotice } from "./github-ci-progress.ts";
|
|
1
2
|
import type { WatchRun } from "./watch-render.ts";
|
|
2
3
|
import { type PrRepository } from "./watch-pr-identity.ts";
|
|
3
4
|
export interface GithubRecords {
|
|
4
5
|
readonly started: unknown;
|
|
5
6
|
readonly result: unknown;
|
|
7
|
+
readonly ciReruns?: readonly CiRerunNotice[];
|
|
6
8
|
}
|
|
7
9
|
export declare function pullOf(inputs: {
|
|
8
10
|
readonly records: readonly GithubRecords[];
|
|
9
11
|
readonly repository: PrRepository | null;
|
|
10
|
-
}, runId: string): Pick<WatchRun, "pullRequest" | "reviews" | "mergeCommit" | "mergeProof">;
|
|
12
|
+
}, runId: string): Pick<WatchRun, "pullRequest" | "reviews" | "mergeCommit" | "mergeProof" | "ciReruns">;
|