cloving 1.3.0 → 1.4.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 +235 -206
- package/dist/src/agent-harness-shell.d.ts +2 -1
- package/dist/src/agent-harness-shell.js +8 -5
- package/dist/src/authority/command-wait-checks.d.ts +8 -0
- package/dist/src/authority/command-wait-checks.js +88 -0
- package/dist/src/authority/command-wait-results.d.ts +15 -0
- package/dist/src/authority/command-wait-results.js +73 -0
- package/dist/src/authority/command-wait-view.d.ts +21 -0
- package/dist/src/authority/command-wait-view.js +34 -0
- package/dist/src/authority/command-waits.d.ts +39 -0
- package/dist/src/authority/command-waits.js +97 -0
- package/dist/src/authority/commands.js +22 -1
- package/dist/src/authority/dispatch-decision.d.ts +8 -0
- package/dist/src/authority/dispatch-decision.js +26 -1
- package/dist/src/authority/effect-requests.js +6 -3
- package/dist/src/authority/effect-results.js +4 -2
- package/dist/src/authority/history-state.d.ts +2 -0
- package/dist/src/authority/history-state.js +13 -1
- package/dist/src/authority/instants.d.ts +1 -0
- package/dist/src/authority/instants.js +21 -0
- package/dist/src/authority/reduction-state.d.ts +2 -0
- package/dist/src/authority/reduction-state.js +5 -0
- package/dist/src/authority/reduction.js +24 -0
- package/dist/src/authority/status-input.d.ts +2 -0
- package/dist/src/authority/status.d.ts +2 -0
- package/dist/src/authority/status.js +1 -0
- package/dist/src/authority/stop-sequence.d.ts +1 -0
- package/dist/src/authority/stop-sequence.js +2 -1
- package/dist/src/authority/transitions.d.ts +6 -4
- package/dist/src/authority/transitions.js +7 -0
- package/dist/src/broker/actor/authority-queries.d.ts +2 -1
- package/dist/src/broker/actor/authority-queries.js +14 -5
- package/dist/src/broker/actor/authority-receipts.js +1 -1
- package/dist/src/broker/actor/authority-settings.js +2 -2
- package/dist/src/broker/actor/authority-upgrades.d.ts +19 -2
- package/dist/src/broker/actor/authority-upgrades.js +7 -2
- package/dist/src/broker/actor/delivery-intents.js +2 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
- package/dist/src/broker/actor/effect-delivery.js +15 -2
- package/dist/src/broker/actor/effect-plan.js +11 -2
- package/dist/src/broker/actor/effect-queries.d.ts +4 -0
- package/dist/src/broker/actor/effect-queries.js +9 -1
- package/dist/src/broker/actor/effect-turn.js +2 -0
- package/dist/src/broker/actor/stop-plan.js +9 -3
- package/dist/src/broker/actor/stop-turn.d.ts +2 -0
- package/dist/src/broker/actor/stop-turn.js +24 -11
- package/dist/src/broker/actor/turn-draft.d.ts +1 -0
- package/dist/src/broker/actor/turn-draft.js +4 -0
- package/dist/src/broker/actor/turn-state.js +5 -1
- package/dist/src/broker/authority-admission.js +60 -0
- package/dist/src/broker/authority-restore.d.ts +2 -0
- package/dist/src/broker/authority-restore.js +35 -1
- package/dist/src/broker/command-wait-restore.d.ts +31 -0
- package/dist/src/broker/command-wait-restore.js +86 -0
- package/dist/src/broker/decision-restore.d.ts +1 -1
- package/dist/src/broker/decision-restore.js +1 -0
- package/dist/src/broker/effect-upgrade.d.ts +2 -0
- package/dist/src/broker/effect-upgrade.js +8 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +42 -3
- package/dist/src/cli/chat-stores.d.ts +2 -0
- package/dist/src/cli/chat-stores.js +113 -0
- package/dist/src/cli/client.d.ts +4 -1
- package/dist/src/cli/client.js +9 -3
- package/dist/src/cli/command-requests.d.ts +17 -0
- package/dist/src/cli/command-requests.js +43 -0
- package/dist/src/cli/command-waits.d.ts +9 -0
- package/dist/src/cli/command-waits.js +51 -0
- package/dist/src/cli/commands.js +14 -41
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/doctor-workflows.d.ts +5 -2
- package/dist/src/cli/doctor-workflows.js +12 -7
- package/dist/src/cli/doctor.js +6 -9
- package/dist/src/cli/harness-probes.d.ts +2 -0
- package/dist/src/cli/harness-probes.js +1 -1
- package/dist/src/cli/harness-processes.d.ts +6 -0
- package/dist/src/cli/harness-processes.js +36 -0
- package/dist/src/cli/init-command.d.ts +9 -0
- package/dist/src/cli/init-command.js +52 -0
- package/dist/src/cli/init-prompt-command.d.ts +10 -0
- package/dist/src/cli/init-prompt-command.js +145 -0
- package/dist/src/cli/init-prompt.d.ts +35 -0
- package/dist/src/cli/init-prompt.js +74 -0
- package/dist/src/cli/init-selection.d.ts +13 -0
- package/dist/src/cli/init-selection.js +75 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +37 -7
- package/dist/src/cli/mcp-server.d.ts +1 -0
- package/dist/src/cli/mcp-server.js +156 -0
- package/dist/src/cli/mcp-tools.d.ts +15 -0
- package/dist/src/cli/mcp-tools.js +80 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +17 -30
- package/dist/src/cli/report-ci-jobs.d.ts +23 -0
- package/dist/src/cli/report-ci-jobs.js +103 -0
- package/dist/src/cli/report-ci-usage.d.ts +9 -0
- package/dist/src/cli/report-ci-usage.js +185 -0
- package/dist/src/cli/report-ci.d.ts +13 -0
- package/dist/src/cli/report-ci.js +74 -0
- package/dist/src/cli/report-closures.d.ts +6 -0
- package/dist/src/cli/report-closures.js +97 -0
- package/dist/src/cli/report-flow.d.ts +7 -0
- package/dist/src/cli/report-flow.js +122 -0
- package/dist/src/cli/report-github-reader.d.ts +29 -0
- package/dist/src/cli/report-github-reader.js +157 -0
- package/dist/src/cli/report-github.d.ts +15 -8
- package/dist/src/cli/report-github.js +131 -150
- package/dist/src/cli/report-operator.d.ts +3 -0
- package/dist/src/cli/report-operator.js +40 -0
- package/dist/src/cli/report-ready.d.ts +3 -0
- package/dist/src/cli/report-ready.js +96 -0
- package/dist/src/cli/report-text.d.ts +9 -0
- package/dist/src/cli/report-text.js +33 -0
- package/dist/src/cli/report.d.ts +1 -0
- package/dist/src/cli/report.js +104 -27
- package/dist/src/cli/runtime-arguments.d.ts +2 -1
- package/dist/src/cli/runtime-arguments.js +7 -2
- package/dist/src/cli/schedule-arguments.d.ts +14 -0
- package/dist/src/cli/schedule-arguments.js +26 -0
- package/dist/src/cli/schedule-render.d.ts +22 -0
- package/dist/src/cli/schedule-render.js +73 -0
- package/dist/src/cli/terminal-text.d.ts +3 -0
- package/dist/src/cli/terminal-text.js +28 -0
- package/dist/src/cli/usage-render.d.ts +1 -0
- package/dist/src/cli/usage-render.js +28 -1
- package/dist/src/cli/usage.d.ts +1 -1
- package/dist/src/cli/usage.js +50 -7
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-board-view.js +19 -2
- package/dist/src/cli/watch-board.d.ts +4 -2
- package/dist/src/cli/watch-board.js +53 -43
- package/dist/src/cli/watch-card-forms.d.ts +1 -1
- package/dist/src/cli/watch-card-forms.js +11 -10
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +2 -11
- package/dist/src/cli/watch-header-view.d.ts +0 -5
- package/dist/src/cli/watch-header-view.js +8 -20
- package/dist/src/cli/watch-model.d.ts +4 -1
- package/dist/src/cli/watch-model.js +17 -11
- package/dist/src/cli/watch-page.js +12 -14
- package/dist/src/cli/watch-phases.d.ts +12 -3
- package/dist/src/cli/watch-phases.js +68 -11
- package/dist/src/cli/watch-pr-board.js +1 -1
- package/dist/src/cli/watch-pr-command.d.ts +1 -0
- package/dist/src/cli/watch-pull-request.js +18 -8
- package/dist/src/cli/watch-reads.d.ts +2 -0
- package/dist/src/cli/watch-reads.js +17 -16
- package/dist/src/cli/watch-render.d.ts +14 -0
- package/dist/src/cli/watch-run-input.d.ts +0 -1
- package/dist/src/cli/watch-run-input.js +0 -13
- package/dist/src/cli/watch-server.js +6 -6
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +59 -5
- package/dist/src/command-wait.d.ts +4 -0
- package/dist/src/command-wait.js +45 -0
- package/dist/src/configuration-change.d.ts +7 -0
- package/dist/src/configuration-change.js +14 -0
- package/dist/src/configuration-schema.d.ts +9 -0
- package/dist/src/configuration-schema.js +6 -2
- package/dist/src/daemon/attachment-file.d.ts +6 -0
- package/dist/src/daemon/attachment-file.js +86 -0
- package/dist/src/daemon/attachments.d.ts +14 -0
- package/dist/src/daemon/attachments.js +17 -0
- package/dist/src/daemon/claude-recovery.d.ts +50 -0
- package/dist/src/daemon/claude-recovery.js +204 -0
- package/dist/src/daemon/claude-stream.d.ts +27 -0
- package/dist/src/daemon/claude-stream.js +63 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -25
- package/dist/src/daemon/claude-turn.js +64 -81
- package/dist/src/daemon/claude-worker.d.ts +2 -1
- package/dist/src/daemon/claude-worker.js +124 -122
- package/dist/src/daemon/daemon-adapters.d.ts +2 -0
- package/dist/src/daemon/daemon-adapters.js +26 -2
- package/dist/src/daemon/daemon-loops.d.ts +3 -1
- package/dist/src/daemon/daemon-loops.js +3 -1
- package/dist/src/daemon/daemon.js +14 -6
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +149 -0
- package/dist/src/daemon/github-ci-filters.d.ts +6 -0
- package/dist/src/daemon/github-ci-filters.js +138 -0
- package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
- package/dist/src/daemon/github-ci-workflows.js +148 -0
- package/dist/src/daemon/github-ci.js +22 -4
- package/dist/src/daemon/github-issue-methods.d.ts +2 -0
- package/dist/src/daemon/github-issue-methods.js +37 -2
- package/dist/src/daemon/github-merge-call.d.ts +2 -1
- package/dist/src/daemon/github-merge-call.js +10 -3
- package/dist/src/daemon/github-merge.js +52 -24
- package/dist/src/daemon/github-methods.js +12 -2
- package/dist/src/daemon/github-operation.d.ts +4 -0
- package/dist/src/daemon/github-operation.js +6 -0
- package/dist/src/daemon/github-worker.d.ts +4 -0
- package/dist/src/daemon/github-worker.js +6 -0
- package/dist/src/daemon/issue-queue.d.ts +1 -1
- package/dist/src/daemon/issue-queue.js +16 -11
- package/dist/src/daemon/notify-events.d.ts +6 -0
- package/dist/src/daemon/notify-events.js +84 -0
- package/dist/src/daemon/notify-journal.js +1 -1
- package/dist/src/daemon/notify-message.d.ts +4 -1
- package/dist/src/daemon/notify-message.js +36 -0
- package/dist/src/daemon/notify.d.ts +1 -1
- package/dist/src/daemon/notify.js +5 -77
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/resume-index-lock.d.ts +13 -0
- package/dist/src/daemon/resume-index-lock.js +160 -0
- package/dist/src/daemon/resume-worktree.d.ts +7 -0
- package/dist/src/daemon/resume-worktree.js +29 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -12
- package/dist/src/daemon/retrying-turn.js +98 -172
- package/dist/src/daemon/schedule-control.d.ts +26 -0
- package/dist/src/daemon/schedule-control.js +110 -0
- package/dist/src/daemon/schedule-journal.d.ts +2 -15
- package/dist/src/daemon/schedule-journal.js +67 -4
- package/dist/src/daemon/ticket-registration.d.ts +2 -7
- package/dist/src/daemon/ticket-registration.js +15 -81
- package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
- package/dist/src/daemon/turn-attempt-journal.js +136 -0
- package/dist/src/daemon/turn-attempts.d.ts +47 -0
- package/dist/src/daemon/turn-attempts.js +166 -0
- package/dist/src/daemon/turn-report.d.ts +8 -1
- package/dist/src/daemon/turn-report.js +39 -0
- package/dist/src/daemon/work-tree.d.ts +9 -0
- package/dist/src/daemon/work-tree.js +20 -0
- package/dist/src/daemon/worker-profile.d.ts +8 -0
- package/dist/src/daemon/worker-profile.js +40 -0
- package/dist/src/daemon/workflow-schedules.d.ts +3 -0
- package/dist/src/daemon/workflow-schedules.js +98 -45
- package/dist/src/daemon/worktree-processes.d.ts +9 -0
- package/dist/src/daemon/worktree-processes.js +151 -0
- package/dist/src/doctor-report.d.ts +3 -5
- package/dist/src/doctor-report.js +6 -13
- package/dist/src/harness-start.d.ts +15 -0
- package/dist/src/harness-start.js +37 -0
- package/dist/src/host/command-wait.d.ts +38 -0
- package/dist/src/host/command-wait.js +115 -0
- package/dist/src/host/start-delivery.d.ts +5 -7
- package/dist/src/host/start-delivery.js +3 -15
- package/dist/src/host/step-bridge-host.d.ts +2 -0
- package/dist/src/host/step-bridge-host.js +21 -0
- package/dist/src/operation-identity.d.ts +1 -0
- package/dist/src/operation-identity.js +4 -0
- package/dist/src/private-config.schema.json +40 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +2 -2
- package/dist/src/project-settings.js +3 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/relay/relay-service.d.ts +3 -0
- package/dist/src/relay/relay-service.js +5 -3
- package/dist/src/report-ci.d.ts +164 -0
- package/dist/src/report-ci.js +32 -0
- package/dist/src/report-effects.d.ts +15 -0
- package/dist/src/report-effects.js +212 -0
- package/dist/src/report-flow-types.d.ts +38 -0
- package/dist/src/report-flow-types.js +7 -0
- package/dist/src/report-flow.d.ts +43 -0
- package/dist/src/report-flow.js +193 -0
- package/dist/src/report-operator.d.ts +67 -0
- package/dist/src/report-operator.js +25 -0
- package/dist/src/report-quality.d.ts +221 -0
- package/dist/src/report-quality.js +94 -0
- package/dist/src/report-ready.d.ts +23 -0
- package/dist/src/report-ready.js +117 -0
- package/dist/src/report-statistics.d.ts +2 -1
- package/dist/src/report-statistics.js +40 -4
- package/dist/src/report.d.ts +588 -47
- package/dist/src/report.js +156 -41
- package/dist/src/schedule-progress.d.ts +33 -0
- package/dist/src/schedule-progress.js +45 -0
- package/dist/src/service/active-tickets.js +6 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/replies.d.ts +8 -1
- package/dist/src/service/replies.js +11 -0
- package/dist/src/service/run-handlers.js +22 -2
- package/dist/src/service/run-metadata.d.ts +15 -1
- package/dist/src/service/run-metadata.js +93 -8
- package/dist/src/service/service.d.ts +4 -0
- package/dist/src/service/service.js +8 -8
- package/dist/src/service/submission-handler.js +18 -4
- package/dist/src/service/worker-port.js +9 -1
- package/dist/src/service/worker-totals.d.ts +2 -0
- package/dist/src/service/worker-totals.js +1 -1
- package/dist/src/step-bridge.d.ts +20 -0
- package/dist/src/steps/command-wait.d.ts +12 -0
- package/dist/src/steps/command-wait.js +26 -0
- package/dist/src/steps/open-decision-wait.d.ts +2 -0
- package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
- package/dist/src/steps/review-by-person.js +4 -1
- package/dist/src/steps/wait-for-command.d.ts +3 -0
- package/dist/src/steps/wait-for-command.js +17 -0
- package/dist/src/steps/wait-for-decision.js +1 -1
- package/dist/src/storage/command-wait-rows.d.ts +30 -0
- package/dist/src/storage/command-wait-rows.js +96 -0
- package/dist/src/storage/decision-snapshots.d.ts +8 -1
- package/dist/src/storage/decision-snapshots.js +15 -1
- package/dist/src/storage/domain-changes.d.ts +2 -0
- package/dist/src/storage/domain-changes.js +3 -0
- package/dist/src/storage/domain-schema.d.ts +13 -1
- package/dist/src/storage/domain-schema.js +31 -4
- package/dist/src/storage/effect-schema.d.ts +1 -0
- package/dist/src/storage/effect-schema.js +5 -0
- package/dist/src/testing-requests.d.ts +15 -0
- package/dist/src/testing-requests.js +93 -0
- package/dist/src/testing.d.ts +4 -10
- package/dist/src/testing.js +33 -86
- package/dist/src/worker-usage.d.ts +1 -0
- package/dist/src/worker-usage.js +3 -0
- package/dist/src/workflow-candidate.d.ts +1 -0
- package/dist/src/workflow-candidate.js +12 -1
- package/dist/src/workflow-contracts.d.ts +1 -0
- package/dist/src/workflow-contracts.js +9 -2
- package/dist/src/workflow-discovery.d.ts +2 -13
- package/dist/src/workflow-discovery.js +1 -13
- package/dist/src/workflow-refusals.js +0 -1
- package/dist/src/workflows.d.ts +1 -1
- package/dist/src/workflows.js +1 -1
- package/dist/tools/red-green-command.d.ts +1 -0
- package/dist/tools/red-green-command.js +174 -0
- package/dist/tools/red-green-process.d.ts +10 -0
- package/dist/tools/red-green-process.js +59 -0
- package/dist/tools/self-host-processes.d.ts +2 -0
- package/dist/tools/self-host-processes.js +32 -13
- package/dist/tools/self-host-project.js +13 -78
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +42 -10
- package/dist/tools/template-command.d.ts +1 -0
- package/dist/tools/template-command.js +160 -0
- package/dist/tools/template-copy.d.ts +11 -0
- package/dist/tools/template-copy.js +130 -0
- package/dist/tools/template-files.d.ts +17 -0
- package/dist/tools/template-files.js +74 -0
- package/dist/tools/workflow-bundles.js +1 -0
- package/dist/tools/workflow-candidate-counts.js +2 -2
- package/dist/tools/workflow-candidate-shape.d.ts +3 -0
- package/dist/tools/workflow-candidate-shape.js +90 -0
- package/dist/tools/workflow-candidate-source.js +15 -1
- package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
- package/dist/tools/workflow-candidate-syntax.js +24 -94
- package/dist/tools/workflow-command.js +1 -2
- package/dist/tools/workflow-folders.d.ts +2 -3
- package/dist/tools/workflow-folders.js +1 -1
- package/package.json +16 -8
- package/templates/develop/README.md +12 -0
- package/templates/develop/develop/flow-tests.ts +37 -0
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/turn.ts +2 -1
- package/templates/idea-to-issue/README.md +27 -0
- package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
- package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
- package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
- package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
- package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
- package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
- package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
- package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
- package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
- package/templates/idea-to-issue/idea-to-issue.ts +49 -0
- package/templates/idea-to-issue/template.json +81 -0
- package/templates/review-day/README.md +97 -0
- package/templates/review-day/review-day/critique.ts +58 -0
- package/templates/review-day/review-day/decision.ts +29 -0
- package/templates/review-day/review-day/facts.ts +69 -0
- package/templates/review-day/review-day/label.ts +29 -0
- package/templates/review-day/review-day/next.ts +28 -0
- package/templates/review-day/review-day/post.ts +27 -0
- package/templates/review-day/review-day/report.ts +98 -0
- package/templates/review-day/review-day/rules.ts +12 -0
- package/templates/review-day/review-day/scenarios.ts +76 -0
- package/templates/review-day/review-day/turn.ts +73 -0
- package/templates/review-day/review-day.declaration.json +16 -0
- package/templates/review-day/review-day.test.ts +362 -0
- package/templates/review-day/review-day.ts +37 -0
- package/templates/review-day/template.json +56 -0
- package/dist/src/cli/watch-start-view.d.ts +0 -18
- package/dist/src/cli/watch-start-view.js +0 -77
- package/dist/src/steps/decision-gate.d.ts +0 -3
- package/dist/workflows/develop-prd.d.ts +0 -7
- package/dist/workflows/develop-prd.js +0 -165
- package/dist/workflows/develop-ticket.d.ts +0 -9
- package/dist/workflows/develop-ticket.js +0 -207
- package/dist/workflows/issue-labels.d.ts +0 -16
- package/dist/workflows/issue-labels.js +0 -70
- package/dist/workflows/ticket-prompts.d.ts +0 -35
- package/dist/workflows/ticket-prompts.js +0 -147
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { scheduleStatusLine, scheduledText } from "./schedule-render.js";
|
|
2
|
+
import { CommandWaits, effectBudgetText } from "./command-waits.js";
|
|
1
3
|
import { AddCard } from "./watch-card-view.js";
|
|
2
4
|
import { priceText } from "./usage-render.js";
|
|
3
5
|
import { component, element } from "./watch-element.js";
|
|
@@ -40,8 +42,6 @@ export function cardReview(card) {
|
|
|
40
42
|
.join(" · ");
|
|
41
43
|
}
|
|
42
44
|
export function CardReview(props) {
|
|
43
|
-
if (props.workflowId !== "develop-issue")
|
|
44
|
-
return null;
|
|
45
45
|
const review = cardReview(props.card);
|
|
46
46
|
if (review === "")
|
|
47
47
|
return null;
|
|
@@ -117,6 +117,12 @@ export function Card(props) {
|
|
|
117
117
|
children: cardStep(card, now),
|
|
118
118
|
}),
|
|
119
119
|
component(CardReview, { card, workflowId }),
|
|
120
|
+
card.scheduled === undefined
|
|
121
|
+
? null
|
|
122
|
+
: element("span", {
|
|
123
|
+
class: "meta",
|
|
124
|
+
children: scheduledText(card.scheduled),
|
|
125
|
+
}),
|
|
120
126
|
element("span", {
|
|
121
127
|
class: "card-cost",
|
|
122
128
|
children: `${card.currentStep === null ? "Totals" : "Totals so far"} · ${priceText(card.claudeCostUsd, card.estimatedCostUsd)}`,
|
|
@@ -131,6 +137,11 @@ export function Card(props) {
|
|
|
131
137
|
],
|
|
132
138
|
}),
|
|
133
139
|
completionMark(card, { workflowId, now: props.observationNow ?? now }),
|
|
140
|
+
element("span", {
|
|
141
|
+
class: "meta",
|
|
142
|
+
children: effectBudgetText(card.spent, card.limit),
|
|
143
|
+
}),
|
|
144
|
+
component(CommandWaits, { waits: card.commandWaits ?? [] }),
|
|
134
145
|
component(HandoffLinks, { run: card }),
|
|
135
146
|
],
|
|
136
147
|
});
|
|
@@ -231,6 +242,12 @@ export function Board(props) {
|
|
|
231
242
|
class: "visually-hidden",
|
|
232
243
|
children: workflow.workflowId,
|
|
233
244
|
}),
|
|
245
|
+
workflow.schedule === undefined
|
|
246
|
+
? null
|
|
247
|
+
: element("p", {
|
|
248
|
+
class: "meta",
|
|
249
|
+
children: scheduleStatusLine(workflow.schedule, "watch"),
|
|
250
|
+
}),
|
|
234
251
|
element("div", {
|
|
235
252
|
class: "columns",
|
|
236
253
|
children: workflow.columns.map((column, index) => component(Column, {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import type { ShownSchedules } from "./schedule-render.ts";
|
|
1
2
|
import type { WorkflowStage, WorkflowStages } from "../workflow-declaration.ts";
|
|
2
|
-
import type { WatchCompletionMark, WatchRun, WatchStep, WatchWorkflow } from "./watch-render.ts";
|
|
3
|
+
import type { WatchCompletionMark, WatchPullRequest, WatchRun, WatchStep, WatchWorkflow } from "./watch-render.ts";
|
|
3
4
|
export declare function completionMarkOf(run: WatchRun, candidates: readonly WatchRun[]): WatchCompletionMark | null;
|
|
4
5
|
export declare function activeRun(state: string): boolean;
|
|
5
6
|
export declare function recentRun(latestAt: string | null, now: string): boolean;
|
|
6
7
|
export declare function stagesFor(metadata: WorkflowStages | undefined, workflowId: string): readonly WorkflowStage[] | undefined;
|
|
7
8
|
export declare function currentStepOf(events: readonly unknown[], workflow: {
|
|
8
|
-
readonly
|
|
9
|
+
readonly pullRequest?: WatchPullRequest | null;
|
|
9
10
|
readonly stages: readonly WorkflowStage[] | undefined;
|
|
10
11
|
}): WatchStep;
|
|
11
12
|
export declare function roundOf(events: readonly unknown[]): number;
|
|
12
13
|
interface BoardInputs {
|
|
14
|
+
readonly schedules?: ShownSchedules;
|
|
13
15
|
readonly workflows: readonly string[];
|
|
14
16
|
readonly workflowStages?: WorkflowStages;
|
|
15
17
|
readonly updatedAt: string;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { activeCommandWait, shownCommandWaits } from "./command-waits.js";
|
|
1
2
|
import { linksOf } from "../authority/handoff-chain.js";
|
|
2
3
|
import { record } from "../protocol.js";
|
|
3
4
|
import { isInstant } from "../authority/instants.js";
|
|
4
|
-
import {
|
|
5
|
+
import { pullRequestSteps, pullRequestStepOf, stageOf, } from "./watch-phases.js";
|
|
5
6
|
import { sameIssue } from "./watch-pr-identity.js";
|
|
6
7
|
const weekMilliseconds = 7 * 24 * 60 * 60 * 1000;
|
|
7
8
|
const terminalStates = ["completed", "failed", "cancelled"];
|
|
@@ -10,21 +11,20 @@ function eventTime(run, type) {
|
|
|
10
11
|
return isInstant(recordedAt) ? Date.parse(recordedAt) : NaN;
|
|
11
12
|
}
|
|
12
13
|
export function completionMarkOf(run, candidates) {
|
|
13
|
-
if (run.
|
|
14
|
-
run.state !== "completed" ||
|
|
15
|
-
run.outcome !== "blocked")
|
|
14
|
+
if (run.state !== "completed")
|
|
16
15
|
return null;
|
|
17
16
|
if (run.mergeProof != null)
|
|
18
17
|
return {
|
|
19
18
|
text: `PR merged · #${String(run.mergeProof.number)}`,
|
|
20
19
|
laterRunId: null,
|
|
21
20
|
};
|
|
21
|
+
if (run.outcome !== "blocked")
|
|
22
|
+
return null;
|
|
22
23
|
const completedAt = eventTime(run, "run.completed");
|
|
23
24
|
const later = candidates
|
|
24
25
|
.filter((candidate) => sameIssue(run.issueIdentity, candidate.issueIdentity) &&
|
|
25
26
|
candidate.mergeProof != null &&
|
|
26
27
|
candidate.runId !== run.runId &&
|
|
27
|
-
candidate.workflowId === "develop-issue" &&
|
|
28
28
|
candidate.state === "completed" &&
|
|
29
29
|
candidate.outcome === "handoff_requested" &&
|
|
30
30
|
candidate.ticketStatus !== "partial" &&
|
|
@@ -52,11 +52,11 @@ export function stagesFor(metadata, workflowId) {
|
|
|
52
52
|
? metadata[workflowId]
|
|
53
53
|
: undefined;
|
|
54
54
|
}
|
|
55
|
-
function stepNames(
|
|
56
|
-
if (
|
|
55
|
+
function stepNames(workflow, stages) {
|
|
56
|
+
if (stages !== undefined)
|
|
57
57
|
return [...stages.map((stage) => stage.label), "Other"];
|
|
58
|
-
return
|
|
59
|
-
?
|
|
58
|
+
return workflow.pullRequest != null
|
|
59
|
+
? pullRequestSteps.map((step) => step.name)
|
|
60
60
|
: ["Agent turn", "Your review"];
|
|
61
61
|
}
|
|
62
62
|
function operationOf(event) {
|
|
@@ -69,16 +69,15 @@ function operationOf(event) {
|
|
|
69
69
|
return [];
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
function stepName(event,
|
|
72
|
+
function stepName(event, workflow) {
|
|
73
73
|
const type = record(event)?.["type"];
|
|
74
|
-
if (
|
|
74
|
+
if (workflow.pullRequest == null && type === "gate.opened")
|
|
75
75
|
return "Your review";
|
|
76
76
|
if (type !== "effect.requested")
|
|
77
77
|
return undefined;
|
|
78
|
-
if (
|
|
78
|
+
if (workflow.pullRequest == null)
|
|
79
79
|
return "Agent turn";
|
|
80
|
-
return
|
|
81
|
-
?.name;
|
|
80
|
+
return pullRequestStepOf(event)?.name;
|
|
82
81
|
}
|
|
83
82
|
function startedAt(event) {
|
|
84
83
|
const value = record(event)?.["recordedAt"];
|
|
@@ -87,30 +86,21 @@ function startedAt(event) {
|
|
|
87
86
|
function chronological(events) {
|
|
88
87
|
return events.toSorted((first, second) => Date.parse(startedAt(first) ?? "") - Date.parse(startedAt(second) ?? ""));
|
|
89
88
|
}
|
|
90
|
-
function declaredStage(event, stages) {
|
|
91
|
-
if (record(event)?.["type"] === "effect.requested") {
|
|
92
|
-
const operation = operationOf(event)[4];
|
|
93
|
-
return stages.find((stage) => stage.operations?.some((name) => name === operation));
|
|
94
|
-
}
|
|
95
|
-
const payload = record(record(event)?.["payload"]);
|
|
96
|
-
return (stages.find((stage) => stage.gateIds?.some((name) => name === payload?.["gateId"])) ??
|
|
97
|
-
stages.find((stage) => stage.gateKinds?.some((name) => name === payload?.["gateKind"])));
|
|
98
|
-
}
|
|
99
89
|
function declaredStep(events, stages) {
|
|
100
90
|
const event = events
|
|
101
91
|
.filter((item) => ["effect.requested", "gate.opened"].includes(String(record(item)?.["type"])))
|
|
102
92
|
.toSorted((first, second) => Number(record(second)?.["sequence"]) -
|
|
103
93
|
Number(record(first)?.["sequence"]))[0];
|
|
104
|
-
const stage =
|
|
94
|
+
const stage = stageOf(event, stages);
|
|
105
95
|
return { name: stage?.label ?? "Other", startedAt: startedAt(event) };
|
|
106
96
|
}
|
|
107
97
|
export function currentStepOf(events, workflow) {
|
|
108
|
-
const {
|
|
109
|
-
if (
|
|
98
|
+
const { stages } = workflow;
|
|
99
|
+
if (stages !== undefined)
|
|
110
100
|
return declaredStep(events, stages);
|
|
111
|
-
const event = chronological(events).findLast((item) => stepName(item,
|
|
101
|
+
const event = chronological(events).findLast((item) => stepName(item, workflow) !== undefined);
|
|
112
102
|
return {
|
|
113
|
-
name: stepName(event,
|
|
103
|
+
name: stepName(event, workflow) ?? stepNames(workflow)[0] ?? "Agent turn",
|
|
114
104
|
startedAt: startedAt(event),
|
|
115
105
|
};
|
|
116
106
|
}
|
|
@@ -129,17 +119,20 @@ function columnOf(run, now) {
|
|
|
129
119
|
return "Stopped";
|
|
130
120
|
return run.outcome === "handoff_requested" ? "Done" : null;
|
|
131
121
|
}
|
|
132
|
-
function
|
|
133
|
-
const issue = run.workflowId === "develop-issue";
|
|
122
|
+
function pullRequestCardDetails(run) {
|
|
134
123
|
return {
|
|
135
|
-
round:
|
|
136
|
-
greptileScore:
|
|
137
|
-
pullRequestNumber:
|
|
124
|
+
round: run.pullRequest !== null ? run.round : null,
|
|
125
|
+
greptileScore: run.reviews.at(-1)?.score ?? null,
|
|
126
|
+
pullRequestNumber: run.pullRequest?.number ?? null,
|
|
138
127
|
};
|
|
139
128
|
}
|
|
140
129
|
function cardOf(run, runs) {
|
|
141
130
|
return {
|
|
142
131
|
runId: run.runId,
|
|
132
|
+
...(run.scheduled === undefined ? {} : { scheduled: run.scheduled }),
|
|
133
|
+
commandWaits: run.commandWaits ?? [],
|
|
134
|
+
spent: run.spent,
|
|
135
|
+
limit: run.limit,
|
|
143
136
|
title: run.title,
|
|
144
137
|
...linksOf(run),
|
|
145
138
|
...(run.awaitedRunId == null ? {} : { awaitedRunId: run.awaitedRunId }),
|
|
@@ -151,7 +144,7 @@ function cardOf(run, runs) {
|
|
|
151
144
|
currentStep: activeRun(run.state) ? run.currentStep : null,
|
|
152
145
|
endedAt: activeRun(run.state) ? null : run.latestAt,
|
|
153
146
|
decisionWaiting: run.decisions.length > 0,
|
|
154
|
-
...
|
|
147
|
+
...pullRequestCardDetails(run),
|
|
155
148
|
};
|
|
156
149
|
}
|
|
157
150
|
function stepOrder(first, second) {
|
|
@@ -174,27 +167,43 @@ function summaryOf(value) {
|
|
|
174
167
|
return {
|
|
175
168
|
state: String(fields?.["state"]),
|
|
176
169
|
waiting: (Array.isArray(pending) && pending.length > 0) ||
|
|
177
|
-
typeof fields?.["awaitedRunId"] === "string"
|
|
170
|
+
typeof fields?.["awaitedRunId"] === "string" ||
|
|
171
|
+
activeCommandWait(shownCommandWaits(fields?.["commandWaits"])),
|
|
178
172
|
latestAt: typeof latest === "string" ? latest : null,
|
|
179
173
|
};
|
|
180
174
|
}
|
|
175
|
+
function runSummaryOf(run) {
|
|
176
|
+
return {
|
|
177
|
+
state: run.state,
|
|
178
|
+
waiting: run.decisions.length > 0 ||
|
|
179
|
+
run.awaitedRunId != null ||
|
|
180
|
+
activeCommandWait(run.commandWaits ?? []),
|
|
181
|
+
latestAt: run.latestAt,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
181
184
|
export function boardsOf(inputs, runs) {
|
|
185
|
+
const schedules = inputs.schedules ?? [];
|
|
182
186
|
return inputs.workflows.map((workflowId) => {
|
|
183
187
|
const own = runs.filter((run) => run.workflowId === workflowId);
|
|
188
|
+
const schedule = "status" in schedules
|
|
189
|
+
? undefined
|
|
190
|
+
: schedules.find((entry) => entry.workflowId === workflowId);
|
|
184
191
|
const summaries = inputs.summaries === undefined
|
|
185
|
-
? own.map(
|
|
186
|
-
state: run.state,
|
|
187
|
-
waiting: run.decisions.length > 0 || run.awaitedRunId != null,
|
|
188
|
-
latestAt: run.latestAt,
|
|
189
|
-
}))
|
|
192
|
+
? own.map(runSummaryOf)
|
|
190
193
|
: inputs.summaries
|
|
191
194
|
.filter((value) => record(value)?.["workflowId"] === workflowId)
|
|
192
195
|
.map(summaryOf);
|
|
193
|
-
const
|
|
194
|
-
...stepNames(
|
|
196
|
+
const names = [
|
|
197
|
+
...stepNames({
|
|
198
|
+
pullRequest: own.find((run) => run.pullRequest !== null)?.pullRequest ?? null,
|
|
199
|
+
}, stagesFor(inputs.workflowStages, workflowId)),
|
|
200
|
+
...own
|
|
201
|
+
.filter((run) => activeRun(run.state))
|
|
202
|
+
.map((run) => run.currentStep.name),
|
|
195
203
|
"Done",
|
|
196
204
|
"Stopped",
|
|
197
|
-
]
|
|
205
|
+
];
|
|
206
|
+
const columns = [...new Set(names)].map((name) => {
|
|
198
207
|
const cards = own
|
|
199
208
|
.filter((run) => columnOf(run, inputs.updatedAt) === name)
|
|
200
209
|
.map((run) => cardOf(run, inputs.completionCandidates ?? runs));
|
|
@@ -210,6 +219,7 @@ export function boardsOf(inputs, runs) {
|
|
|
210
219
|
});
|
|
211
220
|
return {
|
|
212
221
|
workflowId,
|
|
222
|
+
...(schedule === undefined ? {} : { schedule }),
|
|
213
223
|
activeCount: summaries.filter((run) => activeRun(run.state)).length,
|
|
214
224
|
waitingCount: summaries.filter((run) => run.waiting).length,
|
|
215
225
|
latestAt: latestTime(summaries.map((run) => run.latestAt)),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CardForm } from "./watch-run-input.ts";
|
|
2
2
|
export declare function watchCardForms(directory: string): Promise<readonly CardForm[]>;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isWorkflowDeclaration } from "../workflow-declaration.js";
|
|
4
|
-
import {
|
|
4
|
+
import { record } from "../protocol.js";
|
|
5
5
|
export async function watchCardForms(directory) {
|
|
6
|
-
const forms = [
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const forms = [];
|
|
7
|
+
const declarations = await readFile(join(directory, "declarations.json"), "utf8")
|
|
8
|
+
.then((text) => JSON.parse(text))
|
|
9
|
+
.catch(() => null);
|
|
10
|
+
if (!Array.isArray(declarations))
|
|
11
|
+
return [];
|
|
12
|
+
for (const declaration of declarations) {
|
|
13
|
+
const value = { ...record(declaration) };
|
|
14
|
+
delete value["functionName"];
|
|
14
15
|
if (!isWorkflowDeclaration(value))
|
|
15
16
|
continue;
|
|
16
17
|
const entries = Object.entries(value.input.fields);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const watchClient = "\nconst state = { model: null, receivedAt: 0, stale: false, copied: \"\", label: \"\", run: \"\", loading: false, again: false, columns: {}, cards: {},
|
|
1
|
+
export declare const watchClient = "\nconst state = { model: null, receivedAt: 0, stale: false, copied: \"\", label: \"\", run: \"\", loading: false, again: false, columns: {}, cards: {}, hovered: null, focused: null, phonePairing: null, phoneBusy: false, phoneMessage: \"\", phone: null, phoneLoadedAt: 0, phoneAccepted: null, phoneSequence: 0, phoneApplied: 0 };\nfunction readPreference(key) {\n try { return JSON.parse(localStorage.getItem(key)); }\n catch { return null; }\n}\nfunction readColumnChoices(key) {\n const value = readPreference(key);\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n return Object.fromEntries(Object.entries(value).filter(([, choice]) => typeof choice === \"boolean\"));\n}\nfunction savePreference(key, value) {\n try { localStorage.setItem(key, JSON.stringify(value)); }\n catch {}\n}\nfunction columnControls(model, selected) {\n const workflowId = model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId);\n if (workflowId === null) return undefined;\n const key = \"cloving.watch.columns:\" + workflowId;\n if (!Object.hasOwn(state.columns, workflowId))\n state.columns = { ...state.columns, [workflowId]: readColumnChoices(key) };\n const choices = state.columns[workflowId];\n return { choices, onHover(name) { state.hovered = name; }, onFocus(name) { state.focused = name; }, onToggle(name) {\n const changed = { ...choices, [name]: !columnCollapsed(choices, name) };\n state.columns = { ...state.columns, [workflowId]: changed };\n savePreference(key, changed);\n draw();\n } };\n}\nfunction moved(next, followed) {\n const arrived = next === \"waiting_gate\" && next !== state.run;\n state.run = next;\n if (arrived) scrollTo(0, 0);\n else if (followed && next === \"running\") scrollTo(0, document.body.scrollHeight);\n}\nfunction copy(command) {\n const shown = (label) => {\n state.copied = command;\n state.label = label;\n draw();\n };\n navigator.clipboard.writeText(command).then(\n () => { shown(\"Copied\"); },\n () => { shown(\"Copy failed\"); },\n );\n}\nfunction draw() {\n const { model, stale } = state;\n const selected = location.hash.slice(1);\n const followed = innerHeight + scrollY >= document.body.scrollHeight - 80;\n const copying = { command: state.copied, label: state.label, onCopy: copy };\n const now = new Date().toISOString();\n const observationNow = model === null ? now : new Date(Date.parse(model.updatedAt) + performance.now() - state.receivedAt).toISOString();\n const columns = columnControls(model, selected);\n const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));\n const phone = model === null ? undefined : phoneControls(now);\n const page = component(Page, { model, selected, now, observationNow, stale, copying, columns, cards, phone });\n render(page, document.getElementById(\"app\"));\n if (model === null) return;\n document.title = watchTitle(model, selected);\n const { runId } = watchLocation(selected);\n moved(model.runs.find((run) => run.runId === runId)?.state ?? \"\", followed);\n}\nasync function withSelectedRun(model) {\n const { runId } = watchLocation(location.hash);\n if (runId === null || model.runs.some((run) => run.runId === runId)) return model;\n const detail = await fetch(\"data.json?runId=\" + encodeURIComponent(runId), { cache: \"no-store\" });\n if (detail.status === 404) return model;\n if (!detail.ok) throw new Error(\"watch-run-not-available\");\n const { run } = await detail.json();\n if (run?.runId !== runId) throw new Error(\"watch-run-mismatch\");\n return { ...model, runs: [...model.runs, run] };\n}\nasync function load() {\n state.again = state.loading;\n if (state.loading) return;\n state.loading = true;\n try {\n const reply = await fetch(\"data.json\", { cache: \"no-store\" });\n if (!reply.ok) throw new Error(\"watch-not-available\");\n const model = await reply.json();\n const receivedAt = performance.now();\n state.model = await withSelectedRun(model);\n state.receivedAt = receivedAt;\n state.stale = false;\n } catch {\n state.stale = true;\n }\n state.loading = false;\n draw();\n if (state.again) load();\n}\nfunction listen() {\n const source = new EventSource(\"events\");\n source.onmessage = () => { load(); };\n source.onerror = () => { state.stale = true; draw(); };\n}\naddEventListener(\"keydown\", (event) => {\n if (event.key !== String.fromCharCode(92) || event.defaultPrevented || event.repeat || event.isComposing) return;\n if (event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) return;\n if (event.target?.closest?.(\"input, textarea, select, [contenteditable]\")) return;\n const target = state.hovered ?? state.focused;\n if (target === null || watchLocation(location.hash).runId !== null) return;\n const controls = columnControls(state.model, location.hash);\n if (controls === undefined) return;\n event.preventDefault();\n controls.onToggle(target);\n});\naddEventListener(\"hashchange\", () => { state.run = \"\"; state.hovered = null; state.focused = null; draw(); load(); });\ndraw();\nlisten();\nsetInterval(draw, 1000);\nsetInterval(load, 15000);\nif (actionToken !== null) {\n phoneLoad();\n setInterval(phoneLoad, 2000);\n}\n";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const watchClient = `
|
|
2
|
-
const state = { model: null, receivedAt: 0, stale: false, copied: "", label: "", run: "", loading: false, again: false, columns: {}, cards: {},
|
|
2
|
+
const state = { model: null, receivedAt: 0, stale: false, copied: "", label: "", run: "", loading: false, again: false, columns: {}, cards: {}, hovered: null, focused: null, phonePairing: null, phoneBusy: false, phoneMessage: "", phone: null, phoneLoadedAt: 0, phoneAccepted: null, phoneSequence: 0, phoneApplied: 0 };
|
|
3
3
|
function readPreference(key) {
|
|
4
4
|
try { return JSON.parse(localStorage.getItem(key)); }
|
|
5
5
|
catch { return null; }
|
|
@@ -13,14 +13,6 @@ function savePreference(key, value) {
|
|
|
13
13
|
try { localStorage.setItem(key, JSON.stringify(value)); }
|
|
14
14
|
catch {}
|
|
15
15
|
}
|
|
16
|
-
function startControls() {
|
|
17
|
-
if (state.start === null) state.start = readPreference("cloving.watch.start") === true;
|
|
18
|
-
return { shown: state.start, onToggle() {
|
|
19
|
-
state.start = !state.start;
|
|
20
|
-
savePreference("cloving.watch.start", state.start);
|
|
21
|
-
draw();
|
|
22
|
-
} };
|
|
23
|
-
}
|
|
24
16
|
function columnControls(model, selected) {
|
|
25
17
|
const workflowId = model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId);
|
|
26
18
|
if (workflowId === null) return undefined;
|
|
@@ -60,10 +52,9 @@ function draw() {
|
|
|
60
52
|
const now = new Date().toISOString();
|
|
61
53
|
const observationNow = model === null ? now : new Date(Date.parse(model.updatedAt) + performance.now() - state.receivedAt).toISOString();
|
|
62
54
|
const columns = columnControls(model, selected);
|
|
63
|
-
const start = model === null ? undefined : startControls();
|
|
64
55
|
const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));
|
|
65
56
|
const phone = model === null ? undefined : phoneControls(now);
|
|
66
|
-
const page = component(Page, { model, selected, now, observationNow, stale, copying, columns,
|
|
57
|
+
const page = component(Page, { model, selected, now, observationNow, stale, copying, columns, cards, phone });
|
|
67
58
|
render(page, document.getElementById("app"));
|
|
68
59
|
if (model === null) return;
|
|
69
60
|
document.title = watchTitle(model, selected);
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { type PhoneControls } from "./watch-phone-view.ts";
|
|
2
2
|
import { type Shown } from "./watch-element.ts";
|
|
3
3
|
import { type WatchModel } from "./watch-render.ts";
|
|
4
|
-
export interface StartControls {
|
|
5
|
-
readonly shown: boolean;
|
|
6
|
-
readonly onToggle: () => void;
|
|
7
|
-
}
|
|
8
4
|
export interface HeaderProps {
|
|
9
5
|
readonly model: WatchModel | null;
|
|
10
6
|
readonly stale: boolean;
|
|
11
|
-
readonly start?: StartControls;
|
|
12
7
|
readonly phone?: PhoneControls | undefined;
|
|
13
8
|
readonly now?: string;
|
|
14
9
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { queueSpendLines } from "./usage-render.js";
|
|
1
2
|
import { record } from "../protocol.js";
|
|
2
3
|
import { PhonePanel } from "./watch-phone-view.js";
|
|
3
4
|
import { component, element } from "./watch-element.js";
|
|
@@ -73,6 +74,7 @@ export function HeaderStatus(props) {
|
|
|
73
74
|
class: "header-status",
|
|
74
75
|
children: [
|
|
75
76
|
stamp,
|
|
77
|
+
...queueSpendLines(model?.queue?.["spend"]).map((line) => element("span", { class: "queue-spend", children: line })),
|
|
76
78
|
lanes === null
|
|
77
79
|
? null
|
|
78
80
|
: element("span", { class: "queue-lanes", children: lanes }),
|
|
@@ -80,29 +82,15 @@ export function HeaderStatus(props) {
|
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
export function HeaderActions(props) {
|
|
83
|
-
const {
|
|
84
|
-
if (
|
|
85
|
+
const { phone } = props;
|
|
86
|
+
if (phone === undefined)
|
|
85
87
|
return null;
|
|
86
88
|
return element("div", {
|
|
87
89
|
class: "header-actions",
|
|
88
|
-
children:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
],
|
|
90
|
+
children: component(PhonePanel, {
|
|
91
|
+
phone,
|
|
92
|
+
now: props.now ?? props.model?.updatedAt ?? "",
|
|
93
|
+
}),
|
|
106
94
|
});
|
|
107
95
|
}
|
|
108
96
|
export function Header(props) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ShownSchedules } from "./schedule-render.ts";
|
|
1
2
|
import type { WorkflowStages } from "../workflow-declaration.ts";
|
|
2
3
|
import { type WorkflowRefusal } from "../workflow-refusals.ts";
|
|
3
4
|
import type { WatchDecision, WatchItem, WatchModel, WatchTurn } from "./watch-render.ts";
|
|
@@ -6,16 +7,18 @@ export type { GithubRecords } from "./watch-pull-request.ts";
|
|
|
6
7
|
import { type PrRepository } from "./watch-pr-identity.ts";
|
|
7
8
|
type Fields = Readonly<Record<string, unknown>>;
|
|
8
9
|
export declare function activityOf(line: string): WatchItem[];
|
|
10
|
+
export declare function turnActivity(lines: readonly string[]): WatchItem[];
|
|
9
11
|
export interface TurnRecords {
|
|
10
12
|
readonly key: string;
|
|
11
13
|
readonly started: unknown;
|
|
12
14
|
readonly result: unknown;
|
|
13
|
-
readonly
|
|
15
|
+
readonly activity: readonly WatchItem[];
|
|
14
16
|
readonly activeAt?: string | null;
|
|
15
17
|
}
|
|
16
18
|
export declare function turnOf(records: TurnRecords): WatchTurn;
|
|
17
19
|
export declare function decisionCommands(decision: unknown, client: string): WatchDecision;
|
|
18
20
|
export interface WatchInputs {
|
|
21
|
+
readonly schedules?: ShownSchedules;
|
|
19
22
|
readonly queue?: Fields;
|
|
20
23
|
readonly repository?: PrRepository | null;
|
|
21
24
|
readonly workflows: readonly string[];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { shownScheduled } from "./schedule-render.js";
|
|
2
|
+
import { shownCommandWaits } from "./command-waits.js";
|
|
1
3
|
import { operationalDecision } from "../decision-visibility.js";
|
|
2
4
|
import { workflowRefusals, } from "../workflow-refusals.js";
|
|
3
5
|
import { isTicketStatus } from "../ticket-status.js";
|
|
@@ -89,6 +91,9 @@ export function activityOf(line) {
|
|
|
89
91
|
return parts(value).flatMap(failed);
|
|
90
92
|
return value["type"] === "result" ? ended(value) : [];
|
|
91
93
|
}
|
|
94
|
+
export function turnActivity(lines) {
|
|
95
|
+
return lines.flatMap(activityOf).slice(-activityLimit - 1);
|
|
96
|
+
}
|
|
92
97
|
function concise(items) {
|
|
93
98
|
return items.map((item, index) => {
|
|
94
99
|
const before = items[index - 1];
|
|
@@ -135,8 +140,7 @@ export function turnOf(records) {
|
|
|
135
140
|
outcome: records.result === null ? "in work" : outcome,
|
|
136
141
|
costUsd: priceOf(report["costUsd"]),
|
|
137
142
|
estimatedCostUsd: priceOf(report["estimatedCostUsd"]),
|
|
138
|
-
activity: records.
|
|
139
|
-
.flatMap(activityOf)
|
|
143
|
+
activity: records.activity
|
|
140
144
|
.map((item) => item.kind === "result"
|
|
141
145
|
? {
|
|
142
146
|
kind: item.kind,
|
|
@@ -203,14 +207,15 @@ function runOf(inputs, value) {
|
|
|
203
207
|
const runId = text(status["runId"]);
|
|
204
208
|
const workflowId = text(status["workflowId"]);
|
|
205
209
|
const budget = record(status["budget"]);
|
|
210
|
+
const pull = pullOf({ records: inputs.githubRecords, repository: inputs.repository ?? null }, runId);
|
|
206
211
|
const ticketId = text(status["ticketId"]);
|
|
207
|
-
const issue =
|
|
208
|
-
? establishedIssue(inputs.repository ?? null, status["issueIdentity"])
|
|
209
|
-
: null;
|
|
212
|
+
const issue = establishedIssue(inputs.repository ?? null, status["issueIdentity"]);
|
|
210
213
|
return {
|
|
211
214
|
runId,
|
|
212
215
|
workflowId,
|
|
216
|
+
...shownScheduled(status["scheduled"]),
|
|
213
217
|
...runLinksOf(status),
|
|
218
|
+
commandWaits: shownCommandWaits(status["commandWaits"]),
|
|
214
219
|
ticketId: ticketId === "" ? null : ticketId,
|
|
215
220
|
...(issue === null ? {} : { issueIdentity: issue }),
|
|
216
221
|
title: stamp(status["title"]),
|
|
@@ -220,7 +225,7 @@ function runOf(inputs, value) {
|
|
|
220
225
|
estimatedCostUsd: priceOf(status["estimatedCostUsd"]),
|
|
221
226
|
usage: usageOf(status["usage"]),
|
|
222
227
|
currentStep: currentStepOf(list(record(value)["events"]), {
|
|
223
|
-
|
|
228
|
+
pullRequest: pull.pullRequest,
|
|
224
229
|
stages: stagesFor(inputs.workflowStages, workflowId),
|
|
225
230
|
}),
|
|
226
231
|
round: roundOf(list(record(value)["events"])),
|
|
@@ -237,13 +242,13 @@ function runOf(inputs, value) {
|
|
|
237
242
|
...(status["commandEffects"] === undefined
|
|
238
243
|
? {}
|
|
239
244
|
: { commandEffects: shownCommands(status["commandEffects"]) }),
|
|
240
|
-
phases: phasesOf(list(record(value)["events"]),
|
|
245
|
+
phases: phasesOf(list(record(value)["events"]), {
|
|
246
|
+
pullRequest: pull.pullRequest,
|
|
247
|
+
stages: stagesFor(inputs.workflowStages, workflowId),
|
|
248
|
+
}),
|
|
241
249
|
decision: decisionOf(list(record(value)["events"])),
|
|
242
250
|
feedback: list(status["feedback"]).map(feedbackOf),
|
|
243
|
-
...
|
|
244
|
-
records: inputs.githubRecords,
|
|
245
|
-
repository: workflowId === "develop-issue" ? (inputs.repository ?? null) : null,
|
|
246
|
-
}, runId),
|
|
251
|
+
...pull,
|
|
247
252
|
};
|
|
248
253
|
}
|
|
249
254
|
function began(run) {
|
|
@@ -258,6 +263,7 @@ export function watchModel(inputs) {
|
|
|
258
263
|
const workflows = boardsOf({ ...inputs, completionCandidates: candidates }, runs);
|
|
259
264
|
return {
|
|
260
265
|
workflows,
|
|
266
|
+
...(inputs.schedules === undefined ? {} : { schedules: inputs.schedules }),
|
|
261
267
|
...(inputs.queue === undefined ? {} : { queue: inputs.queue }),
|
|
262
268
|
workflowRefusals: workflowRefusals(inputs.workflowRefusals),
|
|
263
269
|
startWorkflowId: startWorkflowOf(workflows),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { scheduleStatusLine, scheduledText, shownScheduled, } from "./schedule-render.js";
|
|
2
|
+
import * as waitDisplay from "./command-waits.js";
|
|
1
3
|
import { cardReply } from "./watch-card-reply.js";
|
|
2
4
|
import { record } from "../protocol.js";
|
|
3
5
|
import { Commands, commandText } from "./command-effects.js";
|
|
@@ -7,8 +9,7 @@ import { watchClient } from "./watch-client.js";
|
|
|
7
9
|
import { watchPhoneClient } from "./watch-phone-client.js";
|
|
8
10
|
import { PhoneAsk, PhoneCode, PhoneList, PhonePanel, phoneButton, phoneNotices, refusalText, timeLeft, } from "./watch-phone-view.js";
|
|
9
11
|
import { priceOf, tokenCount, usageOf } from "../worker-usage.js";
|
|
10
|
-
import { priceText, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
|
|
11
|
-
import { startPrompts, StartCard, StartRun } from "./watch-start-view.js";
|
|
12
|
+
import { priceText, queueSpendLines, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
|
|
12
13
|
import { Board, boardSizing, Card, HandoffLinks, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, observationText, staleObservation, } from "./watch-board-view.js";
|
|
13
14
|
import { boardWorkflow, watchHash, watchLocation, watchTitle, } from "./watch-navigation.js";
|
|
14
15
|
import { clockTime, completedDetail, counted, elapsed, groupActivity, pageTitle, phaseTime, runName, runTone, selectedRun, toneOf, turnTime, waitingDetail, } from "./watch-render.js";
|
|
@@ -16,9 +17,15 @@ import { Command, Decision, Events, Group, Item, Turn, Work, } from "./watch-tur
|
|
|
16
17
|
import { Banner, BannerDetail, BoardPage, Page, Phases, PullRequest, Review, RefusedWorkflows, Run, } from "./watch-view.js";
|
|
17
18
|
import { Brand, clove, Header, HeaderActions, HeaderStatus, Queue, queueLanes, skippedText, } from "./watch-header-view.js";
|
|
18
19
|
const functions = [
|
|
20
|
+
scheduleStatusLine,
|
|
21
|
+
scheduledText,
|
|
22
|
+
shownScheduled,
|
|
19
23
|
record,
|
|
20
24
|
commandText,
|
|
21
25
|
Commands,
|
|
26
|
+
waitDisplay.CommandWaits,
|
|
27
|
+
waitDisplay.commandWaitText,
|
|
28
|
+
waitDisplay.effectBudgetText,
|
|
22
29
|
queueLanes,
|
|
23
30
|
skippedText,
|
|
24
31
|
Queue,
|
|
@@ -34,6 +41,7 @@ const functions = [
|
|
|
34
41
|
tokenCount,
|
|
35
42
|
usageOf,
|
|
36
43
|
priceText,
|
|
44
|
+
queueSpendLines,
|
|
37
45
|
usageText,
|
|
38
46
|
attemptText,
|
|
39
47
|
totalsSuffix,
|
|
@@ -73,9 +81,6 @@ const functions = [
|
|
|
73
81
|
Command,
|
|
74
82
|
Decision,
|
|
75
83
|
Events,
|
|
76
|
-
startPrompts,
|
|
77
|
-
StartCard,
|
|
78
|
-
StartRun,
|
|
79
84
|
BannerDetail,
|
|
80
85
|
Banner,
|
|
81
86
|
Phases,
|
|
@@ -146,7 +151,6 @@ body { margin: 0 auto; max-width: 1800px; padding: 0 20px 96px; }
|
|
|
146
151
|
body:has(.board-page) { padding-bottom: 0; overflow: hidden; }
|
|
147
152
|
.board-page { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
|
|
148
153
|
.board-page > header, .board-page > .down { flex-shrink: 0; }
|
|
149
|
-
.start-run { flex-shrink: 0; max-height: 45dvh; overflow-y: auto; }
|
|
150
154
|
.workflow-refusals { flex-shrink: 0; max-height: 25dvh; overflow-y: auto; overflow-wrap: anywhere; }
|
|
151
155
|
.workflow-refusals h2 { margin: 8px 0; }
|
|
152
156
|
a { color: var(--accent-strong); }
|
|
@@ -168,12 +172,6 @@ header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; padding
|
|
|
168
172
|
.brand svg { width: 30px; height: 30px; color: var(--accent); }
|
|
169
173
|
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); }
|
|
170
174
|
h2, h3 { font-family: var(--heading-font); font-weight: 700; }
|
|
171
|
-
.start-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); gap: 16px; margin-top: 12px; }
|
|
172
|
-
.start-card { min-width: 0; padding: 14px; border-radius: 14px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
|
|
173
|
-
.start-card h3 { margin: 0; }
|
|
174
|
-
.start-card p { margin: 6px 0 12px; }
|
|
175
|
-
.start-card .command { grid-template-columns: minmax(0, 1fr); margin: 0; }
|
|
176
|
-
.start-card button { justify-self: end; }
|
|
177
175
|
.workspace { display: flex; width: 100%; margin-top: 12px; flex: 1; min-height: 0; }
|
|
178
176
|
.workflows { display: flex; flex-direction: row; flex-shrink: 0; gap: 8px; min-width: 0; margin-top: 12px; padding: 6px; overflow-x: auto; overflow-y: hidden; }
|
|
179
177
|
.workflows a { display: grid; flex-shrink: 0; white-space: nowrap; gap: 2px; border-bottom: 3px solid transparent; padding: 10px; color: inherit; text-decoration: none; }
|
|
@@ -192,8 +190,8 @@ h2, h3 { font-family: var(--heading-font); font-weight: 700; }
|
|
|
192
190
|
.column-cards { min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
|
|
193
191
|
.column.collapsed { flex: 0 0 ${String(boardSizing.collapsedColumnWidth)}px; min-width: ${String(boardSizing.collapsedColumnWidth)}px; padding: 6px; }
|
|
194
192
|
.collapsed .column-name { writing-mode: vertical-rl; padding: 0; }
|
|
195
|
-
header button, .phone button, .column-name button, .add-card, .add-card-form button
|
|
196
|
-
header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover
|
|
193
|
+
header button, .phone button, .column-name button, .add-card, .add-card-form 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; }
|
|
194
|
+
header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover { background: var(--surface-2); }
|
|
197
195
|
.add-card, .add-card-form button { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 4px 8px 4px 0; }
|
|
198
196
|
.add-card { width: 100%; text-align: left; margin: 4px 0; }
|
|
199
197
|
.add-card-form { padding: 8px 0; overflow-wrap: anywhere; }
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { WorkflowStage } from "../workflow-declaration.ts";
|
|
2
|
+
import type { WatchPhase, WatchPullRequest } from "./watch-render.ts";
|
|
3
|
+
export declare const pullRequestSteps: {
|
|
3
4
|
name: string;
|
|
4
5
|
operation: string;
|
|
5
6
|
}[];
|
|
6
7
|
export declare function decisionOf(events: readonly unknown[]): string;
|
|
7
|
-
export declare function
|
|
8
|
+
export declare function pullRequestStepOf(event: unknown): {
|
|
9
|
+
name: string;
|
|
10
|
+
operation: string;
|
|
11
|
+
} | undefined;
|
|
12
|
+
export declare function stageOf(event: unknown, stages: readonly WorkflowStage[]): WorkflowStage | undefined;
|
|
13
|
+
export declare function phasesOf(events: readonly unknown[], workflow?: {
|
|
14
|
+
readonly pullRequest?: WatchPullRequest | null;
|
|
15
|
+
readonly stages?: readonly WorkflowStage[] | undefined;
|
|
16
|
+
}): WatchPhase[];
|