@wjarka/cezarion 0.15.1 → 0.16.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 +167 -46
- package/dist/agent-config/catalog.d.ts +6 -2
- package/dist/agent-config/catalog.js +78 -3
- package/dist/agent-config/catalog.js.map +1 -1
- package/dist/agent-config/model-settings/shared.js +6 -3
- package/dist/agent-config/model-settings/shared.js.map +1 -1
- package/dist/agent-config/models.js +4 -0
- package/dist/agent-config/models.js.map +1 -1
- package/dist/agent-config/validate.js +6 -0
- package/dist/agent-config/validate.js.map +1 -1
- package/dist/artifacts/cli.js +10 -2
- package/dist/artifacts/cli.js.map +1 -1
- package/dist/automations/coordinator.d.ts +7 -0
- package/dist/automations/coordinator.js +22 -2
- package/dist/automations/coordinator.js.map +1 -1
- package/dist/automations/github-poller.d.ts +4 -4
- package/dist/automations/github-poller.js.map +1 -1
- package/dist/automations/schedule-runner.d.ts +130 -0
- package/dist/automations/schedule-runner.js +326 -0
- package/dist/automations/schedule-runner.js.map +1 -0
- package/dist/automations/scheduler.d.ts +38 -7
- package/dist/automations/scheduler.js +90 -22
- package/dist/automations/scheduler.js.map +1 -1
- package/dist/automations/store.d.ts +80 -3
- package/dist/automations/store.js +208 -16
- package/dist/automations/store.js.map +1 -1
- package/dist/automations/task-template.d.ts +42 -6
- package/dist/automations/task-template.js +152 -24
- package/dist/automations/task-template.js.map +1 -1
- package/dist/automations/types.d.ts +142 -6
- package/dist/automations/types.js +64 -6
- package/dist/automations/types.js.map +1 -1
- package/dist/autosave-holders.js +8 -12
- package/dist/autosave-holders.js.map +1 -1
- package/dist/ci-wait/client.d.ts +8 -1
- package/dist/ci-wait/client.js +43 -1
- package/dist/ci-wait/client.js.map +1 -1
- package/dist/ci-wait/controller.d.ts +83 -4
- package/dist/ci-wait/controller.js +76 -11
- package/dist/ci-wait/controller.js.map +1 -1
- package/dist/ci-wait/errors.d.ts +7 -1
- package/dist/ci-wait/errors.js +36 -0
- package/dist/ci-wait/errors.js.map +1 -1
- package/dist/ci-wait/github.d.ts +2 -0
- package/dist/ci-wait/github.js +3 -1
- package/dist/ci-wait/github.js.map +1 -1
- package/dist/ci-wait/mcp.d.ts +2 -98
- package/dist/ci-wait/mcp.js +11 -25
- package/dist/ci-wait/mcp.js.map +1 -1
- package/dist/ci-wait/supervisor.d.ts +2 -1
- package/dist/ci-wait/supervisor.js +2 -1
- package/dist/ci-wait/supervisor.js.map +1 -1
- package/dist/ci-wait/tools.d.ts +307 -0
- package/dist/ci-wait/tools.js +63 -0
- package/dist/ci-wait/tools.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/contract/agent-config.d.ts +5 -0
- package/dist/contract/agent-profiles.d.ts +15 -0
- package/dist/contract/automation-schedule.d.ts +60 -0
- package/dist/contract/automations.d.ts +208 -36
- package/dist/contract/delegation.d.ts +96 -0
- package/dist/contract/discovery.d.ts +7 -0
- package/dist/contract/github.d.ts +1 -0
- package/dist/contract/health.d.ts +6 -0
- package/dist/contract/index.d.ts +3 -0
- package/dist/contract/index.js +1445 -745
- package/dist/contract/preview.d.ts +508 -0
- package/dist/contract/runs.d.ts +716 -15
- package/dist/contract/skills.d.ts +39 -0
- package/dist/contract/workflows.d.ts +6 -0
- package/dist/contract/workspace.d.ts +65 -0
- package/dist/contract/zoned-time.d.ts +35 -0
- package/dist/core/agent-env.d.ts +11 -0
- package/dist/core/agent-env.js +27 -5
- package/dist/core/agent-env.js.map +1 -1
- package/dist/core/agent-profiles.js +7 -0
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-runner.d.ts +49 -1
- package/dist/core/agent-runner.js +2 -1
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/backend-detect.d.ts +3 -2
- package/dist/core/backend-detect.js +27 -1
- package/dist/core/backend-detect.js.map +1 -1
- package/dist/core/claude-cli-runner.d.ts +1 -0
- package/dist/core/claude-cli-runner.js +69 -19
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/codex-app-server-runner.d.ts +1 -0
- package/dist/core/codex-app-server-runner.js +200 -25
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +7 -3
- package/dist/core/codex-app-server-transport.js +11 -9
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/core/cursor-acp-runner.d.ts +1 -0
- package/dist/core/cursor-acp-runner.js +24 -9
- package/dist/core/cursor-acp-runner.js.map +1 -1
- package/dist/core/host-model-catalog.js +2 -0
- package/dist/core/host-model-catalog.js.map +1 -1
- package/dist/core/managed-session.js +2 -0
- package/dist/core/managed-session.js.map +1 -1
- package/dist/core/model-identity.js +2 -0
- package/dist/core/model-identity.js.map +1 -1
- package/dist/core/model-presets.js +3 -0
- package/dist/core/model-presets.js.map +1 -1
- package/dist/core/omp-model-catalog.d.ts +43 -0
- package/dist/core/omp-model-catalog.js +205 -0
- package/dist/core/omp-model-catalog.js.map +1 -0
- package/dist/core/omp-runner.d.ts +73 -0
- package/dist/core/omp-runner.js +990 -0
- package/dist/core/omp-runner.js.map +1 -0
- package/dist/core/omp-ui-mapper.d.ts +106 -0
- package/dist/core/omp-ui-mapper.js +882 -0
- package/dist/core/omp-ui-mapper.js.map +1 -0
- package/dist/core/opencode-server-runner.d.ts +18 -4
- package/dist/core/opencode-server-runner.js +337 -96
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/opencode-session-error.d.ts +11 -0
- package/dist/core/opencode-session-error.js +26 -0
- package/dist/core/opencode-session-error.js.map +1 -0
- package/dist/core/opencode-ui-mapper.js +4 -36
- package/dist/core/opencode-ui-mapper.js.map +1 -1
- package/dist/core/pi-runner.d.ts +1 -0
- package/dist/core/pi-runner.js +75 -12
- package/dist/core/pi-runner.js.map +1 -1
- package/dist/core/provider-auth.d.ts +9 -2
- package/dist/core/provider-auth.js +43 -6
- package/dist/core/provider-auth.js.map +1 -1
- package/dist/core/runner-factory.js +3 -0
- package/dist/core/runner-factory.js.map +1 -1
- package/dist/core/runner-model-catalog.js +1 -0
- package/dist/core/runner-model-catalog.js.map +1 -1
- package/dist/core/runner-stderr.d.ts +2 -0
- package/dist/core/runner-stderr.js +20 -0
- package/dist/core/runner-stderr.js.map +1 -0
- package/dist/core/session-process.d.ts +22 -0
- package/dist/core/session-process.js +202 -0
- package/dist/core/session-process.js.map +1 -0
- package/dist/core/ui-events.d.ts +1 -1
- package/dist/core/usage-limit.js +3 -60
- package/dist/core/usage-limit.js.map +1 -1
- package/dist/data-gitignore.d.ts +6 -0
- package/dist/data-gitignore.js +57 -0
- package/dist/data-gitignore.js.map +1 -0
- package/dist/delegation/capacity.d.ts +19 -0
- package/dist/delegation/capacity.js +34 -0
- package/dist/delegation/capacity.js.map +1 -0
- package/dist/delegation/cli.js +13 -4
- package/dist/delegation/cli.js.map +1 -1
- package/dist/delegation/conversations.d.ts +4 -2
- package/dist/delegation/conversations.js +8 -12
- package/dist/delegation/conversations.js.map +1 -1
- package/dist/delegation/credentials.d.ts +2 -0
- package/dist/delegation/credentials.js +10 -0
- package/dist/delegation/credentials.js.map +1 -1
- package/dist/delegation/destroy-observation.d.ts +42 -0
- package/dist/delegation/destroy-observation.js +115 -0
- package/dist/delegation/destroy-observation.js.map +1 -0
- package/dist/delegation/execution-identity.d.ts +6 -0
- package/dist/delegation/execution-identity.js +1 -1
- package/dist/delegation/execution-identity.js.map +1 -1
- package/dist/delegation/policy.d.ts +3 -2
- package/dist/delegation/policy.js +7 -5
- package/dist/delegation/policy.js.map +1 -1
- package/dist/delegation/process-liveness.d.ts +57 -20
- package/dist/delegation/process-liveness.js +114 -92
- package/dist/delegation/process-liveness.js.map +1 -1
- package/dist/delegation/provision.js +6 -6
- package/dist/delegation/provision.js.map +1 -1
- package/dist/delegation/results.js +4 -2
- package/dist/delegation/results.js.map +1 -1
- package/dist/delegation/retry-backoff.d.ts +23 -0
- package/dist/delegation/retry-backoff.js +18 -0
- package/dist/delegation/retry-backoff.js.map +1 -0
- package/dist/delegation/routes.d.ts +64 -58
- package/dist/delegation/scratch-cleanup.d.ts +29 -0
- package/dist/delegation/scratch-cleanup.js +143 -0
- package/dist/delegation/scratch-cleanup.js.map +1 -0
- package/dist/delegation/service.d.ts +20 -1
- package/dist/delegation/service.js +233 -70
- package/dist/delegation/service.js.map +1 -1
- package/dist/delegation/transport.d.ts +12 -6
- package/dist/delegation/workspace.d.ts +23 -4
- package/dist/delegation/workspace.js +147 -31
- package/dist/delegation/workspace.js.map +1 -1
- package/dist/git-worktree-lock-helper.js +8 -3
- package/dist/git-worktree-lock-helper.js.map +1 -1
- package/dist/git-worktree-lock.d.ts +6 -1
- package/dist/git-worktree-lock.js +10 -4
- package/dist/git-worktree-lock.js.map +1 -1
- package/dist/git-worktree-release.d.ts +20 -0
- package/dist/git-worktree-release.js +27 -0
- package/dist/git-worktree-release.js.map +1 -0
- package/dist/git-worktree.d.ts +8 -2
- package/dist/git-worktree.js +19 -2
- package/dist/git-worktree.js.map +1 -1
- package/dist/handoff.d.ts +2 -2
- package/dist/handoff.js +1 -1
- package/dist/index.js +109 -76
- package/dist/index.js.map +1 -1
- package/dist/paths.d.ts +1 -1
- package/dist/paths.js +5 -1
- package/dist/paths.js.map +1 -1
- package/dist/preview/cdp.d.ts +13 -0
- package/dist/preview/cdp.js +69 -0
- package/dist/preview/cdp.js.map +1 -0
- package/dist/preview/chromium.d.ts +75 -0
- package/dist/preview/chromium.js +394 -0
- package/dist/preview/chromium.js.map +1 -0
- package/dist/preview/dev-server.d.ts +68 -0
- package/dist/preview/dev-server.js +341 -0
- package/dist/preview/dev-server.js.map +1 -0
- package/dist/preview/host.d.ts +154 -0
- package/dist/preview/host.js +681 -0
- package/dist/preview/host.js.map +1 -0
- package/dist/preview/registration.d.ts +63 -0
- package/dist/preview/registration.js +109 -0
- package/dist/preview/registration.js.map +1 -0
- package/dist/preview/session.d.ts +73 -0
- package/dist/preview/session.js +347 -0
- package/dist/preview/session.js.map +1 -0
- package/dist/preview/url.d.ts +6 -0
- package/dist/preview/url.js +17 -0
- package/dist/preview/url.js.map +1 -0
- package/dist/runs/agent-tmpdir-removal.d.ts +15 -0
- package/dist/runs/agent-tmpdir-removal.js +60 -0
- package/dist/runs/agent-tmpdir-removal.js.map +1 -0
- package/dist/runs/agent-tmpdir.d.ts +12 -1
- package/dist/runs/agent-tmpdir.js +123 -34
- package/dist/runs/agent-tmpdir.js.map +1 -1
- package/dist/runs/delegation-state.d.ts +5 -1
- package/dist/runs/delegation-state.js +9 -0
- package/dist/runs/delegation-state.js.map +1 -1
- package/dist/runs/event-history.d.ts +4 -4
- package/dist/runs/event-history.js +97 -117
- package/dist/runs/event-history.js.map +1 -1
- package/dist/runs/history-compressor.d.ts +29 -0
- package/dist/runs/history-compressor.js +116 -0
- package/dist/runs/history-compressor.js.map +1 -0
- package/dist/runs/history-file.d.ts +36 -0
- package/dist/runs/history-file.js +463 -0
- package/dist/runs/history-file.js.map +1 -0
- package/dist/runs/human-ask-summary.js +18 -13
- package/dist/runs/human-ask-summary.js.map +1 -1
- package/dist/runs/legacy-index.d.ts +62 -0
- package/dist/runs/legacy-index.js +168 -0
- package/dist/runs/legacy-index.js.map +1 -0
- package/dist/runs/raw-record.d.ts +52 -0
- package/dist/runs/raw-record.js +145 -0
- package/dist/runs/raw-record.js.map +1 -0
- package/dist/runs/retention.d.ts +13 -6
- package/dist/runs/retention.js +42 -13
- package/dist/runs/retention.js.map +1 -1
- package/dist/runs/run-claims.d.ts +23 -0
- package/dist/runs/run-claims.js +24 -0
- package/dist/runs/run-claims.js.map +1 -0
- package/dist/runs/run-database.d.ts +385 -0
- package/dist/runs/run-database.js +930 -0
- package/dist/runs/run-database.js.map +1 -0
- package/dist/runs/run-index.d.ts +35 -9
- package/dist/runs/run-index.js +200 -25
- package/dist/runs/run-index.js.map +1 -1
- package/dist/runs/run-row.d.ts +44 -0
- package/dist/runs/run-row.js +84 -0
- package/dist/runs/run-row.js.map +1 -0
- package/dist/runs/run-search.d.ts +29 -0
- package/dist/runs/run-search.js +63 -0
- package/dist/runs/run-search.js.map +1 -0
- package/dist/runs/store-open-error.d.ts +24 -0
- package/dist/runs/store-open-error.js +61 -0
- package/dist/runs/store-open-error.js.map +1 -0
- package/dist/runs/store.d.ts +667 -32
- package/dist/runs/store.js +2153 -324
- package/dist/runs/store.js.map +1 -1
- package/dist/runs/transcript-facts.d.ts +77 -0
- package/dist/runs/transcript-facts.js +302 -0
- package/dist/runs/transcript-facts.js.map +1 -0
- package/dist/runs/webhook.js +5 -4
- package/dist/runs/webhook.js.map +1 -1
- package/dist/runs/worker-execution.d.ts +22 -0
- package/dist/runs/worker-execution.js +30 -0
- package/dist/runs/worker-execution.js.map +1 -0
- package/dist/server/capabilities.d.ts +1 -0
- package/dist/server/capabilities.js +2 -0
- package/dist/server/capabilities.js.map +1 -1
- package/dist/server/cockpit-ownership.d.ts +8 -0
- package/dist/server/cockpit-ownership.js +19 -0
- package/dist/server/cockpit-ownership.js.map +1 -1
- package/dist/server/forge/github.d.ts +1 -4
- package/dist/server/forge/github.js +47 -23
- package/dist/server/forge/github.js.map +1 -1
- package/dist/server/git.js +1 -1
- package/dist/server/git.js.map +1 -1
- package/dist/server/open-in-app.js +1 -0
- package/dist/server/open-in-app.js.map +1 -1
- package/dist/server/preview-socket.d.ts +36 -0
- package/dist/server/preview-socket.js +126 -0
- package/dist/server/preview-socket.js.map +1 -0
- package/dist/server/project-context.d.ts +31 -4
- package/dist/server/project-context.js +73 -9
- package/dist/server/project-context.js.map +1 -1
- package/dist/server/provider-action-gate.js +1 -0
- package/dist/server/provider-action-gate.js.map +1 -1
- package/dist/server/repo-branches.d.ts +4 -3
- package/dist/server/repo-branches.js +5 -4
- package/dist/server/repo-branches.js.map +1 -1
- package/dist/server/server.d.ts +4500 -2727
- package/dist/server/server.js +651 -202
- package/dist/server/server.js.map +1 -1
- package/dist/server/upgrade-router.d.ts +23 -0
- package/dist/server/upgrade-router.js +53 -0
- package/dist/server/upgrade-router.js.map +1 -0
- package/dist/server/validators.d.ts +6 -1
- package/dist/server/validators.js +4 -4
- package/dist/server/validators.js.map +1 -1
- package/dist/server/ws.d.ts +16 -16
- package/dist/server/ws.js +56 -54
- package/dist/server/ws.js.map +1 -1
- package/dist/skills-remote.d.ts +14 -0
- package/dist/skills-remote.js +91 -15
- package/dist/skills-remote.js.map +1 -1
- package/dist/task-cli/cli.js +40 -16
- package/dist/task-cli/cli.js.map +1 -1
- package/dist/task-cli/discovery.d.ts +4 -3
- package/dist/task-cli/discovery.js +4 -3
- package/dist/task-cli/discovery.js.map +1 -1
- package/dist/task-cli/http.d.ts +2 -0
- package/dist/task-cli/http.js +10 -4
- package/dist/task-cli/http.js.map +1 -1
- package/dist/task-cli/projections.d.ts +5 -2
- package/dist/task-cli/projections.js +13 -0
- package/dist/task-cli/projections.js.map +1 -1
- package/dist/task-cli/watch.d.ts +15 -2
- package/dist/task-cli/watch.js +31 -9
- package/dist/task-cli/watch.js.map +1 -1
- package/dist/ui-state.d.ts +4 -3
- package/dist/ui-state.js +8 -3
- package/dist/ui-state.js.map +1 -1
- package/dist/workflows/grouped-command.d.ts +31 -0
- package/dist/workflows/grouped-command.js +143 -0
- package/dist/workflows/grouped-command.js.map +1 -0
- package/dist/workflows/run.d.ts +223 -42
- package/dist/workflows/run.js +1316 -398
- package/dist/workflows/run.js.map +1 -1
- package/dist/workflows/types.d.ts +12 -0
- package/dist/workflows/types.js +20 -0
- package/dist/workflows/types.js.map +1 -1
- package/dist/workspace/agent-accounts.d.ts +5 -1
- package/dist/workspace/agent-accounts.js +1 -0
- package/dist/workspace/agent-accounts.js.map +1 -1
- package/dist/workspace/agent-profiles.js +1 -1
- package/dist/workspace/agent-profiles.js.map +1 -1
- package/dist/workspace/config.d.ts +3 -1
- package/dist/workspace/config.js +1 -0
- package/dist/workspace/config.js.map +1 -1
- package/dist/worktree-setup.d.ts +85 -0
- package/dist/worktree-setup.js +164 -0
- package/dist/worktree-setup.js.map +1 -0
- package/package.json +7 -5
- package/scripts/benchmark-run-store-fixture.ts +428 -0
- package/scripts/benchmark-run-store.ts +743 -0
- package/scripts/benchmark-stuck-destroys.ts +143 -0
- package/scripts/mock-autonomous.mjs +11 -0
- package/scripts/mock-ci-tool.mjs +20 -5
- package/scripts/mock-claude.mjs +110 -1
- package/scripts/mock-codex-app-server.mjs +117 -2
- package/scripts/mock-codex-coalesce-steer.mjs +59 -0
- package/scripts/mock-codex-reverse-steer.mjs +130 -0
- package/scripts/mock-cursor-acp.mjs +75 -1
- package/scripts/mock-omp-rpc.mjs +605 -0
- package/scripts/mock-opencode-serve.mjs +312 -22
- package/scripts/mock-pi-rpc.mjs +109 -3
- package/scripts/mock-runner-crash.mjs +42 -0
- package/scripts/mock-silent-tail.mjs +78 -0
- package/scripts/mock-turn-messages.mjs +5 -0
- package/scripts/omp-ci-wait.mjs +29 -0
- package/scripts/omp-restrict-delegation.yml +4 -0
- package/scripts/pi-ci-wait.mjs +12 -9
- package/scripts/seed-archive-profile.ts +3 -3
- package/web/dist/assets/agent-accounts-CFOBMVHc.js +1 -0
- package/web/dist/assets/alert-dialog-BrpNUwMt.js +1 -0
- package/web/dist/assets/app-window-CSHwDX9N.js +1 -0
- package/web/dist/assets/button-C_rd7CPp.js +43 -0
- package/web/dist/assets/compare-variants-D6WXhvXA.js +1 -0
- package/web/dist/assets/diff-DrEARXTV.js +3 -0
- package/web/dist/assets/diff-controls-B1-j7nFg.js +1 -0
- package/web/dist/assets/{diff-view-DPn6bQ5W.js → diff-view-DvGLjdTk.js} +3 -3
- package/web/dist/assets/dropdown-menu-BegOZFrj.js +1 -0
- package/web/dist/assets/format-DpNe3S0A.js +1 -0
- package/web/dist/assets/git-toolbar-Cw4ljmhB.js +1 -0
- package/web/dist/assets/github-CfV5sqL0.js +1 -0
- package/web/dist/assets/{image-preview-DJ8cgb1Z.js → image-preview-FOEfqpZP.js} +1 -1
- package/web/dist/assets/index-DgWWlOLy.js +13 -0
- package/web/dist/assets/index-fBFnuvxu.css +1 -0
- package/web/dist/assets/{nav-row-styles-3j64kH5s.js → nav-row-styles-vp2JbhuJ.js} +1 -1
- package/web/dist/assets/play-CmVAj_fu.js +1 -0
- package/web/dist/assets/popover-BohP6WTx.js +1 -0
- package/web/dist/assets/preview-pane-connected-qTA5KNoJ.js +3 -0
- package/web/dist/assets/preview-state-vuMviq6q.js +1 -0
- package/web/dist/assets/prompt-templates-Cubdut_C.js +15 -0
- package/web/dist/assets/repo-git-Cf4t5PD0.js +1 -0
- package/web/dist/assets/{run-diff-5-RRdcVz.js → run-diff-BpkUW37Z.js} +3 -3
- package/web/dist/assets/run-header-68WHf9wV.js +1 -0
- package/web/dist/assets/skills-DiVIgKeU.js +1 -0
- package/web/dist/assets/square-terminal-B6RYYieR.js +1 -0
- package/web/dist/assets/status-dot-CqTJHSP9.js +1 -0
- package/web/dist/assets/{tab-link-K0hjzEXR.js → tab-link-B07Hu4QX.js} +1 -1
- package/web/dist/assets/task-changes--lQF6EYf.js +1 -0
- package/web/dist/assets/task-commits-Cx0qy4DN.js +1 -0
- package/web/dist/assets/task-files-D50s-gKW.js +2 -0
- package/web/dist/assets/task-github-item-DaqmSwYT.js +1 -0
- package/web/dist/assets/task-thread-BPQ64lui.js +7 -0
- package/web/dist/assets/{task-thread-Bw_nQuTx.css → task-thread-zNE2Q9E-.css} +1 -1
- package/web/dist/assets/textarea-D20O4Pw0.js +1 -0
- package/web/dist/assets/thread-state-DWcFMrvb.js +4 -0
- package/web/dist/assets/use-hand-to-agent-state-BLIGmwbd.css +1 -0
- package/web/dist/assets/use-hand-to-agent-state-Cy9eyyfL.js +1 -0
- package/web/dist/assets/{utils-fzNfbPzA.js → utils-JsL3ZsJf.js} +1 -1
- package/web/dist/assets/workflows-jwG7uxqi.js +11 -0
- package/web/dist/assets/{zoomable-image-CDmZ_Rtl.js → zoomable-image-BJJ64KGc.js} +1 -1
- package/web/dist/cezarion-lockup-dark.svg +1 -13
- package/web/dist/cezarion-lockup-light.svg +1 -13
- package/web/dist/cezarion-mark-dark.svg +1 -12
- package/web/dist/cezarion-mark-light.svg +1 -12
- package/web/dist/index.html +16 -21
- package/web/dist/assets/agent-accounts-CU2ZDv24.js +0 -1
- package/web/dist/assets/alert-dialog-C-xYE_dg.js +0 -43
- package/web/dist/assets/chevron-right-BENZ-1ZN.js +0 -1
- package/web/dist/assets/collapsible-DD9J91Iv.js +0 -1
- package/web/dist/assets/compare-variants-5FmqpFSN.js +0 -1
- package/web/dist/assets/diff-controls-Bj0YrioE.js +0 -1
- package/web/dist/assets/diff-rE8rm75J2.js +0 -3
- package/web/dist/assets/diff-stat-BKDCSVfJ.js +0 -1
- package/web/dist/assets/dropdown-menu-Ch5BYQh_.js +0 -1
- package/web/dist/assets/format-dBiNDNVe.js +0 -1
- package/web/dist/assets/git-toolbar-ClVvf5iF.js +0 -1
- package/web/dist/assets/github-BkNOyour.css +0 -1
- package/web/dist/assets/github-DeZMeMwJ.js +0 -1
- package/web/dist/assets/github-item-detail-W5F6GVjF.js +0 -1
- package/web/dist/assets/github-sidebar-model-DcMu-IK2.js +0 -1
- package/web/dist/assets/highlighter-CdHqIwFr.js +0 -3
- package/web/dist/assets/index-CatemBEL.js +0 -8
- package/web/dist/assets/index-MvfD8bZJ.css +0 -1
- package/web/dist/assets/markdown-zdKeLIYA.js +0 -2
- package/web/dist/assets/mobile-run-bar-BCfmFi8V.js +0 -1
- package/web/dist/assets/prompt-templates-CBPp39IU.js +0 -15
- package/web/dist/assets/reference-chip-D6owncJT.js +0 -1
- package/web/dist/assets/repo-git-CtdkZFey.js +0 -1
- package/web/dist/assets/run-header-BcjoDi0W.js +0 -1
- package/web/dist/assets/sheet-ChnYVrp1.js +0 -1
- package/web/dist/assets/skills-C8YKp2vr.js +0 -1
- package/web/dist/assets/task-changes-BW8YdWG8.js +0 -1
- package/web/dist/assets/task-commits-q2kB2y6L.js +0 -1
- package/web/dist/assets/task-files-pPL6_3Cr.js +0 -2
- package/web/dist/assets/task-github-item-BXF5R52U.js +0 -1
- package/web/dist/assets/task-thread-DtkFL3EC.js +0 -10
- package/web/dist/assets/textarea-DxlkE-Yd.js +0 -1
- package/web/dist/assets/token-metrics-DIAjrPlM.js +0 -1
- package/web/dist/assets/use-desktop-CrDny2uG.js +0 -1
- package/web/dist/assets/use-submit-shortcut-KWJsC906.js +0 -1
- package/web/dist/assets/workflows-TmcPEj2K.js +0 -11
- /package/web/dist/assets/{lib-BQXq3kEf2.js → lib-BQXq3kEf.js} +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { nextOccurrence, occurrencesBetween } from '../contract/index.js';
|
|
2
|
+
import { isScheduleAutomation } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The schedule kind's evaluator (spec 2026-10-02-scheduled-automations § Lifecycle): what fires
|
|
5
|
+
* when a scheduled automation's occurrence comes due, by the timer or by hand.
|
|
6
|
+
*
|
|
7
|
+
* The one rule that matters is the AGE rule in `fire`: how late the occurrence is decides what
|
|
8
|
+
* happens — on time (within the grace window) it is `launched`; late but within a day, the
|
|
9
|
+
* LATEST missed occurrence fires once as `catch-up`; older, nothing fires and the log says how
|
|
10
|
+
* many were skipped. The same rule applies whether the timer fired on time, the laptop slept, or
|
|
11
|
+
* cezar just booted, and `nextRunAt` always advances from `max(occurrence, now)` — which is what
|
|
12
|
+
* makes a burst impossible: a daily that slept three days fires one catch-up, not three.
|
|
13
|
+
*
|
|
14
|
+
* Everything runs under the #651 project lease. A held (or lost) lease is the one case that
|
|
15
|
+
* must NOT advance `nextRunAt`: the state file is shared, so the loser moving it on would make
|
|
16
|
+
* the winner — firing from the same on-disk state — skip the occurrence entirely. The loser logs
|
|
17
|
+
* `skipped` and throws `ScheduleLeaseHeldError`, so the workspace floor retries it; by then the
|
|
18
|
+
* winner's receipt turns the retry into a `duplicate`, never a second launch. Held leases and
|
|
19
|
+
* duplicates are not failures and do not count towards the three-strike auto-pause.
|
|
20
|
+
*/
|
|
21
|
+
export const SCHEDULE_GRACE_MS = 10 * 60_000;
|
|
22
|
+
export const SCHEDULE_CATCH_UP_MS = 24 * 60 * 60_000;
|
|
23
|
+
export const SCHEDULE_AUTO_PAUSE_AFTER = 3;
|
|
24
|
+
/** The cap the missed-occurrence count runs under: a count that reaches it is a lower bound. */
|
|
25
|
+
const OCCURRENCE_LIMIT = 1_000;
|
|
26
|
+
export const SCHEDULE_LEASE_HELD_REASON = 'automation lease is held by another process; retrying shortly';
|
|
27
|
+
/** `fire` met a held or non-current lease; the workspace timer re-arms it at the retry floor. */
|
|
28
|
+
export class ScheduleLeaseHeldError extends Error {
|
|
29
|
+
constructor() { super(SCHEDULE_LEASE_HELD_REASON); }
|
|
30
|
+
}
|
|
31
|
+
/** The project cannot launch a task now: its run store cannot open (#779). Not a launch failure,
|
|
32
|
+
* so it never counts towards the auto-pause or a poll's backoff; the timer retries at its floor. */
|
|
33
|
+
export class AutomationProjectUnavailableError extends Error {
|
|
34
|
+
constructor(message, options = {}) {
|
|
35
|
+
super(message, options);
|
|
36
|
+
this.name = 'AutomationProjectUnavailableError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class ScheduleRunner {
|
|
40
|
+
handle;
|
|
41
|
+
constructor(handle) {
|
|
42
|
+
this.handle = handle;
|
|
43
|
+
}
|
|
44
|
+
now() {
|
|
45
|
+
return this.handle.now?.() ?? Date.now();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* When the timer should next fire this definition: the stored `nextRunAt`, or — for a
|
|
49
|
+
* definition never armed, or whose schedule was edited (the PUT clears `nextRunAt`) — the next
|
|
50
|
+
* occurrence after now, which is then persisted so every process agrees on it.
|
|
51
|
+
*/
|
|
52
|
+
dueAt(definition) {
|
|
53
|
+
const state = this.handle.store.state(definition.id) ?? {};
|
|
54
|
+
if (state.nextRunAt)
|
|
55
|
+
return Date.parse(state.nextRunAt);
|
|
56
|
+
const next = nextOccurrence(definition.schedule, this.now(), this.handle.timeZone);
|
|
57
|
+
if (next === null)
|
|
58
|
+
return null;
|
|
59
|
+
this.handle.store.setState(definition.id, (current) => ({ ...current, revision: definition.revision, nextRunAt: new Date(next).toISOString() }));
|
|
60
|
+
return next;
|
|
61
|
+
}
|
|
62
|
+
/** The timer fired (or boot found a past-due occurrence): apply the age rule and launch. */
|
|
63
|
+
async fire(definition) {
|
|
64
|
+
const outcome = await this.underLease(async () => {
|
|
65
|
+
// The timer captured `definition` from this process's view; another cockpit may have
|
|
66
|
+
// paused, edited or deleted it since. Re-read it under the lease and fire only the
|
|
67
|
+
// revision that is still on disk. Anything else launches nothing and moves nothing —
|
|
68
|
+
// the process that changed it owns `nextRunAt` — and `onChange` re-arms from the fresh view.
|
|
69
|
+
this.handle.store.reload();
|
|
70
|
+
const current = this.handle.store.get(definition.id);
|
|
71
|
+
if (!current?.enabled || !isScheduleAutomation(current) || current.revision !== definition.revision) {
|
|
72
|
+
this.handle.onChange?.(definition.id, current?.revision ?? definition.revision);
|
|
73
|
+
return { result: 'skipped' };
|
|
74
|
+
}
|
|
75
|
+
const now = this.now();
|
|
76
|
+
const due = this.dueAt(definition);
|
|
77
|
+
if (due === null)
|
|
78
|
+
return { result: 'skipped' };
|
|
79
|
+
const advance = { armedAt: this.handle.store.state(definition.id)?.nextRunAt };
|
|
80
|
+
// Not due yet: another cockpit (or a PUT) moved `nextRunAt` after this fire was armed.
|
|
81
|
+
if (due > now)
|
|
82
|
+
return { result: 'skipped', occurrenceAt: new Date(due).toISOString() };
|
|
83
|
+
if (now - due <= SCHEDULE_GRACE_MS) {
|
|
84
|
+
await this.handle.ready?.();
|
|
85
|
+
return this.launch(definition, { at: new Date(due).toISOString(), trigger: 'schedule' }, now, advance);
|
|
86
|
+
}
|
|
87
|
+
// Late. Every occurrence from the due one up to now was missed; the newest may catch up.
|
|
88
|
+
const missed = this.missed(definition, due, now);
|
|
89
|
+
const latest = missed.latest;
|
|
90
|
+
if (now - latest <= SCHEDULE_CATCH_UP_MS) {
|
|
91
|
+
await this.handle.ready?.();
|
|
92
|
+
if (missed.count > 1)
|
|
93
|
+
await this.logSkipped(definition, missed.count - 1, missed.atLeast, true);
|
|
94
|
+
return this.launch(definition, { at: new Date(latest).toISOString(), trigger: 'catch-up' }, now, advance);
|
|
95
|
+
}
|
|
96
|
+
await this.logSkipped(definition, missed.count, missed.atLeast, false);
|
|
97
|
+
this.advance(definition, now, now, advance);
|
|
98
|
+
return { result: 'skipped', occurrenceAt: new Date(latest).toISOString() };
|
|
99
|
+
});
|
|
100
|
+
if (outcome)
|
|
101
|
+
return outcome;
|
|
102
|
+
await this.handle.store.appendLog({ automationId: definition.id, revision: definition.revision, result: 'skipped', reason: SCHEDULE_LEASE_HELD_REASON });
|
|
103
|
+
this.handle.onChange?.(definition.id, definition.revision);
|
|
104
|
+
throw new ScheduleLeaseHeldError();
|
|
105
|
+
}
|
|
106
|
+
/** `POST /automations/:id/run`: fire now, by hand, paused or not; `nextRunAt` is untouched. */
|
|
107
|
+
async runNow(definition) {
|
|
108
|
+
const outcome = await this.underLease(async () => {
|
|
109
|
+
const current = this.currentUnderLease(definition);
|
|
110
|
+
if (!current)
|
|
111
|
+
return { result: 'skipped' };
|
|
112
|
+
const now = this.now();
|
|
113
|
+
return this.launch(current, { at: new Date(now).toISOString(), trigger: 'manual' }, now, null);
|
|
114
|
+
});
|
|
115
|
+
return outcome ?? { result: 'lease-held' };
|
|
116
|
+
}
|
|
117
|
+
/** Retry a `launch-error` receipt of this kind: the same receipt, fired again by hand. */
|
|
118
|
+
async retry(definition, receipt) {
|
|
119
|
+
const occurrenceAt = receipt.occurrenceAt ?? new Date(this.now()).toISOString();
|
|
120
|
+
const outcome = await this.underLease(async () => {
|
|
121
|
+
const current = this.currentUnderLease(definition);
|
|
122
|
+
if (!current)
|
|
123
|
+
return { result: 'skipped', occurrenceAt };
|
|
124
|
+
const now = this.now();
|
|
125
|
+
// Re-checked under the lease: another retry may have relaunched it since the caller read it.
|
|
126
|
+
if (this.handle.store.latestReceipts().get(receipt.receiptKey)?.status !== 'launch-error') {
|
|
127
|
+
return { result: 'duplicate', occurrenceAt };
|
|
128
|
+
}
|
|
129
|
+
const reserved = { ...receipt, status: 'reserved', error: undefined, updatedAt: new Date(now).toISOString() };
|
|
130
|
+
this.handle.store.appendReceipt(reserved);
|
|
131
|
+
return this.launchReserved(current, { at: occurrenceAt, trigger: 'manual' }, reserved, now, null);
|
|
132
|
+
});
|
|
133
|
+
return outcome ?? { result: 'lease-held', occurrenceAt };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Run now and Retry act on this process's cached definition, which another cockpit may have
|
|
137
|
+
* edited or deleted since. Re-read it under the lease: the fresh schedule definition (paused is
|
|
138
|
+
* fine, those are manual actions), or `undefined` after notifying when it is gone or no longer
|
|
139
|
+
* a schedule, so the caller launches and writes nothing.
|
|
140
|
+
*/
|
|
141
|
+
currentUnderLease(definition) {
|
|
142
|
+
this.handle.store.reload();
|
|
143
|
+
const current = this.handle.store.get(definition.id);
|
|
144
|
+
if (current && isScheduleAutomation(current))
|
|
145
|
+
return current;
|
|
146
|
+
this.handle.onChange?.(definition.id, current?.revision ?? definition.revision);
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
/** Runs `operation` under the project lease; `undefined` when the lease is held or not current. */
|
|
150
|
+
async underLease(operation) {
|
|
151
|
+
const { store } = this.handle;
|
|
152
|
+
let lease = store.acquireLease();
|
|
153
|
+
if (lease && !lease.isCurrent()) {
|
|
154
|
+
lease.release();
|
|
155
|
+
lease = undefined;
|
|
156
|
+
}
|
|
157
|
+
if (!lease)
|
|
158
|
+
return undefined;
|
|
159
|
+
try {
|
|
160
|
+
return await operation();
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
try {
|
|
164
|
+
await store.maybeCompact();
|
|
165
|
+
}
|
|
166
|
+
catch { /* append-only state remains readable; next fire retries */ }
|
|
167
|
+
lease.release();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async launch(definition, occurrence, now, advance) {
|
|
171
|
+
const { store } = this.handle;
|
|
172
|
+
const eventId = occurrence.trigger === 'manual' ? `manual:${occurrence.at}` : `schedule:${occurrence.at}`;
|
|
173
|
+
const receipt = store.reserveReceipt({ automationId: definition.id, revision: definition.revision, eventId, occurrenceAt: occurrence.at });
|
|
174
|
+
if (!receipt) {
|
|
175
|
+
// Under the lease nobody else is launching, so a `reserved` receipt this process is not
|
|
176
|
+
// running is a crash leftover: settle it first (see `reconcile`). One in flight here is a
|
|
177
|
+
// live launch its launcher settles, and is left alone.
|
|
178
|
+
const existing = store.latestReceipts().get(`${definition.id}:${eventId}`);
|
|
179
|
+
if (existing?.status === 'reserved' && !store.isReservationInFlight(existing.receiptId))
|
|
180
|
+
await this.handle.reconcile?.();
|
|
181
|
+
await store.appendLog({ automationId: definition.id, revision: definition.revision, result: 'duplicate', reason: `A durable receipt already exists for the ${occurrence.at} occurrence.` });
|
|
182
|
+
if (advance)
|
|
183
|
+
this.advance(definition, Date.parse(occurrence.at), now, advance);
|
|
184
|
+
return { result: 'duplicate', occurrenceAt: occurrence.at };
|
|
185
|
+
}
|
|
186
|
+
return this.launchReserved(definition, occurrence, receipt, now, advance);
|
|
187
|
+
}
|
|
188
|
+
async launchReserved(definition, occurrence, receipt, now, advance) {
|
|
189
|
+
const { store } = this.handle;
|
|
190
|
+
if (!this.handle.launch) {
|
|
191
|
+
store.appendReceipt({ ...receipt, status: 'launch-error', error: 'This cockpit cannot launch tasks.', updatedAt: new Date(now).toISOString() });
|
|
192
|
+
if (advance)
|
|
193
|
+
this.advance(definition, Date.parse(occurrence.at), now, advance);
|
|
194
|
+
return { result: 'detection-only', occurrenceAt: occurrence.at };
|
|
195
|
+
}
|
|
196
|
+
const started = Date.now();
|
|
197
|
+
const result = occurrence.trigger === 'schedule' ? 'launched' : occurrence.trigger;
|
|
198
|
+
let runId;
|
|
199
|
+
try {
|
|
200
|
+
({ runId } = await this.handle.launch(definition, occurrence, receipt.receiptId));
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
204
|
+
store.appendReceipt({ ...receipt, status: 'launch-error', error: message, updatedAt: new Date(this.now()).toISOString() });
|
|
205
|
+
await store.appendLog({ automationId: definition.id, revision: definition.revision, result: 'failed', reason: message, receiptId: receipt.receiptId, durationMs: Date.now() - started });
|
|
206
|
+
// Only the timer counts towards the auto-pause: Run now and Retry leave `enabled` alone.
|
|
207
|
+
if (advance)
|
|
208
|
+
await this.recordFailure(definition, occurrence, now, advance);
|
|
209
|
+
else
|
|
210
|
+
this.handle.onChange?.(definition.id, definition.revision);
|
|
211
|
+
return { result: 'failed', occurrenceAt: occurrence.at };
|
|
212
|
+
}
|
|
213
|
+
store.appendReceipt({ ...receipt, status: 'launched', runId, updatedAt: new Date(this.now()).toISOString() });
|
|
214
|
+
await store.appendLog({
|
|
215
|
+
automationId: definition.id, revision: definition.revision, result,
|
|
216
|
+
reason: reasonFor(occurrence, this.handle.timeZone),
|
|
217
|
+
receiptId: receipt.receiptId, runId, durationMs: Date.now() - started,
|
|
218
|
+
});
|
|
219
|
+
store.setState(definition.id, (current) => ({
|
|
220
|
+
...current,
|
|
221
|
+
...(advance ? { ...this.advanced(current, definition, Date.parse(occurrence.at), now, advance), lastRunAt: occurrence.at } : { revision: Math.max(current.revision ?? 0, definition.revision) }),
|
|
222
|
+
lastSuccessAt: new Date(this.now()).toISOString(),
|
|
223
|
+
consecutiveFailures: 0,
|
|
224
|
+
}));
|
|
225
|
+
this.handle.onChange?.(definition.id, definition.revision);
|
|
226
|
+
return { result, runId, occurrenceAt: occurrence.at };
|
|
227
|
+
}
|
|
228
|
+
async recordFailure(definition, occurrence, now, advance) {
|
|
229
|
+
const { store } = this.handle;
|
|
230
|
+
const next = store.setState(definition.id, (current) => ({
|
|
231
|
+
...current,
|
|
232
|
+
...this.advanced(current, definition, Date.parse(occurrence.at), now, advance),
|
|
233
|
+
consecutiveFailures: (current.consecutiveFailures ?? 0) + 1,
|
|
234
|
+
}));
|
|
235
|
+
if ((next.consecutiveFailures ?? 0) >= SCHEDULE_AUTO_PAUSE_AFTER) {
|
|
236
|
+
const paused = this.pause(definition.id);
|
|
237
|
+
if (paused) {
|
|
238
|
+
await store.appendLog({ automationId: paused.id, revision: paused.revision, result: 'failed', reason: `Paused after ${SCHEDULE_AUTO_PAUSE_AFTER} consecutive launch failures; fix the task and enable it again.` });
|
|
239
|
+
this.handle.onChange?.(paused.id, paused.revision);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
this.handle.onChange?.(definition.id, definition.revision);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Pauses the CURRENT revision, not the one this fire started with: the definition may have been
|
|
247
|
+
* edited while the launch ran — here or in another cockpit, hence the re-read — and the failure
|
|
248
|
+
* count belongs to the automation, not to a revision. Pausing the stale copy would either
|
|
249
|
+
* conflict or revert the edit. Already paused, deleted or no longer a schedule: nothing to do.
|
|
250
|
+
*/
|
|
251
|
+
pause(id) {
|
|
252
|
+
this.handle.store.reload();
|
|
253
|
+
const current = this.handle.store.get(id);
|
|
254
|
+
if (!current?.enabled || current.kind !== 'schedule')
|
|
255
|
+
return undefined;
|
|
256
|
+
const { revision, createdAt: _c, updatedAt: _u, id: _id, ...editable } = current;
|
|
257
|
+
try {
|
|
258
|
+
return this.handle.store.update(id, revision, { ...editable, enabled: false }, () => ({ nextRunAt: undefined }));
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Edited or deleted in between; the next failure pauses whatever is current then.
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
advance(definition, fromMs, now, advance) {
|
|
266
|
+
this.handle.store.setState(definition.id, (current) => ({
|
|
267
|
+
...current,
|
|
268
|
+
...this.advanced(current, definition, fromMs, now, advance),
|
|
269
|
+
}));
|
|
270
|
+
this.handle.onChange?.(definition.id, definition.revision);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The `revision`/`nextRunAt` pair a timer fire writes. An edit that landed meanwhile already
|
|
274
|
+
* bumped the state's revision (never moved back) and, when it changed the schedule or resumed
|
|
275
|
+
* the definition, re-armed `nextRunAt` — which then stands. An edit that left `nextRunAt`
|
|
276
|
+
* alone (a rename) left the schedule alone too, so advancing from the captured one is right.
|
|
277
|
+
*/
|
|
278
|
+
advanced(current, definition, fromMs, now, advance) {
|
|
279
|
+
const revision = Math.max(current.revision ?? 0, definition.revision);
|
|
280
|
+
if (current.nextRunAt !== advance.armedAt)
|
|
281
|
+
return { revision, nextRunAt: current.nextRunAt };
|
|
282
|
+
return { revision, nextRunAt: nextIso(definition, Math.max(fromMs, now), this.handle.timeZone) };
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The occurrences in `[due, now]`: the latest one and how many there are. `occurrencesBetween`
|
|
286
|
+
* stops at its cap EARLIEST-first, so the latest is searched for on its own — in the catch-up
|
|
287
|
+
* window, else in the week before it (every shape recurs within 7 days; 9 covers a DST week) —
|
|
288
|
+
* and a count that reached the cap is reported as a lower bound, never as an exact number.
|
|
289
|
+
*/
|
|
290
|
+
missed(definition, due, now) {
|
|
291
|
+
const { schedule } = definition;
|
|
292
|
+
const { timeZone } = this.handle;
|
|
293
|
+
const windowStart = Math.max(due, now - SCHEDULE_CATCH_UP_MS);
|
|
294
|
+
const recent = occurrencesBetween(schedule, windowStart, now + 1, timeZone);
|
|
295
|
+
const older = occurrencesBetween(schedule, due, windowStart, timeZone, OCCURRENCE_LIMIT);
|
|
296
|
+
const latest = recent.at(-1)
|
|
297
|
+
?? occurrencesBetween(schedule, Math.max(due, windowStart - 9 * 86_400_000), windowStart, timeZone).at(-1)
|
|
298
|
+
?? due;
|
|
299
|
+
return { latest, count: recent.length + older.length, atLeast: older.length >= OCCURRENCE_LIMIT };
|
|
300
|
+
}
|
|
301
|
+
async logSkipped(definition, total, atLeast, latestCaughtUp) {
|
|
302
|
+
const count = atLeast ? `at least ${total}` : String(total);
|
|
303
|
+
const plural = total === 1 ? '' : 's';
|
|
304
|
+
await this.handle.store.appendLog({
|
|
305
|
+
automationId: definition.id,
|
|
306
|
+
revision: definition.revision,
|
|
307
|
+
result: 'skipped',
|
|
308
|
+
reason: latestCaughtUp
|
|
309
|
+
? `Missed ${count} older occurrence${plural} while cezar was not running or the machine was asleep; only the latest one caught up.`
|
|
310
|
+
: `Missed ${count} occurrence${plural} while cezar was not running or the machine was asleep; nothing was launched for them.`,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function nextIso(definition, afterMs, timeZone) {
|
|
315
|
+
const next = nextOccurrence(definition.schedule, afterMs, timeZone);
|
|
316
|
+
return next === null ? undefined : new Date(next).toISOString();
|
|
317
|
+
}
|
|
318
|
+
function reasonFor(occurrence, timeZone) {
|
|
319
|
+
const when = new Intl.DateTimeFormat('en-GB', { timeZone, weekday: 'short', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }).format(new Date(occurrence.at));
|
|
320
|
+
switch (occurrence.trigger) {
|
|
321
|
+
case 'schedule': return `Scheduled run at ${when}.`;
|
|
322
|
+
case 'catch-up': return `Caught up the ${when} occurrence missed while cezar was not running or the machine was asleep.`;
|
|
323
|
+
case 'manual': return `Started by hand at ${when}.`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=schedule-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule-runner.js","sourceRoot":"","sources":["../../src/automations/schedule-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import type { AutomationCoordinator } from './coordinator.ts';
|
|
2
2
|
import type { GithubCandidate, GithubPoller, GithubPollResult } from './github-poller.ts';
|
|
3
|
+
import { type ScheduleLauncher } from './schedule-runner.ts';
|
|
3
4
|
import type { AutomationStore } from './store.ts';
|
|
4
|
-
import type
|
|
5
|
+
import { type GithubAutomationDefinition } from './types.ts';
|
|
5
6
|
export interface AutomationLaunchResult {
|
|
6
7
|
runId: string;
|
|
7
8
|
}
|
|
8
|
-
export type AutomationLauncher = (definition:
|
|
9
|
+
export type AutomationLauncher = (definition: GithubAutomationDefinition, candidate: GithubCandidate, receiptId: string) => Promise<AutomationLaunchResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Everything one project needs on the workspace timer. Every registered project gets one; only a
|
|
12
|
+
* project with a github.com remote carries `github`, so its polls can fire — a schedule needs no
|
|
13
|
+
* remote (spec 2026-10-02-scheduled-automations § Architecture).
|
|
14
|
+
*/
|
|
9
15
|
export interface ProjectAutomationHandle {
|
|
10
16
|
projectId: string;
|
|
11
|
-
owner: string;
|
|
12
|
-
repo: string;
|
|
13
17
|
store: AutomationStore;
|
|
14
|
-
|
|
18
|
+
/** The zone schedules are evaluated in — the server's own (`localTimeZone()`). */
|
|
19
|
+
timeZone: string;
|
|
20
|
+
github?: {
|
|
21
|
+
owner: string;
|
|
22
|
+
repo: string;
|
|
23
|
+
poller: GithubPoller;
|
|
24
|
+
};
|
|
15
25
|
launch?: AutomationLauncher;
|
|
26
|
+
launchSchedule?: ScheduleLauncher;
|
|
16
27
|
onChange?: (automationId: string, revision: number) => void;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
/** See `ScheduleRunnerHandle.reconcile`. */
|
|
30
|
+
reconcileReceipts?: () => Promise<void>;
|
|
31
|
+
/** See `ScheduleRunnerHandle.ready`; a poll asks it before it launches what it found. */
|
|
32
|
+
ready?: () => Promise<void>;
|
|
17
33
|
}
|
|
18
34
|
/** A different process currently owns this project's poll lock. */
|
|
19
35
|
export declare class LeaseHeldError extends Error {
|
|
@@ -22,17 +38,32 @@ export declare class LeaseHeldError extends Error {
|
|
|
22
38
|
export declare class ProjectAutomationScheduler {
|
|
23
39
|
private readonly handle;
|
|
24
40
|
constructor(handle: ProjectAutomationHandle);
|
|
25
|
-
check(definition:
|
|
41
|
+
check(definition: GithubAutomationDefinition, mode?: 'preview' | 'execute'): Promise<GithubPollResult>;
|
|
26
42
|
private launch;
|
|
27
43
|
private recordSkip;
|
|
28
44
|
private recordFailure;
|
|
29
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The longest the workspace timer sleeps before it looks at the wall clock again. Node timers
|
|
48
|
+
* count on a monotonic clock that stops while the machine is suspended, so one timer armed for
|
|
49
|
+
* the whole distance to a weekly occurrence would wake days late after a laptop slept. A capped
|
|
50
|
+
* wake that is not yet due re-arms without firing; the cap also keeps every delay far below
|
|
51
|
+
* `setTimeout`'s 2^31 ms overflow.
|
|
52
|
+
*/
|
|
53
|
+
export declare const WORKSPACE_TIMER_CAP_MS = 60000;
|
|
30
54
|
export interface WorkspaceAutomationSchedulerOptions {
|
|
31
55
|
coordinator: AutomationCoordinator;
|
|
32
56
|
handle: (projectId: string, store: AutomationStore) => ProjectAutomationHandle | undefined;
|
|
33
57
|
now?: () => number;
|
|
34
58
|
}
|
|
35
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* One workspace timer, running only while the scheduler is started (automations are opt-in) and at
|
|
61
|
+
* least one project is registered with the coordinator. With nothing enabled it is an idle wake
|
|
62
|
+
* at the cap, even before any project has a definitions file: every wake goes through
|
|
63
|
+
* `reschedule`, whose coordinator refresh re-reads a store another cockpit changed and opens a
|
|
64
|
+
* project whose definitions file appeared, so their edits arm here within one cap. No registered
|
|
65
|
+
* project: no timer.
|
|
66
|
+
*/
|
|
36
67
|
export declare class WorkspaceAutomationScheduler {
|
|
37
68
|
private readonly options;
|
|
38
69
|
private timer?;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AutomationProjectUnavailableError, ScheduleRunner } from './schedule-runner.js';
|
|
2
|
+
import { isGithubAutomation, isScheduleAutomation } from './types.js';
|
|
1
3
|
/** One request chain process-wide. The promise tail also prevents a failed request from
|
|
2
4
|
* poisoning later projects. */
|
|
3
5
|
class GithubRequestArbiter {
|
|
@@ -19,6 +21,9 @@ export class ProjectAutomationScheduler {
|
|
|
19
21
|
this.handle = handle;
|
|
20
22
|
}
|
|
21
23
|
async check(definition, mode = 'execute') {
|
|
24
|
+
const { github } = this.handle;
|
|
25
|
+
if (!github)
|
|
26
|
+
throw new Error('No GitHub remote is configured');
|
|
22
27
|
const detectionOnly = mode === 'execute' && !this.handle.launch;
|
|
23
28
|
if (detectionOnly)
|
|
24
29
|
mode = 'preview';
|
|
@@ -38,7 +43,7 @@ export class ProjectAutomationScheduler {
|
|
|
38
43
|
const overlapSince = since
|
|
39
44
|
? new Date(Date.parse(since) - 120_000).toISOString()
|
|
40
45
|
: undefined;
|
|
41
|
-
const result = await githubRequests.run(() =>
|
|
46
|
+
const result = await githubRequests.run(() => github.poller.poll(github.owner, github.repo, definition, { since: overlapSince }));
|
|
42
47
|
const eligible = result.candidates.filter((candidate) => {
|
|
43
48
|
if (state.baselineAt && candidate.timestamp <= state.baselineAt)
|
|
44
49
|
return false;
|
|
@@ -48,14 +53,16 @@ export class ProjectAutomationScheduler {
|
|
|
48
53
|
return Date.parse(candidate.timestamp) >= overlap;
|
|
49
54
|
});
|
|
50
55
|
if (mode === 'execute' && this.handle.launch) {
|
|
56
|
+
if (eligible.length > 0)
|
|
57
|
+
await this.handle.ready?.();
|
|
51
58
|
for (const candidate of eligible)
|
|
52
59
|
await this.launch(definition, candidate);
|
|
53
60
|
}
|
|
54
61
|
if (mode === 'execute') {
|
|
55
62
|
const now = new Date().toISOString();
|
|
56
63
|
const cursor = laterCursor(state.cursor, result.cursor);
|
|
57
|
-
store.setState(definition.id, {
|
|
58
|
-
...
|
|
64
|
+
store.setState(definition.id, (current) => ({
|
|
65
|
+
...current,
|
|
59
66
|
revision: definition.revision,
|
|
60
67
|
cursor,
|
|
61
68
|
frozenHighWatermark: result.truncated && cursor?.tieBreaker
|
|
@@ -65,14 +72,14 @@ export class ProjectAutomationScheduler {
|
|
|
65
72
|
nextCheckAt: new Date(Date.now() + definition.intervalSeconds * 1_000).toISOString(),
|
|
66
73
|
consecutiveFailures: 0,
|
|
67
74
|
backoffUntil: undefined,
|
|
68
|
-
});
|
|
75
|
+
}));
|
|
69
76
|
}
|
|
70
77
|
else if (detectionOnly) {
|
|
71
|
-
store.setState(definition.id, {
|
|
72
|
-
...
|
|
78
|
+
store.setState(definition.id, (current) => ({
|
|
79
|
+
...current,
|
|
73
80
|
revision: definition.revision,
|
|
74
81
|
nextCheckAt: new Date(Date.now() + definition.intervalSeconds * 1_000).toISOString(),
|
|
75
|
-
});
|
|
82
|
+
}));
|
|
76
83
|
}
|
|
77
84
|
this.handle.onChange?.(definition.id, definition.revision);
|
|
78
85
|
completion = mode === 'preview'
|
|
@@ -83,6 +90,8 @@ export class ProjectAutomationScheduler {
|
|
|
83
90
|
catch (error) {
|
|
84
91
|
if (error instanceof LeaseHeldError)
|
|
85
92
|
await this.recordSkip(definition, error);
|
|
93
|
+
// Not a failure: nothing was launched or moved, and the timer retries at its floor.
|
|
94
|
+
else if (error instanceof AutomationProjectUnavailableError) { /* see above */ }
|
|
86
95
|
else if (mode === 'execute')
|
|
87
96
|
await this.recordFailure(definition, error);
|
|
88
97
|
else
|
|
@@ -128,14 +137,15 @@ export class ProjectAutomationScheduler {
|
|
|
128
137
|
this.handle.onChange?.(definition.id, definition.revision);
|
|
129
138
|
}
|
|
130
139
|
async recordFailure(definition, error) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
this.handle.store.setState(definition.id, (current) => {
|
|
141
|
+
const failures = (current.consecutiveFailures ?? 0) + 1;
|
|
142
|
+
const delay = Math.min(6 * 60 * 60_000, 60_000 * 2 ** (failures - 1));
|
|
143
|
+
return {
|
|
144
|
+
...current,
|
|
145
|
+
consecutiveFailures: failures,
|
|
146
|
+
backoffUntil: new Date(Date.now() + delay).toISOString(),
|
|
147
|
+
nextCheckAt: new Date(Date.now() + delay).toISOString(),
|
|
148
|
+
};
|
|
139
149
|
});
|
|
140
150
|
await this.handle.store.appendLog({ automationId: definition.id, revision: definition.revision, result: 'error', reason: error instanceof Error ? error.message : String(error) });
|
|
141
151
|
this.handle.onChange?.(definition.id, definition.revision);
|
|
@@ -151,7 +161,22 @@ function laterCursor(current, observed) {
|
|
|
151
161
|
return order > 0 ? observed : current;
|
|
152
162
|
}
|
|
153
163
|
const MIN_RETRY_MS = 60_000;
|
|
154
|
-
/**
|
|
164
|
+
/**
|
|
165
|
+
* The longest the workspace timer sleeps before it looks at the wall clock again. Node timers
|
|
166
|
+
* count on a monotonic clock that stops while the machine is suspended, so one timer armed for
|
|
167
|
+
* the whole distance to a weekly occurrence would wake days late after a laptop slept. A capped
|
|
168
|
+
* wake that is not yet due re-arms without firing; the cap also keeps every delay far below
|
|
169
|
+
* `setTimeout`'s 2^31 ms overflow.
|
|
170
|
+
*/
|
|
171
|
+
export const WORKSPACE_TIMER_CAP_MS = 60_000;
|
|
172
|
+
/**
|
|
173
|
+
* One workspace timer, running only while the scheduler is started (automations are opt-in) and at
|
|
174
|
+
* least one project is registered with the coordinator. With nothing enabled it is an idle wake
|
|
175
|
+
* at the cap, even before any project has a definitions file: every wake goes through
|
|
176
|
+
* `reschedule`, whose coordinator refresh re-reads a store another cockpit changed and opens a
|
|
177
|
+
* project whose definitions file appeared, so their edits arm here within one cap. No registered
|
|
178
|
+
* project: no timer.
|
|
179
|
+
*/
|
|
155
180
|
export class WorkspaceAutomationScheduler {
|
|
156
181
|
options;
|
|
157
182
|
timer;
|
|
@@ -197,24 +222,67 @@ export class WorkspaceAutomationScheduler {
|
|
|
197
222
|
const handle = this.options.handle(projectId, store);
|
|
198
223
|
if (!handle)
|
|
199
224
|
continue;
|
|
200
|
-
|
|
225
|
+
const enabled = store.list().filter((item) => item.enabled);
|
|
226
|
+
// A poll needs the project's GitHub remote; without one it is never armed, not armed to fail.
|
|
227
|
+
if (handle.github) {
|
|
228
|
+
const scheduler = new ProjectAutomationScheduler(handle);
|
|
229
|
+
for (const definition of enabled.filter(isGithubAutomation)) {
|
|
230
|
+
const key = `${projectId}:${definition.id}`;
|
|
231
|
+
live.add(key);
|
|
232
|
+
const at = Date.parse(store.state(definition.id)?.nextCheckAt ?? new Date().toISOString());
|
|
233
|
+
due.push({ key, at: Math.max(at, this.retryAfter.get(key) ?? 0), retryAfterMs: Math.max(definition.intervalSeconds * 1_000, MIN_RETRY_MS), fire: () => scheduler.check(definition) });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const runner = new ScheduleRunner({
|
|
237
|
+
projectId,
|
|
238
|
+
store,
|
|
239
|
+
timeZone: handle.timeZone,
|
|
240
|
+
...(handle.launchSchedule ? { launch: handle.launchSchedule } : {}),
|
|
241
|
+
...(handle.onChange ? { onChange: handle.onChange } : {}),
|
|
242
|
+
...(handle.now ? { now: handle.now } : {}),
|
|
243
|
+
...(handle.reconcileReceipts ? { reconcile: handle.reconcileReceipts } : {}),
|
|
244
|
+
...(handle.ready ? { ready: handle.ready } : {}),
|
|
245
|
+
});
|
|
246
|
+
for (const definition of enabled.filter(isScheduleAutomation)) {
|
|
201
247
|
const key = `${projectId}:${definition.id}`;
|
|
248
|
+
let at;
|
|
249
|
+
// A throwing `dueAt` (an unknown zone, an unwritable state file) skips this item rather
|
|
250
|
+
// than stalling the one timer every other automation shares.
|
|
251
|
+
try {
|
|
252
|
+
at = runner.dueAt(definition);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (at === null)
|
|
258
|
+
continue;
|
|
202
259
|
live.add(key);
|
|
203
|
-
|
|
204
|
-
|
|
260
|
+
// A rejected fire (a held lease included) re-arms at the floor; the schedule's own next
|
|
261
|
+
// occurrence is the runner's business, not the timer's.
|
|
262
|
+
due.push({ key, at: Math.max(at, this.retryAfter.get(key) ?? 0), retryAfterMs: MIN_RETRY_MS, fire: () => runner.fire(definition) });
|
|
205
263
|
}
|
|
206
264
|
}
|
|
207
265
|
for (const key of this.retryAfter.keys())
|
|
208
266
|
if (!live.has(key))
|
|
209
267
|
this.retryAfter.delete(key);
|
|
210
|
-
if (!due.length)
|
|
268
|
+
if (!due.length) {
|
|
269
|
+
if (this.options.coordinator.hasProjects()) {
|
|
270
|
+
this.timer = setTimeout(() => { this.timer = undefined; void this.reschedule(); }, WORKSPACE_TIMER_CAP_MS);
|
|
271
|
+
}
|
|
211
272
|
return;
|
|
273
|
+
}
|
|
212
274
|
due.sort((a, b) => a.at - b.at);
|
|
213
275
|
const next = due[0];
|
|
276
|
+
const clock = () => this.options.now?.() ?? Date.now();
|
|
214
277
|
this.timer = setTimeout(() => {
|
|
215
278
|
this.timer = undefined;
|
|
216
|
-
|
|
217
|
-
|
|
279
|
+
// A capped wake short of the due instant fires nothing: look again from fresh state.
|
|
280
|
+
if (clock() < next.at) {
|
|
281
|
+
void this.reschedule();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
void next.fire().then(() => { this.retryAfter.delete(next.key); }, () => { this.retryAfter.set(next.key, clock() + next.retryAfterMs); }).finally(() => this.reschedule());
|
|
285
|
+
}, Math.min(WORKSPACE_TIMER_CAP_MS, Math.max(0, next.at - clock())));
|
|
218
286
|
}
|
|
219
287
|
}
|
|
220
288
|
//# sourceMappingURL=scheduler.js.map
|