cloving 0.3.20 → 1.1.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/{LICENSE.md → LICENSE} +1 -1
- package/README.md +606 -182
- package/dist/src/authority/budgets.d.ts +12 -0
- package/dist/src/authority/budgets.js +42 -0
- package/dist/src/authority/commands.d.ts +7 -0
- package/dist/src/authority/commands.js +271 -0
- package/dist/src/authority/details.d.ts +28 -0
- package/dist/src/authority/details.js +33 -0
- package/dist/src/authority/dispatch-decision.d.ts +40 -0
- package/dist/src/authority/dispatch-decision.js +47 -0
- package/dist/src/authority/effect-requests.d.ts +2 -0
- package/dist/src/authority/effect-requests.js +139 -0
- package/dist/src/authority/effect-results.d.ts +4 -0
- package/dist/src/authority/effect-results.js +236 -0
- package/dist/src/authority/events.d.ts +2 -0
- package/dist/src/authority/events.js +45 -0
- package/dist/src/authority/gate-reduction.d.ts +8 -0
- package/dist/src/authority/gate-reduction.js +109 -0
- package/dist/src/authority/gates.d.ts +48 -0
- package/dist/src/authority/gates.js +77 -0
- package/dist/src/authority/history-state.d.ts +15 -0
- package/dist/src/authority/history-state.js +61 -0
- package/dist/src/authority/history.d.ts +13 -0
- package/dist/src/authority/history.js +37 -0
- package/dist/src/authority/instants.d.ts +3 -0
- package/dist/src/authority/instants.js +38 -0
- package/dist/src/authority/leases.d.ts +15 -0
- package/dist/src/authority/leases.js +113 -0
- package/dist/src/authority/operations.d.ts +101 -0
- package/dist/src/authority/operations.js +75 -0
- package/dist/src/authority/reconciliation.d.ts +29 -0
- package/dist/src/authority/reconciliation.js +156 -0
- package/dist/src/authority/reducer.d.ts +41 -0
- package/dist/src/authority/reducer.js +139 -0
- package/dist/src/authority/reduction-state.d.ts +36 -0
- package/dist/src/authority/reduction-state.js +68 -0
- package/dist/src/authority/reduction.d.ts +6 -0
- package/dist/src/authority/reduction.js +160 -0
- package/dist/src/authority/status-closure.d.ts +4 -0
- package/dist/src/authority/status-closure.js +57 -0
- package/dist/src/authority/status-effects.d.ts +17 -0
- package/dist/src/authority/status-effects.js +43 -0
- package/dist/src/authority/status-input.d.ts +45 -0
- package/dist/src/authority/status-input.js +9 -0
- package/dist/src/authority/status.d.ts +32 -0
- package/dist/src/authority/status.js +256 -0
- package/dist/src/authority/stop-sequence.d.ts +37 -0
- package/dist/src/authority/stop-sequence.js +91 -0
- package/dist/src/authority/transitions.d.ts +63 -0
- package/dist/src/authority/transitions.js +124 -0
- package/dist/src/broker/actor/adapter-calls.d.ts +13 -0
- package/dist/src/broker/actor/adapter-calls.js +34 -0
- package/dist/src/broker/actor/adapter-outcomes.d.ts +28 -0
- package/dist/src/broker/actor/adapter-outcomes.js +80 -0
- package/dist/src/broker/actor/authority-actor.d.ts +25 -0
- package/dist/src/broker/actor/authority-actor.js +169 -0
- package/dist/src/broker/actor/authority-changes.d.ts +31 -0
- package/dist/src/broker/actor/authority-changes.js +46 -0
- package/dist/src/broker/actor/authority-connection.d.ts +15 -0
- package/dist/src/broker/actor/authority-connection.js +44 -0
- package/dist/src/broker/actor/authority-conversion.d.ts +10 -0
- package/dist/src/broker/actor/authority-conversion.js +72 -0
- package/dist/src/broker/actor/authority-delivery.d.ts +13 -0
- package/dist/src/broker/actor/authority-delivery.js +162 -0
- package/dist/src/broker/actor/authority-logger.d.ts +2 -0
- package/dist/src/broker/actor/authority-logger.js +19 -0
- package/dist/src/broker/actor/authority-policy.d.ts +9 -0
- package/dist/src/broker/actor/authority-policy.js +11 -0
- package/dist/src/broker/actor/authority-queries.d.ts +45 -0
- package/dist/src/broker/actor/authority-queries.js +85 -0
- package/dist/src/broker/actor/authority-receipts.d.ts +28 -0
- package/dist/src/broker/actor/authority-receipts.js +84 -0
- package/dist/src/broker/actor/authority-release.d.ts +13 -0
- package/dist/src/broker/actor/authority-release.js +69 -0
- package/dist/src/broker/actor/authority-runtime.d.ts +60 -0
- package/dist/src/broker/actor/authority-runtime.js +204 -0
- package/dist/src/broker/actor/authority-session.d.ts +67 -0
- package/dist/src/broker/actor/authority-session.js +251 -0
- package/dist/src/broker/actor/authority-settings.d.ts +33 -0
- package/dist/src/broker/actor/authority-settings.js +63 -0
- package/dist/src/broker/actor/authority-upgrades.d.ts +16 -0
- package/dist/src/broker/actor/authority-upgrades.js +12 -0
- package/dist/src/broker/actor/authority-watchdog.d.ts +14 -0
- package/dist/src/broker/actor/authority-watchdog.js +41 -0
- package/dist/src/broker/actor/authority.d.ts +14 -0
- package/dist/src/broker/actor/authority.js +115 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +68 -0
- package/dist/src/broker/actor/delivery-intents.js +77 -0
- package/dist/src/broker/actor/delivery-plan.d.ts +2 -0
- package/dist/src/broker/actor/delivery-plan.js +109 -0
- package/dist/src/broker/actor/delivery-results.d.ts +11 -0
- package/dist/src/broker/actor/delivery-results.js +63 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +19 -0
- package/dist/src/broker/actor/effect-delivery.js +118 -0
- package/dist/src/broker/actor/effect-plan.d.ts +41 -0
- package/dist/src/broker/actor/effect-plan.js +173 -0
- package/dist/src/broker/actor/effect-queries.d.ts +27 -0
- package/dist/src/broker/actor/effect-queries.js +80 -0
- package/dist/src/broker/actor/effect-turn.d.ts +25 -0
- package/dist/src/broker/actor/effect-turn.js +84 -0
- package/dist/src/broker/actor/pin-check.d.ts +6 -0
- package/dist/src/broker/actor/pin-check.js +12 -0
- package/dist/src/broker/actor/runtime-parts.d.ts +23 -0
- package/dist/src/broker/actor/runtime-parts.js +34 -0
- package/dist/src/broker/actor/stop-plan.d.ts +20 -0
- package/dist/src/broker/actor/stop-plan.js +46 -0
- package/dist/src/broker/actor/stop-turn.d.ts +17 -0
- package/dist/src/broker/actor/stop-turn.js +42 -0
- package/dist/src/broker/actor/turn-draft.d.ts +31 -0
- package/dist/src/broker/actor/turn-draft.js +138 -0
- package/dist/src/broker/actor/turn-plan.d.ts +17 -0
- package/dist/src/broker/actor/turn-plan.js +136 -0
- package/dist/src/broker/actor/turn-refusals.d.ts +8 -0
- package/dist/src/broker/actor/turn-refusals.js +35 -0
- package/dist/src/broker/actor/turn-staging.d.ts +78 -0
- package/dist/src/broker/actor/turn-staging.js +34 -0
- package/dist/src/broker/actor/turn-state.d.ts +34 -0
- package/dist/src/broker/actor/turn-state.js +208 -0
- package/dist/src/broker/authority-admission.d.ts +21 -0
- package/dist/src/broker/authority-admission.js +70 -0
- package/dist/src/broker/authority-restore.d.ts +30 -0
- package/dist/src/broker/authority-restore.js +165 -0
- package/dist/src/broker/decision-restore.d.ts +16 -0
- package/dist/src/broker/decision-restore.js +158 -0
- package/dist/src/broker/decision-upgrade.d.ts +3 -0
- package/dist/src/broker/decision-upgrade.js +12 -0
- package/dist/src/broker/effect-restore.d.ts +20 -0
- package/dist/src/broker/effect-restore.js +111 -0
- package/dist/src/broker/effect-upgrade.d.ts +3 -0
- package/dist/src/broker/effect-upgrade.js +9 -0
- package/dist/src/broker/operation-digest.d.ts +1 -0
- package/dist/src/broker/operation-digest.js +4 -0
- package/dist/src/broker/socket-address.d.ts +9 -0
- package/dist/src/broker/socket-address.js +14 -0
- package/dist/src/broker/workflow-pin.d.ts +2 -0
- package/dist/src/broker/workflow-pin.js +5 -0
- package/dist/src/chats/analysis-batches.d.ts +24 -0
- package/dist/src/chats/analysis-batches.js +83 -0
- package/dist/src/chats/analysis-contract.d.ts +80 -0
- package/dist/src/chats/analysis-contract.js +16 -0
- package/dist/src/chats/analysis-data.d.ts +3 -0
- package/dist/src/chats/analysis-data.js +85 -0
- package/dist/src/chats/analysis-input.d.ts +12 -0
- package/dist/src/chats/analysis-input.js +83 -0
- package/dist/src/chats/analysis-links.d.ts +2 -0
- package/dist/src/chats/analysis-links.js +25 -0
- package/dist/src/chats/analysis-prompt.d.ts +10 -0
- package/dist/src/chats/analysis-prompt.js +16 -0
- package/dist/src/chats/analysis-proposal.d.ts +2 -0
- package/dist/src/chats/analysis-proposal.js +32 -0
- package/dist/src/chats/analysis-provenance.d.ts +4 -0
- package/dist/src/chats/analysis-provenance.js +99 -0
- package/dist/src/chats/analysis-shape.d.ts +3 -0
- package/dist/src/chats/analysis-shape.js +228 -0
- package/dist/src/chats/analysis.d.ts +3 -0
- package/dist/src/chats/analysis.js +42 -0
- package/dist/src/chats/corpus-input.d.ts +5 -0
- package/dist/src/chats/corpus-input.js +288 -0
- package/dist/src/chats/destination.d.ts +4 -0
- package/dist/src/chats/destination.js +96 -0
- package/dist/src/chats/import.d.ts +15 -0
- package/dist/src/chats/import.js +243 -0
- package/dist/src/chats/input-file.d.ts +3 -0
- package/dist/src/chats/input-file.js +32 -0
- package/dist/src/chats/normalize.d.ts +29 -0
- package/dist/src/chats/normalize.js +155 -0
- package/dist/src/chats/previous-import.d.ts +5 -0
- package/dist/src/chats/previous-import.js +34 -0
- package/dist/src/chats/reader.d.ts +21 -0
- package/dist/src/chats/reader.js +118 -0
- package/dist/src/chats/redact-import.d.ts +14 -0
- package/dist/src/chats/redact-import.js +141 -0
- package/dist/src/chats/redaction.d.ts +41 -0
- package/dist/src/chats/redaction.js +161 -0
- package/dist/src/chats/revision-input.d.ts +3 -0
- package/dist/src/chats/revision-input.js +180 -0
- package/dist/src/chats/revision.d.ts +48 -0
- package/dist/src/chats/revision.js +94 -0
- package/dist/src/chats/selection.d.ts +25 -0
- package/dist/src/chats/selection.js +109 -0
- package/dist/src/chats/source.d.ts +23 -0
- package/dist/src/chats/source.js +135 -0
- package/dist/src/chats/structure.d.ts +57 -0
- package/dist/src/chats/structure.js +216 -0
- package/dist/src/cli/arguments.d.ts +31 -0
- package/dist/src/cli/arguments.js +235 -0
- package/dist/src/cli/client.d.ts +16 -0
- package/dist/src/cli/client.js +159 -0
- package/dist/src/cli/commands.d.ts +17 -0
- package/dist/src/cli/commands.js +271 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +127 -0
- package/dist/src/cli/render.d.ts +10 -0
- package/dist/src/cli/render.js +254 -0
- package/dist/src/cli/runtime-arguments.d.ts +73 -0
- package/dist/src/cli/runtime-arguments.js +248 -0
- package/dist/src/cli/runtime-directory.d.ts +4 -0
- package/dist/src/cli/runtime-directory.js +25 -0
- package/dist/src/cli/toolchain.d.ts +3 -0
- package/dist/src/cli/toolchain.js +74 -0
- package/dist/src/cli/usage-render.d.ts +3 -0
- package/dist/src/cli/usage-render.js +28 -0
- package/dist/src/cli/usage.d.ts +5 -0
- package/dist/src/cli/usage.js +156 -0
- package/dist/src/cli/validate.d.ts +38 -0
- package/dist/src/cli/validate.js +116 -0
- package/dist/src/cli/watch-actions.d.ts +10 -0
- package/dist/src/cli/watch-actions.js +58 -0
- package/dist/src/cli/watch-board-view.d.ts +54 -0
- package/dist/src/cli/watch-board-view.js +201 -0
- package/dist/src/cli/watch-board.d.ts +15 -0
- package/dist/src/cli/watch-board.js +179 -0
- package/dist/src/cli/watch-card-client.d.ts +1 -0
- package/dist/src/cli/watch-card-client.js +44 -0
- package/dist/src/cli/watch-card-forms.d.ts +2 -0
- package/dist/src/cli/watch-card-forms.js +33 -0
- package/dist/src/cli/watch-card-reply.d.ts +5 -0
- package/dist/src/cli/watch-card-reply.js +34 -0
- package/dist/src/cli/watch-card-view.d.ts +40 -0
- package/dist/src/cli/watch-card-view.js +86 -0
- package/dist/src/cli/watch-client.d.ts +1 -0
- package/dist/src/cli/watch-client.js +118 -0
- package/dist/src/cli/watch-element.d.ts +11 -0
- package/dist/src/cli/watch-element.js +6 -0
- package/dist/src/cli/watch-model.d.ts +29 -0
- package/dist/src/cli/watch-model.js +278 -0
- package/dist/src/cli/watch-navigation.d.ts +9 -0
- package/dist/src/cli/watch-navigation.js +40 -0
- package/dist/src/cli/watch-page.d.ts +1 -0
- package/dist/src/cli/watch-page.js +258 -0
- package/dist/src/cli/watch-paths.d.ts +2 -0
- package/dist/src/cli/watch-paths.js +52 -0
- package/dist/src/cli/watch-phases.d.ts +7 -0
- package/dist/src/cli/watch-phases.js +148 -0
- package/dist/src/cli/watch-pr-board.d.ts +3 -0
- package/dist/src/cli/watch-pr-board.js +26 -0
- package/dist/src/cli/watch-pr-command.d.ts +15 -0
- package/dist/src/cli/watch-pr-command.js +37 -0
- package/dist/src/cli/watch-pr-identity.d.ts +20 -0
- package/dist/src/cli/watch-pr-identity.js +62 -0
- package/dist/src/cli/watch-pr-observer.d.ts +19 -0
- package/dist/src/cli/watch-pr-observer.js +108 -0
- package/dist/src/cli/watch-pr-settings.d.ts +8 -0
- package/dist/src/cli/watch-pr-settings.js +47 -0
- package/dist/src/cli/watch-reads.d.ts +28 -0
- package/dist/src/cli/watch-reads.js +248 -0
- package/dist/src/cli/watch-render.d.ts +153 -0
- package/dist/src/cli/watch-render.js +102 -0
- package/dist/src/cli/watch-run-input.d.ts +14 -0
- package/dist/src/cli/watch-run-input.js +49 -0
- package/dist/src/cli/watch-server.d.ts +13 -0
- package/dist/src/cli/watch-server.js +214 -0
- package/dist/src/cli/watch-start-view.d.ts +18 -0
- package/dist/src/cli/watch-start-view.js +77 -0
- package/dist/src/cli/watch-stream.d.ts +11 -0
- package/dist/src/cli/watch-stream.js +128 -0
- package/dist/src/cli/watch-turn.d.ts +30 -0
- package/dist/src/cli/watch-turn.js +135 -0
- package/dist/src/cli/watch-usage.d.ts +6 -0
- package/dist/src/cli/watch-usage.js +65 -0
- package/dist/src/cli/watch-view.d.ts +54 -0
- package/dist/src/cli/watch-view.js +267 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +104 -0
- package/dist/src/daemon/analysis-launch.d.ts +5 -0
- package/dist/src/daemon/analysis-launch.js +81 -0
- package/dist/src/daemon/analysis-token.d.ts +6 -0
- package/dist/src/daemon/analysis-token.js +88 -0
- package/dist/src/daemon/analysis-worker.d.ts +22 -0
- package/dist/src/daemon/analysis-worker.js +219 -0
- package/dist/src/daemon/chats-files.d.ts +15 -0
- package/dist/src/daemon/chats-files.js +113 -0
- package/dist/src/daemon/chats-worker.d.ts +12 -0
- package/dist/src/daemon/chats-worker.js +200 -0
- package/dist/src/daemon/claude-turn.d.ts +38 -0
- package/dist/src/daemon/claude-turn.js +216 -0
- package/dist/src/daemon/claude-worker.d.ts +29 -0
- package/dist/src/daemon/claude-worker.js +276 -0
- package/dist/src/daemon/codex-stream.d.ts +4 -0
- package/dist/src/daemon/codex-stream.js +129 -0
- package/dist/src/daemon/daemon.d.ts +49 -0
- package/dist/src/daemon/daemon.js +195 -0
- package/dist/src/daemon/delivery-router.d.ts +10 -0
- package/dist/src/daemon/delivery-router.js +34 -0
- package/dist/src/daemon/github-calls.d.ts +29 -0
- package/dist/src/daemon/github-calls.js +127 -0
- package/dist/src/daemon/github-issue-methods.d.ts +3 -0
- package/dist/src/daemon/github-issue-methods.js +99 -0
- package/dist/src/daemon/github-issue-privacy.d.ts +6 -0
- package/dist/src/daemon/github-issue-privacy.js +131 -0
- package/dist/src/daemon/github-merge.d.ts +18 -0
- package/dist/src/daemon/github-merge.js +259 -0
- package/dist/src/daemon/github-methods.d.ts +5 -0
- package/dist/src/daemon/github-methods.js +202 -0
- package/dist/src/daemon/github-operation.d.ts +38 -0
- package/dist/src/daemon/github-operation.js +57 -0
- package/dist/src/daemon/github-ticket-status.d.ts +3 -0
- package/dist/src/daemon/github-ticket-status.js +268 -0
- package/dist/src/daemon/github-worker.d.ts +17 -0
- package/dist/src/daemon/github-worker.js +281 -0
- package/dist/src/daemon/host-environment.d.ts +8 -0
- package/dist/src/daemon/host-environment.js +14 -0
- package/dist/src/daemon/issue-queue.d.ts +10 -0
- package/dist/src/daemon/issue-queue.js +254 -0
- package/dist/src/daemon/notify-message.d.ts +14 -0
- package/dist/src/daemon/notify-message.js +48 -0
- package/dist/src/daemon/notify.d.ts +12 -0
- package/dist/src/daemon/notify.js +161 -0
- package/dist/src/daemon/operation-journal.d.ts +43 -0
- package/dist/src/daemon/operation-journal.js +55 -0
- package/dist/src/daemon/retrying-turn.d.ts +9 -0
- package/dist/src/daemon/retrying-turn.js +185 -0
- package/dist/src/daemon/ticket-registration.d.ts +33 -0
- package/dist/src/daemon/ticket-registration.js +177 -0
- package/dist/src/daemon/ticket-source.d.ts +17 -0
- package/dist/src/daemon/ticket-source.js +36 -0
- package/dist/src/daemon/work-tree.d.ts +26 -0
- package/dist/src/daemon/work-tree.js +206 -0
- package/dist/src/effect-authorization.d.ts +21 -0
- package/dist/src/effect-authorization.js +14 -0
- package/dist/src/execution-pin.d.ts +4 -0
- package/dist/src/execution-pin.js +68 -0
- package/dist/src/host/start-delivery.d.ts +41 -0
- package/dist/src/host/start-delivery.js +68 -0
- package/dist/src/host/step-bridge-host.d.ts +79 -0
- package/dist/src/host/step-bridge-host.js +205 -0
- package/dist/src/host/step-claims.d.ts +31 -0
- package/dist/src/host/step-claims.js +85 -0
- package/dist/src/host/world-host.d.ts +21 -0
- package/dist/src/host/world-host.js +51 -0
- package/dist/src/host/world-reconciliation.d.ts +39 -0
- package/dist/src/host/world-reconciliation.js +81 -0
- package/dist/src/host/world-runs.d.ts +14 -0
- package/dist/src/host/world-runs.js +69 -0
- package/dist/src/operation-identity.d.ts +7 -0
- package/dist/src/operation-identity.js +59 -0
- package/dist/src/protocol.d.ts +35 -0
- package/dist/src/protocol.js +64 -0
- package/dist/src/resource-files.d.ts +1 -0
- package/dist/src/resource-files.js +29 -0
- package/dist/src/service/changes.d.ts +11 -0
- package/dist/src/service/changes.js +32 -0
- package/dist/src/service/decision-handler.d.ts +9 -0
- package/dist/src/service/decision-handler.js +233 -0
- package/dist/src/service/event-handler.d.ts +10 -0
- package/dist/src/service/event-handler.js +70 -0
- package/dist/src/service/expiry.d.ts +13 -0
- package/dist/src/service/expiry.js +53 -0
- package/dist/src/service/gateway.d.ts +21 -0
- package/dist/src/service/gateway.js +120 -0
- package/dist/src/service/registry.d.ts +40 -0
- package/dist/src/service/registry.js +13 -0
- package/dist/src/service/replies.d.ts +26 -0
- package/dist/src/service/replies.js +56 -0
- package/dist/src/service/run-handlers.d.ts +4 -0
- package/dist/src/service/run-handlers.js +263 -0
- package/dist/src/service/service.d.ts +58 -0
- package/dist/src/service/service.js +212 -0
- package/dist/src/service/submission-handler.d.ts +4 -0
- package/dist/src/service/submission-handler.js +206 -0
- package/dist/src/service/transport.d.ts +16 -0
- package/dist/src/service/transport.js +141 -0
- package/dist/src/service/worker-port.d.ts +85 -0
- package/dist/src/service/worker-port.js +126 -0
- package/dist/src/service/worker-totals.d.ts +3 -0
- package/dist/src/service/worker-totals.js +28 -0
- package/dist/src/step-bridge.d.ts +57 -0
- package/dist/src/step-bridge.js +4 -0
- package/dist/src/steps/decision-gate.d.ts +2 -0
- package/dist/src/steps/decision-gate.js +8 -0
- package/dist/src/steps/load-cycle.d.ts +10 -0
- package/dist/src/steps/load-cycle.js +11 -0
- package/dist/src/steps/protected-effect.d.ts +2 -0
- package/dist/src/steps/protected-effect.js +8 -0
- package/dist/src/storage/decision-rows.d.ts +54 -0
- package/dist/src/storage/decision-rows.js +72 -0
- package/dist/src/storage/decision-snapshots.d.ts +17 -0
- package/dist/src/storage/decision-snapshots.js +25 -0
- package/dist/src/storage/domain-changes.d.ts +48 -0
- package/dist/src/storage/domain-changes.js +213 -0
- package/dist/src/storage/domain-rows.d.ts +85 -0
- package/dist/src/storage/domain-rows.js +129 -0
- package/dist/src/storage/domain-schema.d.ts +32 -0
- package/dist/src/storage/domain-schema.js +193 -0
- package/dist/src/storage/effect-changes.d.ts +5 -0
- package/dist/src/storage/effect-changes.js +105 -0
- package/dist/src/storage/effect-rows.d.ts +67 -0
- package/dist/src/storage/effect-rows.js +74 -0
- package/dist/src/storage/effect-schema.d.ts +1 -0
- package/dist/src/storage/effect-schema.js +59 -0
- package/dist/src/storage/statements.d.ts +9 -0
- package/dist/src/storage/statements.js +8 -0
- package/dist/src/submission.d.ts +42 -0
- package/dist/src/submission.js +71 -0
- package/dist/src/ticket-status.d.ts +8 -0
- package/dist/src/ticket-status.js +45 -0
- package/dist/src/token-prices.d.ts +19 -0
- package/dist/src/token-prices.js +76 -0
- package/dist/src/turn-profile.d.ts +13 -0
- package/dist/src/turn-profile.js +100 -0
- package/dist/src/worker-usage.d.ts +22 -0
- package/dist/src/worker-usage.js +44 -0
- package/dist/src/workflow-admission.d.ts +45 -0
- package/dist/src/workflow-admission.js +151 -0
- package/dist/src/workflow-candidate.d.ts +29 -0
- package/dist/src/workflow-candidate.js +59 -0
- package/dist/src/workflow-contracts.d.ts +29 -0
- package/dist/src/workflow-contracts.js +110 -0
- package/dist/src/workflow-declaration.d.ts +11 -0
- package/dist/src/workflow-declaration.js +59 -0
- package/dist/src/workflow-resources.d.ts +8 -0
- package/dist/src/workflow-resources.js +14 -0
- package/dist/src/workflows.d.ts +6 -0
- package/dist/src/workflows.js +4 -0
- package/dist/tools/compile-workflows.d.ts +1 -0
- package/dist/tools/compile-workflows.js +33 -0
- package/dist/tools/self-host-processes.d.ts +10 -0
- package/dist/tools/self-host-processes.js +156 -0
- package/dist/tools/self-host-workflows.d.ts +15 -0
- package/dist/tools/self-host-workflows.js +78 -0
- package/dist/tools/self-host.d.ts +1 -0
- package/dist/tools/self-host.js +261 -0
- package/dist/tools/self-update-host.d.ts +13 -0
- package/dist/tools/self-update-host.js +88 -0
- package/dist/tools/self-update.d.ts +11 -0
- package/dist/tools/self-update.js +177 -0
- package/dist/tools/workflow-manifest.d.ts +3 -0
- package/dist/tools/workflow-manifest.js +34 -0
- package/dist/workflows/analyze-chats.d.ts +10 -0
- package/dist/workflows/analyze-chats.declaration.json +9 -0
- package/dist/workflows/analyze-chats.js +73 -0
- package/dist/workflows/develop-prd.d.ts +7 -0
- package/dist/workflows/develop-prd.js +97 -0
- package/dist/workflows/develop-ticket.d.ts +9 -0
- package/dist/workflows/develop-ticket.js +202 -0
- package/dist/workflows/issue-labels.d.ts +16 -0
- package/dist/workflows/issue-labels.js +70 -0
- package/dist/workflows/ticket-prompts.d.ts +35 -0
- package/dist/workflows/ticket-prompts.js +133 -0
- package/package.json +84 -75
- package/dist/abstract_gpt/index.js +0 -55
- package/dist/cloving_gpt/adapters/Adapter.js +0 -2
- package/dist/cloving_gpt/adapters/azureopenai.js +0 -69
- package/dist/cloving_gpt/adapters/claude.js +0 -128
- package/dist/cloving_gpt/adapters/gemini.js +0 -135
- package/dist/cloving_gpt/adapters/gpt4all.js +0 -29
- package/dist/cloving_gpt/adapters/index.js +0 -2
- package/dist/cloving_gpt/adapters/mistral.js +0 -128
- package/dist/cloving_gpt/adapters/ollama.js +0 -128
- package/dist/cloving_gpt/adapters/openai.js +0 -100
- package/dist/cloving_gpt/index.js +0 -192
- package/dist/commands/analyze.js +0 -47
- package/dist/commands/chat.js +0 -14
- package/dist/commands/check.js +0 -7
- package/dist/commands/commit.js +0 -44
- package/dist/commands/config.js +0 -167
- package/dist/commands/describe.js +0 -235
- package/dist/commands/generate/code.js +0 -21
- package/dist/commands/generate/commit.js +0 -11
- package/dist/commands/generate/context.js +0 -82
- package/dist/commands/generate/docs.js +0 -11
- package/dist/commands/generate/documentation.js +0 -11
- package/dist/commands/generate/fizzbuzz.js +0 -35
- package/dist/commands/generate/init.js +0 -15
- package/dist/commands/generate/review.js +0 -11
- package/dist/commands/generate/sh.js +0 -95
- package/dist/commands/generate/shell.js +0 -11
- package/dist/commands/generate/unit_tests.js +0 -11
- package/dist/commands/init.js +0 -13
- package/dist/commands/models.js +0 -22
- package/dist/commands/project/build.js +0 -88
- package/dist/commands/project/complete.js +0 -12
- package/dist/commands/project/init.js +0 -82
- package/dist/commands/project/plan.js +0 -108
- package/dist/commands/proxy.js +0 -11
- package/dist/commands/review.js +0 -50
- package/dist/commands/tokens.js +0 -75
- package/dist/commands/unit_tests.js +0 -150
- package/dist/commands/update.js +0 -7
- package/dist/file2.js +0 -4
- package/dist/index.js +0 -136
- package/dist/managers/BlockManager.js +0 -120
- package/dist/managers/ChatManager.js +0 -653
- package/dist/managers/ChunkManager.js +0 -32
- package/dist/managers/CodeManager.js +0 -185
- package/dist/managers/CommitManager.js +0 -78
- package/dist/managers/DocsManager.js +0 -88
- package/dist/managers/DocumentationManager.js +0 -114
- package/dist/managers/InitManager.js +0 -230
- package/dist/managers/ProxyManager.js +0 -210
- package/dist/managers/ReviewManager.js +0 -131
- package/dist/managers/ShellManager.js +0 -163
- package/dist/managers/StreamManager.js +0 -308
- package/dist/managers/UnitTestManager.js +0 -243
- package/dist/managers/src/managers/ProxyManager.js +0 -1
- package/dist/newfile.js +0 -2
- package/dist/package.json +0 -86
- package/dist/utils/command_utils.js +0 -384
- package/dist/utils/config_utils.js +0 -249
- package/dist/utils/gitUtils.js +0 -42
- package/dist/utils/git_utils.js +0 -217
- package/dist/utils/modelUtils.js +0 -7
- package/dist/utils/model_utils.js +0 -7
- package/dist/utils/prompt_utils.js +0 -333
- package/dist/utils/prompts/CODEGEN_COULDNT_APPLY.md +0 -5
- package/dist/utils/prompts/CODEGEN_EXAMPLES.md +0 -82
- package/dist/utils/prompts/CODEGEN_INSTRUCTIONS.md +0 -43
- package/dist/utils/prompts/DOCS_INSTRUCTIONS.md +0 -9
- package/dist/utils/prompts/INIT_INSTRUCTIONS.md +0 -132
- package/dist/utils/prompts/REVIEW_INSTRUCTIONS.md +0 -49
- package/dist/utils/prompts/SHELL_INSTRUCTIONS.md +0 -15
- package/dist/utils/prompts/SPECIAL_FILES.md +0 -66
- package/dist/utils/prompts/index.js +0 -27
- package/dist/utils/string_utils.js +0 -505
- package/dist/utils/types.js +0 -2
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { AddCard } from "./watch-card-view.js";
|
|
2
|
+
import { priceText } from "./usage-render.js";
|
|
3
|
+
import { component, element } from "./watch-element.js";
|
|
4
|
+
import { watchHash } from "./watch-navigation.js";
|
|
5
|
+
export const boardSizing = {
|
|
6
|
+
minimumColumnWidth: 200,
|
|
7
|
+
collapsedColumnWidth: 44,
|
|
8
|
+
gap: 12,
|
|
9
|
+
};
|
|
10
|
+
export function boardLayout(input) {
|
|
11
|
+
const { contentWidth, openColumns, collapsedColumns } = input;
|
|
12
|
+
const fixedWidth = collapsedColumns * boardSizing.collapsedColumnWidth +
|
|
13
|
+
Math.max(0, openColumns + collapsedColumns - 1) * boardSizing.gap;
|
|
14
|
+
const columnWidth = Math.max(boardSizing.minimumColumnWidth, (contentWidth - fixedWidth) / Math.max(1, openColumns));
|
|
15
|
+
return {
|
|
16
|
+
columnWidth: openColumns === 0 ? boardSizing.minimumColumnWidth : columnWidth,
|
|
17
|
+
totalWidth: openColumns * columnWidth + fixedWidth,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function cardStep(card, now) {
|
|
21
|
+
if (card.endedAt !== null)
|
|
22
|
+
return new Date(card.endedAt).toLocaleString();
|
|
23
|
+
const step = card.currentStep;
|
|
24
|
+
if (step === null)
|
|
25
|
+
return "";
|
|
26
|
+
if (step.startedAt === null)
|
|
27
|
+
return step.name;
|
|
28
|
+
const minutes = Math.max(0, Math.floor((Date.parse(now) - Date.parse(step.startedAt)) / 60000));
|
|
29
|
+
return `${step.name} · ${String(minutes)} min`;
|
|
30
|
+
}
|
|
31
|
+
export function cardReview(card) {
|
|
32
|
+
return [
|
|
33
|
+
card.round === null ? null : `round ${String(card.round)}`,
|
|
34
|
+
card.greptileScore === null ? null : `${String(card.greptileScore)}/5`,
|
|
35
|
+
card.pullRequestNumber === null
|
|
36
|
+
? null
|
|
37
|
+
: `#${String(card.pullRequestNumber)}`,
|
|
38
|
+
]
|
|
39
|
+
.filter((part) => part !== null)
|
|
40
|
+
.join(" · ");
|
|
41
|
+
}
|
|
42
|
+
export function CardReview(props) {
|
|
43
|
+
if (props.workflowId !== "develop-issue")
|
|
44
|
+
return null;
|
|
45
|
+
const review = cardReview(props.card);
|
|
46
|
+
if (review === "")
|
|
47
|
+
return null;
|
|
48
|
+
return element("span", {
|
|
49
|
+
class: "card-review",
|
|
50
|
+
children: review
|
|
51
|
+
.split(" · ")
|
|
52
|
+
.map((part, index) => [
|
|
53
|
+
index === 0 ? "" : " · ",
|
|
54
|
+
element("span", { class: "review-pill", children: part }),
|
|
55
|
+
]),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function completionMark(card, workflowId) {
|
|
59
|
+
const mark = card.completionMark;
|
|
60
|
+
if (mark === null)
|
|
61
|
+
return null;
|
|
62
|
+
let text = mark.text;
|
|
63
|
+
const status = card.pullRequestObservation?.status;
|
|
64
|
+
if (text === "Needs attention" && status === "merged")
|
|
65
|
+
text = `PR merged #${String(card.pullRequestNumber)}`;
|
|
66
|
+
if (text === "Needs attention" && status === "unavailable")
|
|
67
|
+
text = "PR status unavailable";
|
|
68
|
+
if (mark.laterRunId === null)
|
|
69
|
+
return element("span", { class: "completion-mark", children: text });
|
|
70
|
+
return element("a", {
|
|
71
|
+
class: "completion-mark",
|
|
72
|
+
href: watchHash({ workflowId, runId: mark.laterRunId }),
|
|
73
|
+
children: mark.text,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export function Card(props) {
|
|
77
|
+
const { card, workflowId, now } = props;
|
|
78
|
+
return element("article", {
|
|
79
|
+
class: "card",
|
|
80
|
+
children: [
|
|
81
|
+
element("a", {
|
|
82
|
+
class: "card-run",
|
|
83
|
+
href: watchHash({ workflowId, runId: card.runId }),
|
|
84
|
+
title: card.runId,
|
|
85
|
+
children: [
|
|
86
|
+
element("strong", {
|
|
87
|
+
children: card.title ?? card.runId.slice(0, 12),
|
|
88
|
+
}),
|
|
89
|
+
element("span", {
|
|
90
|
+
class: card.endedAt === null && card.currentStep !== null
|
|
91
|
+
? "card-step active"
|
|
92
|
+
: "card-step",
|
|
93
|
+
children: cardStep(card, now),
|
|
94
|
+
}),
|
|
95
|
+
component(CardReview, { card, workflowId }),
|
|
96
|
+
element("span", {
|
|
97
|
+
class: "card-cost",
|
|
98
|
+
children: `${card.currentStep === null ? "Totals" : "Totals so far"} · ${priceText(card.claudeCostUsd, card.estimatedCostUsd)}`,
|
|
99
|
+
}),
|
|
100
|
+
card.decisionWaiting
|
|
101
|
+
? element("span", {
|
|
102
|
+
class: "decision-mark",
|
|
103
|
+
children: "! Decision waiting",
|
|
104
|
+
})
|
|
105
|
+
: null,
|
|
106
|
+
element("small", { children: card.runId.slice(0, 12) }),
|
|
107
|
+
],
|
|
108
|
+
}),
|
|
109
|
+
completionMark(card, workflowId),
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export function WorkflowList(props) {
|
|
114
|
+
return element("nav", {
|
|
115
|
+
class: "workflows",
|
|
116
|
+
"aria-label": "Workflows",
|
|
117
|
+
children: props.workflows.map((workflow) => element("a", {
|
|
118
|
+
key: workflow.workflowId,
|
|
119
|
+
href: watchHash({ workflowId: workflow.workflowId, runId: null }),
|
|
120
|
+
"aria-current": workflow.workflowId === props.selected ? "page" : undefined,
|
|
121
|
+
children: [
|
|
122
|
+
element("strong", { children: workflow.workflowId }),
|
|
123
|
+
element("span", {
|
|
124
|
+
children: `${String(workflow.activeCount)} active · ${String(workflow.waitingCount)} waiting`,
|
|
125
|
+
}),
|
|
126
|
+
],
|
|
127
|
+
})),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
export function columnCollapsed(choices, name) {
|
|
131
|
+
const value = choices !== null && Object.hasOwn(choices, name)
|
|
132
|
+
? choices[name]
|
|
133
|
+
: undefined;
|
|
134
|
+
return value ?? ["Done", "Stopped"].includes(name);
|
|
135
|
+
}
|
|
136
|
+
export function Column(props) {
|
|
137
|
+
const { column, workflowId, now, controls } = props;
|
|
138
|
+
const collapsed = columnCollapsed(controls?.choices ?? null, column.name);
|
|
139
|
+
const tone = column.name === "Stopped" ? "column stopped" : "column";
|
|
140
|
+
return element("section", {
|
|
141
|
+
class: `${tone}${collapsed ? " collapsed" : ""}`,
|
|
142
|
+
onMouseEnter: () => controls?.onHover?.(column.name),
|
|
143
|
+
onMouseLeave: () => controls?.onHover?.(null),
|
|
144
|
+
onFocusIn: () => controls?.onFocus?.(column.name),
|
|
145
|
+
onFocusOut: () => controls?.onFocus?.(null),
|
|
146
|
+
children: [
|
|
147
|
+
element("h3", {
|
|
148
|
+
class: "column-name",
|
|
149
|
+
children: [
|
|
150
|
+
element("span", { children: column.name }),
|
|
151
|
+
" ",
|
|
152
|
+
element("span", {
|
|
153
|
+
class: "column-count",
|
|
154
|
+
children: String(column.cards.length),
|
|
155
|
+
}),
|
|
156
|
+
element("button", {
|
|
157
|
+
type: "button",
|
|
158
|
+
"aria-label": `${collapsed ? "Expand" : "Collapse"} ${column.name}`,
|
|
159
|
+
"aria-expanded": String(!collapsed),
|
|
160
|
+
onClick: () => controls?.onToggle(column.name),
|
|
161
|
+
children: collapsed ? "+" : "−",
|
|
162
|
+
}),
|
|
163
|
+
],
|
|
164
|
+
}),
|
|
165
|
+
collapsed
|
|
166
|
+
? null
|
|
167
|
+
: element("div", {
|
|
168
|
+
class: "column-cards",
|
|
169
|
+
children: [
|
|
170
|
+
column.cards.map((card) => component(Card, { key: card.runId, card, workflowId, now })),
|
|
171
|
+
props.addCard,
|
|
172
|
+
],
|
|
173
|
+
}),
|
|
174
|
+
],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
export function Board(props) {
|
|
178
|
+
const { workflow, now } = props;
|
|
179
|
+
return element("main", {
|
|
180
|
+
class: "board",
|
|
181
|
+
children: [
|
|
182
|
+
element("h2", { children: workflow.workflowId }),
|
|
183
|
+
element("div", {
|
|
184
|
+
class: "columns",
|
|
185
|
+
children: workflow.columns.map((column, index) => component(Column, {
|
|
186
|
+
key: column.name,
|
|
187
|
+
column,
|
|
188
|
+
workflowId: workflow.workflowId,
|
|
189
|
+
now,
|
|
190
|
+
controls: props.controls,
|
|
191
|
+
addCard: index === 0
|
|
192
|
+
? component(AddCard, {
|
|
193
|
+
form: props.cardForm,
|
|
194
|
+
controls: props.cards,
|
|
195
|
+
})
|
|
196
|
+
: null,
|
|
197
|
+
})),
|
|
198
|
+
}),
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WatchCompletionMark, WatchRun, WatchStep, WatchWorkflow } from "./watch-render.ts";
|
|
2
|
+
export declare function completionMarkOf(run: WatchRun, candidates: readonly WatchRun[]): WatchCompletionMark | null;
|
|
3
|
+
export declare function activeRun(state: string): boolean;
|
|
4
|
+
export declare function recentRun(latestAt: string | null, now: string): boolean;
|
|
5
|
+
export declare function currentStepOf(events: readonly unknown[], workflowId: string): WatchStep;
|
|
6
|
+
export declare function roundOf(events: readonly unknown[]): number;
|
|
7
|
+
interface BoardInputs {
|
|
8
|
+
readonly workflows: readonly string[];
|
|
9
|
+
readonly updatedAt: string;
|
|
10
|
+
readonly summaries?: readonly unknown[];
|
|
11
|
+
readonly completionCandidates?: readonly WatchRun[];
|
|
12
|
+
}
|
|
13
|
+
export declare function boardsOf(inputs: BoardInputs, runs: readonly WatchRun[]): WatchWorkflow[];
|
|
14
|
+
export declare function startWorkflowOf(workflows: readonly WatchWorkflow[]): string | null;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { record } from "../protocol.js";
|
|
2
|
+
import { isInstant } from "../authority/instants.js";
|
|
3
|
+
import { issueSteps } from "./watch-phases.js";
|
|
4
|
+
const weekMilliseconds = 7 * 24 * 60 * 60 * 1000;
|
|
5
|
+
const terminalStates = ["completed", "failed", "cancelled"];
|
|
6
|
+
function eventTime(run, type) {
|
|
7
|
+
const recordedAt = run.events.find((event) => event.type === type)?.recordedAt;
|
|
8
|
+
return isInstant(recordedAt) ? Date.parse(recordedAt) : NaN;
|
|
9
|
+
}
|
|
10
|
+
export function completionMarkOf(run, candidates) {
|
|
11
|
+
if (run.workflowId !== "develop-issue" ||
|
|
12
|
+
run.state !== "completed" ||
|
|
13
|
+
run.outcome !== "blocked")
|
|
14
|
+
return null;
|
|
15
|
+
const completedAt = eventTime(run, "run.completed");
|
|
16
|
+
const later = candidates
|
|
17
|
+
.filter((candidate) => typeof run.ticketId === "string" &&
|
|
18
|
+
run.ticketId !== "" &&
|
|
19
|
+
candidate.ticketId === run.ticketId &&
|
|
20
|
+
candidate.runId !== run.runId &&
|
|
21
|
+
candidate.workflowId === "develop-issue" &&
|
|
22
|
+
candidate.state === "completed" &&
|
|
23
|
+
candidate.outcome === "handoff_requested" &&
|
|
24
|
+
candidate.ticketStatus !== "partial" &&
|
|
25
|
+
candidate.issueUpdate !== "failed")
|
|
26
|
+
.map((candidate) => ({
|
|
27
|
+
runId: candidate.runId,
|
|
28
|
+
createdAt: eventTime(candidate, "run.created"),
|
|
29
|
+
}))
|
|
30
|
+
.filter((candidate) => candidate.createdAt > completedAt)
|
|
31
|
+
.toSorted((first, second) => first.createdAt - second.createdAt ||
|
|
32
|
+
(first.runId < second.runId ? -1 : 1))[0];
|
|
33
|
+
return later === undefined
|
|
34
|
+
? { text: "Needs attention", laterRunId: null }
|
|
35
|
+
: { text: "Done in a later run", laterRunId: later.runId };
|
|
36
|
+
}
|
|
37
|
+
export function activeRun(state) {
|
|
38
|
+
return !terminalStates.includes(state);
|
|
39
|
+
}
|
|
40
|
+
export function recentRun(latestAt, now) {
|
|
41
|
+
const age = Date.parse(now) - Date.parse(latestAt ?? "");
|
|
42
|
+
return age >= 0 && age <= weekMilliseconds;
|
|
43
|
+
}
|
|
44
|
+
function stepNames(workflowId) {
|
|
45
|
+
return workflowId === "develop-issue"
|
|
46
|
+
? issueSteps.map((step) => step.name)
|
|
47
|
+
: ["Claude turn", "Your review"];
|
|
48
|
+
}
|
|
49
|
+
function operationOf(event) {
|
|
50
|
+
const payload = record(record(event)?.["payload"]);
|
|
51
|
+
try {
|
|
52
|
+
const operation = JSON.parse(String(payload?.["operationId"]));
|
|
53
|
+
return Array.isArray(operation) ? operation : [];
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function stepName(event, workflowId) {
|
|
60
|
+
const type = record(event)?.["type"];
|
|
61
|
+
if (workflowId !== "develop-issue" && type === "gate.opened")
|
|
62
|
+
return "Your review";
|
|
63
|
+
if (type !== "effect.requested")
|
|
64
|
+
return undefined;
|
|
65
|
+
if (workflowId !== "develop-issue")
|
|
66
|
+
return "Claude turn";
|
|
67
|
+
return issueSteps.find((step) => step.operation === operationOf(event)[4])
|
|
68
|
+
?.name;
|
|
69
|
+
}
|
|
70
|
+
function startedAt(event) {
|
|
71
|
+
const value = record(event)?.["recordedAt"];
|
|
72
|
+
return typeof value === "string" ? value : null;
|
|
73
|
+
}
|
|
74
|
+
function chronological(events) {
|
|
75
|
+
return events.toSorted((first, second) => Date.parse(startedAt(first) ?? "") - Date.parse(startedAt(second) ?? ""));
|
|
76
|
+
}
|
|
77
|
+
export function currentStepOf(events, workflowId) {
|
|
78
|
+
const event = chronological(events).findLast((item) => stepName(item, workflowId) !== undefined);
|
|
79
|
+
return {
|
|
80
|
+
name: stepName(event, workflowId) ?? stepNames(workflowId)[0] ?? "Claude turn",
|
|
81
|
+
startedAt: startedAt(event),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function roundOf(events) {
|
|
85
|
+
const event = chronological(events).findLast((item) => record(item)?.["type"] === "effect.requested" &&
|
|
86
|
+
operationOf(item)[4] === "claude-turn");
|
|
87
|
+
const round = operationOf(event)[1];
|
|
88
|
+
return typeof round === "number" ? round : 1;
|
|
89
|
+
}
|
|
90
|
+
function columnOf(run, now) {
|
|
91
|
+
if (activeRun(run.state))
|
|
92
|
+
return run.currentStep.name;
|
|
93
|
+
if (!recentRun(run.latestAt, now))
|
|
94
|
+
return null;
|
|
95
|
+
if (run.state !== "completed" || run.outcome === "blocked")
|
|
96
|
+
return "Stopped";
|
|
97
|
+
return run.outcome === "handoff_requested" ? "Done" : null;
|
|
98
|
+
}
|
|
99
|
+
function cardOf(run, runs) {
|
|
100
|
+
const issue = run.workflowId === "develop-issue";
|
|
101
|
+
return {
|
|
102
|
+
runId: run.runId,
|
|
103
|
+
title: run.title,
|
|
104
|
+
completionMark: completionMarkOf(run, runs),
|
|
105
|
+
pullRequestObservation: null,
|
|
106
|
+
claudeCostUsd: run.claudeCostUsd,
|
|
107
|
+
estimatedCostUsd: run.estimatedCostUsd,
|
|
108
|
+
usage: run.usage,
|
|
109
|
+
currentStep: activeRun(run.state) ? run.currentStep : null,
|
|
110
|
+
endedAt: activeRun(run.state) ? null : run.latestAt,
|
|
111
|
+
decisionWaiting: run.decisions.length > 0,
|
|
112
|
+
round: issue ? run.round : null,
|
|
113
|
+
greptileScore: issue ? (run.reviews.at(-1)?.score ?? null) : null,
|
|
114
|
+
pullRequestNumber: issue ? (run.pullRequest?.number ?? null) : null,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function stepOrder(first, second) {
|
|
118
|
+
const waiting = Number(second.decisionWaiting) - Number(first.decisionWaiting);
|
|
119
|
+
if (waiting !== 0)
|
|
120
|
+
return waiting;
|
|
121
|
+
return (Date.parse(first.currentStep?.startedAt ?? "1970-01-01") -
|
|
122
|
+
Date.parse(second.currentStep?.startedAt ?? "1970-01-01"));
|
|
123
|
+
}
|
|
124
|
+
function latestTime(times) {
|
|
125
|
+
return (times
|
|
126
|
+
.filter((time) => time !== null)
|
|
127
|
+
.toSorted((first, second) => Date.parse(second) - Date.parse(first))[0] ??
|
|
128
|
+
null);
|
|
129
|
+
}
|
|
130
|
+
function summaryOf(value) {
|
|
131
|
+
const fields = record(value);
|
|
132
|
+
const pending = fields?.["pendingDecisions"];
|
|
133
|
+
const latest = fields?.["latestAt"];
|
|
134
|
+
return {
|
|
135
|
+
state: String(fields?.["state"]),
|
|
136
|
+
waiting: Array.isArray(pending) && pending.length > 0,
|
|
137
|
+
latestAt: typeof latest === "string" ? latest : null,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export function boardsOf(inputs, runs) {
|
|
141
|
+
return inputs.workflows.map((workflowId) => {
|
|
142
|
+
const own = runs.filter((run) => run.workflowId === workflowId);
|
|
143
|
+
const summaries = inputs.summaries === undefined
|
|
144
|
+
? own.map((run) => ({
|
|
145
|
+
state: run.state,
|
|
146
|
+
waiting: run.decisions.length > 0,
|
|
147
|
+
latestAt: run.latestAt,
|
|
148
|
+
}))
|
|
149
|
+
: inputs.summaries
|
|
150
|
+
.filter((value) => record(value)?.["workflowId"] === workflowId)
|
|
151
|
+
.map(summaryOf);
|
|
152
|
+
const columns = [...stepNames(workflowId), "Done", "Stopped"].map((name) => {
|
|
153
|
+
const cards = own
|
|
154
|
+
.filter((run) => columnOf(run, inputs.updatedAt) === name)
|
|
155
|
+
.map((run) => cardOf(run, inputs.completionCandidates ?? runs));
|
|
156
|
+
return {
|
|
157
|
+
name,
|
|
158
|
+
cards: ["Done", "Stopped"].includes(name)
|
|
159
|
+
? cards
|
|
160
|
+
.toSorted((first, second) => Date.parse(second.endedAt ?? "") -
|
|
161
|
+
Date.parse(first.endedAt ?? ""))
|
|
162
|
+
.slice(0, 20)
|
|
163
|
+
: cards.toSorted(stepOrder),
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
workflowId,
|
|
168
|
+
activeCount: summaries.filter((run) => activeRun(run.state)).length,
|
|
169
|
+
waitingCount: summaries.filter((run) => run.waiting).length,
|
|
170
|
+
latestAt: latestTime(summaries.map((run) => run.latestAt)),
|
|
171
|
+
columns,
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
export function startWorkflowOf(workflows) {
|
|
176
|
+
const waiting = workflows.filter((workflow) => workflow.waitingCount > 0);
|
|
177
|
+
return ((waiting.length > 0 ? waiting : workflows).toSorted((first, second) => Date.parse(second.latestAt ?? "1970-01-01") -
|
|
178
|
+
Date.parse(first.latestAt ?? "1970-01-01"))[0]?.workflowId ?? null);
|
|
179
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const watchCardClient = "\nasync function submitCard(workflowId) {\n const draft = state.cards[workflowId];\n if (!draft || draft.pending || draft.admitted) return;\n state.cards[workflowId] = { ...draft, pending: true, message: \"\" };\n draw();\n let result;\n try {\n const response = await fetch(\"actions/run\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", \"x-cloving-token\": actionToken },\n body: JSON.stringify({ workflowId, fields: draft.fields, commandId: draft.commandId }),\n });\n result = response.ok ? cardReply(await response.json()) : { admitted: false, message: \"request-refused: Refresh the page and check the input (16 KiB maximum).\" };\n } catch {\n result = cardReply({ kind: \"error\", error: { code: \"outcome-unknown\" } });\n }\n if (state.cards[workflowId]?.commandId !== draft.commandId) return;\n state.cards[workflowId] = { ...draft, ...result, pending: false };\n draw();\n}\n\nfunction cardControls(model, workflowId) {\n if (actionToken === null || workflowId === null) return undefined;\n const form = model?.cardForms?.find((item) => item.workflowId === workflowId);\n if (form === undefined) return undefined;\n const draft = state.cards[workflowId] ?? null;\n return { draft, onOpen() {\n state.cards[workflowId] = { commandId: crypto.randomUUID(), fields: {}, pending: false, admitted: false, message: \"\" };\n draw();\n document.querySelector(\".add-card-form input, .add-card-form textarea, .add-card-form button\")?.focus();\n }, onCancel() {\n delete state.cards[workflowId];\n draw();\n document.querySelector(\".add-card\")?.focus();\n },\n onChange(name, value) {\n const fields = { ...state.cards[workflowId].fields, [name]: value };\n if (form.fields.find((field) => field.name === name)?.optional && !value.trim())\n delete fields[name];\n state.cards[workflowId] = { ...state.cards[workflowId], fields };\n }, onSubmit() { submitCard(workflowId); } };\n}\n";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const watchCardClient = `
|
|
2
|
+
async function submitCard(workflowId) {
|
|
3
|
+
const draft = state.cards[workflowId];
|
|
4
|
+
if (!draft || draft.pending || draft.admitted) return;
|
|
5
|
+
state.cards[workflowId] = { ...draft, pending: true, message: "" };
|
|
6
|
+
draw();
|
|
7
|
+
let result;
|
|
8
|
+
try {
|
|
9
|
+
const response = await fetch("actions/run", {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "content-type": "application/json", "x-cloving-token": actionToken },
|
|
12
|
+
body: JSON.stringify({ workflowId, fields: draft.fields, commandId: draft.commandId }),
|
|
13
|
+
});
|
|
14
|
+
result = response.ok ? cardReply(await response.json()) : { admitted: false, message: "request-refused: Refresh the page and check the input (16 KiB maximum)." };
|
|
15
|
+
} catch {
|
|
16
|
+
result = cardReply({ kind: "error", error: { code: "outcome-unknown" } });
|
|
17
|
+
}
|
|
18
|
+
if (state.cards[workflowId]?.commandId !== draft.commandId) return;
|
|
19
|
+
state.cards[workflowId] = { ...draft, ...result, pending: false };
|
|
20
|
+
draw();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function cardControls(model, workflowId) {
|
|
24
|
+
if (actionToken === null || workflowId === null) return undefined;
|
|
25
|
+
const form = model?.cardForms?.find((item) => item.workflowId === workflowId);
|
|
26
|
+
if (form === undefined) return undefined;
|
|
27
|
+
const draft = state.cards[workflowId] ?? null;
|
|
28
|
+
return { draft, onOpen() {
|
|
29
|
+
state.cards[workflowId] = { commandId: crypto.randomUUID(), fields: {}, pending: false, admitted: false, message: "" };
|
|
30
|
+
draw();
|
|
31
|
+
document.querySelector(".add-card-form input, .add-card-form textarea, .add-card-form button")?.focus();
|
|
32
|
+
}, onCancel() {
|
|
33
|
+
delete state.cards[workflowId];
|
|
34
|
+
draw();
|
|
35
|
+
document.querySelector(".add-card")?.focus();
|
|
36
|
+
},
|
|
37
|
+
onChange(name, value) {
|
|
38
|
+
const fields = { ...state.cards[workflowId].fields, [name]: value };
|
|
39
|
+
if (form.fields.find((field) => field.name === name)?.optional && !value.trim())
|
|
40
|
+
delete fields[name];
|
|
41
|
+
state.cards[workflowId] = { ...state.cards[workflowId], fields };
|
|
42
|
+
}, onSubmit() { submitCard(workflowId); } };
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { isWorkflowDeclaration } from "../workflow-declaration.js";
|
|
4
|
+
import { builtinCardForms } from "./watch-run-input.js";
|
|
5
|
+
export async function watchCardForms(directory) {
|
|
6
|
+
const forms = [...builtinCardForms()];
|
|
7
|
+
const files = await readdir(directory).catch(() => []);
|
|
8
|
+
for (const file of files
|
|
9
|
+
.filter((name) => name.endsWith(".declaration.json"))
|
|
10
|
+
.sort()) {
|
|
11
|
+
const value = await readFile(join(directory, file), "utf8")
|
|
12
|
+
.then((text) => JSON.parse(text))
|
|
13
|
+
.catch(() => null);
|
|
14
|
+
if (!isWorkflowDeclaration(value))
|
|
15
|
+
continue;
|
|
16
|
+
const entries = Object.entries(value.input.fields);
|
|
17
|
+
if (!entries.every(([, rule]) => rule === "string" || rule.type === "string"))
|
|
18
|
+
continue;
|
|
19
|
+
if (forms.some((form) => form.workflowId === value.workflowId))
|
|
20
|
+
continue;
|
|
21
|
+
forms.push({
|
|
22
|
+
workflowId: value.workflowId,
|
|
23
|
+
source: "input",
|
|
24
|
+
fields: entries.map(([name, rule]) => ({
|
|
25
|
+
name,
|
|
26
|
+
label: name,
|
|
27
|
+
multiline: false,
|
|
28
|
+
optional: rule !== "string" && rule.optional === true,
|
|
29
|
+
})),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return forms;
|
|
33
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function cardReply(reply) {
|
|
2
|
+
if (reply.kind === "result")
|
|
3
|
+
return {
|
|
4
|
+
admitted: true,
|
|
5
|
+
message: `Run ${String(reply.result["runId"])} is admitted`,
|
|
6
|
+
};
|
|
7
|
+
const explanations = {
|
|
8
|
+
"workflow-active": "Add the label cloving: ready to the issue to put it in the queue.",
|
|
9
|
+
"unknown-workflow": "This workflow is no longer registered. Refresh the page.",
|
|
10
|
+
"workflow-unavailable": "A required workflow capability is unavailable.",
|
|
11
|
+
"invalid-submission": "Check the workflow fields.",
|
|
12
|
+
"input-too-large": "Shorten the input and try again.",
|
|
13
|
+
"invalid-request": "The service could not read this run request.",
|
|
14
|
+
"conflicting-command": "This form was already sent with different fields. Open a new form.",
|
|
15
|
+
"service-unavailable": "Start the Cloving service and retry this form.",
|
|
16
|
+
"authority-unavailable": "The service authority is unavailable. Retry this form later.",
|
|
17
|
+
"permission-denied": "The service refused access to this account.",
|
|
18
|
+
"outcome-unknown": "The reply was lost. Retry this form with the same command ID.",
|
|
19
|
+
"resolver-timeout": "The input resolver timed out. Retry this form.",
|
|
20
|
+
"resolver-failure": "The input resolver failed. Check the service before retrying.",
|
|
21
|
+
"invalid-ticket-id": "Enter a valid issue number or ticket ID.",
|
|
22
|
+
"ticket-source-not-configured": "Configure the daemon ticket command first.",
|
|
23
|
+
"ticket-not-available": "The ticket could not be read.",
|
|
24
|
+
"next-source-not-configured": "Configure the daemon next-ticket command first.",
|
|
25
|
+
"next-ticket-not-available": "The next ticket could not be read.",
|
|
26
|
+
"no-ready-ticket": "There is no ready ticket in the queue.",
|
|
27
|
+
"unsupported-prompt": "This workflow requires declared input fields.",
|
|
28
|
+
};
|
|
29
|
+
const { code } = reply.error;
|
|
30
|
+
return {
|
|
31
|
+
admitted: false,
|
|
32
|
+
message: `${code}: ${explanations[code] ?? "The service refused this run."}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Shown } from "./watch-element.ts";
|
|
2
|
+
import type { CardField, CardForm } from "./watch-run-input.ts";
|
|
3
|
+
export interface CardDraft {
|
|
4
|
+
readonly commandId: string;
|
|
5
|
+
readonly fields: Readonly<Record<string, string>>;
|
|
6
|
+
readonly pending: boolean;
|
|
7
|
+
readonly admitted: boolean;
|
|
8
|
+
readonly message: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CardControls {
|
|
11
|
+
readonly draft: CardDraft | null;
|
|
12
|
+
readonly onOpen: () => void;
|
|
13
|
+
readonly onCancel: () => void;
|
|
14
|
+
readonly onChange: (name: string, value: string) => void;
|
|
15
|
+
readonly onSubmit: () => void;
|
|
16
|
+
}
|
|
17
|
+
export interface CardKeyEvent {
|
|
18
|
+
readonly key: string;
|
|
19
|
+
readonly defaultPrevented?: boolean;
|
|
20
|
+
readonly isComposing?: boolean;
|
|
21
|
+
readonly repeat?: boolean;
|
|
22
|
+
readonly ctrlKey?: boolean;
|
|
23
|
+
readonly metaKey?: boolean;
|
|
24
|
+
readonly target?: {
|
|
25
|
+
readonly localName?: string;
|
|
26
|
+
};
|
|
27
|
+
readonly currentTarget: object;
|
|
28
|
+
readonly preventDefault: () => void;
|
|
29
|
+
}
|
|
30
|
+
export declare function cardSubmitKey(event: CardKeyEvent): boolean;
|
|
31
|
+
export declare function cardKey(event: CardKeyEvent, controls: CardControls): void;
|
|
32
|
+
export declare function CardInput(props: {
|
|
33
|
+
readonly field: CardField;
|
|
34
|
+
readonly controls: CardControls;
|
|
35
|
+
readonly draft: CardDraft;
|
|
36
|
+
}): Shown;
|
|
37
|
+
export declare function AddCard(props: {
|
|
38
|
+
readonly form: CardForm | undefined;
|
|
39
|
+
readonly controls: CardControls | undefined;
|
|
40
|
+
}): Shown;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { component, element } from "./watch-element.js";
|
|
2
|
+
export function cardSubmitKey(event) {
|
|
3
|
+
const name = event.target?.localName;
|
|
4
|
+
return (name === "input" ||
|
|
5
|
+
(name === "textarea" && Boolean(event.ctrlKey || event.metaKey)));
|
|
6
|
+
}
|
|
7
|
+
export function cardKey(event, controls) {
|
|
8
|
+
if (event.defaultPrevented || event.isComposing || event.repeat)
|
|
9
|
+
return;
|
|
10
|
+
if (event.key === "Escape") {
|
|
11
|
+
event.preventDefault();
|
|
12
|
+
controls.onCancel();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (event.key !== "Enter")
|
|
16
|
+
return;
|
|
17
|
+
if (!cardSubmitKey(event))
|
|
18
|
+
return;
|
|
19
|
+
event.preventDefault();
|
|
20
|
+
const prototype = Reflect.getPrototypeOf(event.currentTarget);
|
|
21
|
+
if (prototype === null)
|
|
22
|
+
return;
|
|
23
|
+
const requestSubmit = Reflect.get(prototype, "requestSubmit");
|
|
24
|
+
if (typeof requestSubmit === "function")
|
|
25
|
+
Reflect.apply(requestSubmit, event.currentTarget, []);
|
|
26
|
+
}
|
|
27
|
+
export function CardInput(props) {
|
|
28
|
+
const { field, controls, draft } = props;
|
|
29
|
+
return element("label", {
|
|
30
|
+
children: [
|
|
31
|
+
field.label,
|
|
32
|
+
element(field.multiline ? "textarea" : "input", {
|
|
33
|
+
name: field.name,
|
|
34
|
+
type: field.multiline ? undefined : "text",
|
|
35
|
+
rows: field.multiline ? 5 : undefined,
|
|
36
|
+
value: draft.fields[field.name] ?? "",
|
|
37
|
+
required: !field.optional,
|
|
38
|
+
disabled: draft.pending || draft.admitted,
|
|
39
|
+
onInput: (event) => {
|
|
40
|
+
controls.onChange(field.name, event.currentTarget.value);
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function AddCard(props) {
|
|
47
|
+
const { form, controls } = props;
|
|
48
|
+
if (form === undefined || controls === undefined)
|
|
49
|
+
return null;
|
|
50
|
+
const { draft } = controls;
|
|
51
|
+
if (draft === null)
|
|
52
|
+
return element("button", {
|
|
53
|
+
class: "add-card",
|
|
54
|
+
type: "button",
|
|
55
|
+
onClick: controls.onOpen,
|
|
56
|
+
children: "+ Add a card",
|
|
57
|
+
});
|
|
58
|
+
return element("form", {
|
|
59
|
+
class: "add-card-form",
|
|
60
|
+
onKeyDown: (event) => {
|
|
61
|
+
cardKey(event, controls);
|
|
62
|
+
},
|
|
63
|
+
onSubmit: (event) => {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
controls.onSubmit();
|
|
66
|
+
},
|
|
67
|
+
children: [
|
|
68
|
+
form.fields.map((field) => component(CardInput, { key: field.name, field, controls, draft })),
|
|
69
|
+
element("button", {
|
|
70
|
+
type: "submit",
|
|
71
|
+
disabled: draft.pending || draft.admitted,
|
|
72
|
+
children: draft.pending ? "Adding…" : "Add card",
|
|
73
|
+
}),
|
|
74
|
+
element("button", {
|
|
75
|
+
type: "button",
|
|
76
|
+
onClick: controls.onCancel,
|
|
77
|
+
children: "Cancel",
|
|
78
|
+
}),
|
|
79
|
+
element("p", {
|
|
80
|
+
role: "status",
|
|
81
|
+
"aria-live": "polite",
|
|
82
|
+
children: draft.message,
|
|
83
|
+
}),
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const watchClient = "\nconst state = { model: null, stale: false, copied: \"\", label: \"\", run: \"\", loading: false, again: false, columns: {}, cards: {}, start: null, hovered: null, focused: null };\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 startControls() {\n if (state.start === null) state.start = readPreference(\"cloving.watch.start\") === true;\n return { shown: state.start, onToggle() {\n state.start = !state.start;\n savePreference(\"cloving.watch.start\", state.start);\n draw();\n } };\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 columns = columnControls(model, selected);\n const start = model === null ? undefined : startControls();\n const cards = cardControls(model, model === null ? null : boardWorkflow(model, watchLocation(selected).workflowId));\n const page = component(Page, { model, selected, now, stale, copying, columns, start, cards });\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 state.model = await withSelectedRun(await reply.json());\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);\n";
|