toolroll 0.9.103 → 0.9.105
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/CHANGELOG.md +65 -0
- package/README.md +27 -27
- package/dist/accent-colors.js +0 -29
- package/dist/acp-agents.js +0 -3
- package/dist/acp-attest.js +0 -30
- package/dist/acp-check.js +3 -70
- package/dist/acp-client.js +3 -94
- package/dist/acp-inspect.js +1 -20
- package/dist/action-ledger.js +0 -8
- package/dist/activity-line.js +0 -14
- package/dist/actor.js +0 -15
- package/dist/advanced-schema.js +12 -0
- package/dist/advanced-view.js +26 -0
- package/dist/advanced.js +61 -0
- package/dist/agent-board.js +0 -117
- package/dist/agent-fence.js +11 -367
- package/dist/agent-onboard.js +12 -50
- package/dist/agent-pulse.js +5 -38
- package/dist/agent-state-words.js +0 -8
- package/dist/agent-state.js +1 -45
- package/dist/agent-turns.js +3 -17
- package/dist/agentconfig.js +1 -99
- package/dist/agents-board.js +0 -60
- package/dist/agents-live.js +1 -8
- package/dist/api-tokens.js +0 -27
- package/dist/approval-authority.js +0 -59
- package/dist/approval-password.js +0 -10
- package/dist/approval-policy.js +0 -29
- package/dist/approval-rules-ui.js +0 -9
- package/dist/assignment-adapters.js +0 -14
- package/dist/assignment-brief.js +1 -17
- package/dist/assignment-delivery.js +0 -22
- package/dist/assignment-presentation.js +0 -14
- package/dist/assignment-status.js +1 -30
- package/dist/assignment-ui.js +0 -12
- package/dist/assignment.js +117 -103
- package/dist/attest.js +0 -38
- package/dist/audit-cli.js +0 -9
- package/dist/backend.js +0 -59
- package/dist/backup-ui.js +0 -12
- package/dist/backup.js +8 -61
- package/dist/batch-checks.js +0 -20
- package/dist/batch-policy.js +0 -4
- package/dist/beads.js +0 -48
- package/dist/bin.js +0 -8
- package/dist/board.js +1 -36
- package/dist/boot-identity.js +0 -42
- package/dist/bounded-spawn.js +4 -28
- package/dist/brand-mark.js +0 -21
- package/dist/brief-fence.js +0 -16
- package/dist/browser/terminal.css +1 -1
- package/dist/browser/terminal.js +16 -16
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +26 -26
- package/dist/browser-crew.js +0 -8
- package/dist/browser-shell.js +2 -15
- package/dist/browser-workspace.js +6 -30
- package/dist/budget-alerts.js +1 -4
- package/dist/build-review.js +2 -50
- package/dist/builder-restart.js +0 -13
- package/dist/builder.js +21 -1035
- package/dist/canonical-json.js +0 -12
- package/dist/capscan.js +1 -32
- package/dist/card-catalog.js +0 -12
- package/dist/card-cli.js +0 -1
- package/dist/card-render.js +0 -25
- package/dist/card-sources.js +0 -10
- package/dist/chat-acceptance.js +0 -7
- package/dist/chat-actions.js +5 -190
- package/dist/chat-admission.js +0 -7
- package/dist/chat-approval.js +0 -25
- package/dist/chat-ask.js +0 -17
- package/dist/chat-card-part.js +0 -3
- package/dist/chat-card.js +0 -6
- package/dist/chat-channel.js +2 -83
- package/dist/chat-continuity.js +0 -31
- package/dist/chat-controls.js +0 -7
- package/dist/chat-core.js +0 -55
- package/dist/chat-decide.js +2 -153
- package/dist/chat-delivery-state.js +0 -49
- package/dist/chat-delivery.js +2 -143
- package/dist/chat-display.js +0 -2
- package/dist/chat-evidence.js +0 -65
- package/dist/chat-flow.js +0 -72
- package/dist/chat-follow.js +0 -13
- package/dist/chat-inbox.js +0 -34
- package/dist/chat-live-schema.js +0 -14
- package/dist/chat-live.js +2 -87
- package/dist/chat-message-states.js +13 -40
- package/dist/chat-messages.js +0 -153
- package/dist/chat-migration.js +0 -57
- package/dist/chat-polish.js +0 -7
- package/dist/chat-quiet.js +0 -37
- package/dist/chat-review.js +0 -4
- package/dist/chat-rooms.js +0 -22
- package/dist/chat-settings-page.js +0 -4
- package/dist/chat-task-actions.js +0 -7
- package/dist/chat-terms.js +0 -21
- package/dist/chat-voice.js +0 -38
- package/dist/chat-warmth.js +1 -3
- package/dist/check-access.js +0 -30
- package/dist/check-facts.js +2 -62
- package/dist/check-failure.js +0 -98
- package/dist/check-levels-ui.js +4 -10
- package/dist/check-levels.js +3 -35
- package/dist/check-load.js +1 -49
- package/dist/check-only-standing.js +0 -6
- package/dist/check-only.js +0 -22
- package/dist/check-progress.js +0 -32
- package/dist/check-repair.js +2 -35
- package/dist/check-report.js +1 -108
- package/dist/check-stamp.js +0 -20
- package/dist/checkout-cleanup.js +0 -84
- package/dist/checkout-proof.js +1 -13
- package/dist/child-database.js +0 -3
- package/dist/claim.js +4 -508
- package/dist/claude-print.js +0 -10
- package/dist/cli-fast.js +0 -8
- package/dist/cli-help.js +90 -78
- package/dist/cli-http.js +0 -10
- package/dist/cli.js +26 -241
- package/dist/code-extract.js +0 -6
- package/dist/code-map-acts.js +0 -7
- package/dist/code-map-admission.js +2 -26
- package/dist/code-map-build.js +3 -24
- package/dist/code-map-cli.js +0 -4
- package/dist/code-map-main.js +0 -6
- package/dist/code-map-read.js +0 -12
- package/dist/code-map-report.js +0 -9
- package/dist/code-map-shape.js +0 -19
- package/dist/code-map-store.js +0 -26
- package/dist/codex-limits.js +1 -17
- package/dist/coding-context.js +0 -10
- package/dist/coding-handoff.js +0 -14
- package/dist/coding-provider.js +0 -39
- package/dist/coding-shipping-ui.js +0 -1
- package/dist/coding-ui.js +0 -1
- package/dist/coding-update.js +1 -18
- package/dist/coding-workspace.js +0 -27
- package/dist/commit-extract.js +0 -83
- package/dist/connect-cli.js +0 -19
- package/dist/console-chrome.js +1 -34
- package/dist/console-instance.js +2 -91
- package/dist/container-state.js +0 -4
- package/dist/containment.js +2 -105
- package/dist/contract-changes.js +0 -6
- package/dist/contracts/acceptance-terms.js +0 -7
- package/dist/contracts/chat-actions.js +0 -46
- package/dist/contracts/chat-callback-rows.js +0 -8
- package/dist/contracts/chat-card.js +0 -14
- package/dist/contracts/chat-content.js +0 -55
- package/dist/contracts/chat-tables.js +0 -7
- package/dist/contracts/cli.js +0 -59
- package/dist/contracts/coding-activity.js +0 -15
- package/dist/contracts/coding-context.js +0 -15
- package/dist/contracts/coding-handoff.js +0 -11
- package/dist/contracts/coding-workspace.js +0 -14
- package/dist/contracts/console-api.js +3 -54
- package/dist/contracts/contract-test.js +0 -14
- package/dist/contracts/contract.js +0 -48
- package/dist/contracts/decision.js +0 -20
- package/dist/contracts/diff-stat.js +0 -16
- package/dist/contracts/discord-callback.js +0 -9
- package/dist/contracts/flow-card.js +0 -18
- package/dist/contracts/flow-propose.js +0 -8
- package/dist/contracts/flow-send.js +0 -31
- package/dist/contracts/flow.js +0 -112
- package/dist/contracts/gateway-tools.js +0 -22
- package/dist/contracts/handoff.js +0 -22
- package/dist/contracts/integration-metadata.js +0 -39
- package/dist/contracts/lead-context.js +0 -14
- package/dist/contracts/lead-tools.js +0 -49
- package/dist/contracts/mcp-oauth.js +0 -12
- package/dist/contracts/memory-pass.js +0 -21
- package/dist/contracts/model-catalog.js +0 -9
- package/dist/contracts/observation-request.js +0 -11
- package/dist/contracts/plan.js +0 -16
- package/dist/contracts/project-knowledge.js +0 -26
- package/dist/contracts/project-memory.js +0 -16
- package/dist/contracts/project-skills.js +0 -31
- package/dist/contracts/proof.js +0 -23
- package/dist/contracts/provider.js +0 -9
- package/dist/contracts/recipes.js +0 -16
- package/dist/contracts/release-check.js +0 -61
- package/dist/contracts/release-terms.js +0 -27
- package/dist/contracts/retention.js +0 -12
- package/dist/contracts/review-findings.js +0 -13
- package/dist/contracts/route-results.js +0 -15
- package/dist/contracts/route.js +0 -33
- package/dist/contracts/scope.js +0 -29
- package/dist/contracts/scout-report.js +0 -34
- package/dist/contracts/slack-callback.js +0 -11
- package/dist/contracts/sort-answer.js +0 -24
- package/dist/contracts/stage-output.js +0 -46
- package/dist/contracts/storage.js +0 -8
- package/dist/contracts/store-json.js +0 -41
- package/dist/contracts/subagent-turn.js +0 -23
- package/dist/contracts/task-sizing.js +0 -10
- package/dist/contracts/teams-callback.js +0 -7
- package/dist/contracts/telegram-callback.js +0 -27
- package/dist/contracts/trigger-payloads.js +0 -41
- package/dist/contracts/update-journal.js +0 -47
- package/dist/contracts/verification-receipt.js +0 -36
- package/dist/contracts/verification-view.js +0 -15
- package/dist/contracts/youiyoux-request.js +0 -26
- package/dist/control-setup.js +0 -7
- package/dist/control-ui.js +0 -3
- package/dist/controller-service.js +0 -4
- package/dist/controller-supervisor.js +0 -15
- package/dist/converse.js +3 -129
- package/dist/coordinator-proposals.js +1 -6
- package/dist/coordinator.js +0 -65
- package/dist/credentials-ui.js +0 -6
- package/dist/daemon.js +0 -137
- package/dist/database-reclaim.js +0 -3
- package/dist/decision.js +0 -78
- package/dist/demo-chat.js +4 -15
- package/dist/demo-sign-in.js +77 -0
- package/dist/demo.js +5 -194
- package/dist/deploy-gate.js +0 -20
- package/dist/deploy-lock.js +0 -4
- package/dist/deploy-phase.js +0 -22
- package/dist/deploy-rescue.js +0 -21
- package/dist/deprecations.js +0 -12
- package/dist/design/kit.css +9 -6
- package/dist/design/kit.js +2 -33
- package/dist/desktop-access.js +0 -9
- package/dist/desktop-bundle.js +1 -3
- package/dist/desktop-host.js +0 -34
- package/dist/desktop-update-gate.js +0 -8
- package/dist/desktop-update-recovery.js +1 -18
- package/dist/desktop-update.js +2 -48
- package/dist/digest-times.js +0 -2
- package/dist/disclosure.js +0 -5
- package/dist/discord-api.js +0 -6
- package/dist/discord-chat.js +0 -31
- package/dist/discord.js +0 -7
- package/dist/discover.js +0 -50
- package/dist/dispatch.js +61 -60
- package/dist/dispose.js +0 -208
- package/dist/doctor.js +0 -48
- package/dist/easy-start-args.js +7 -7
- package/dist/easy-start.js +32 -45
- package/dist/egress.js +1 -63
- package/dist/email-settings.js +0 -8
- package/dist/envelope.js +50 -86
- package/dist/eval-gate.js +1 -37
- package/dist/eval-hooks.js +0 -120
- package/dist/eval-oracle-main.js +0 -7
- package/dist/eval-oracle.js +3 -42
- package/dist/eval-world.js +1 -23
- package/dist/evals.js +6 -134
- package/dist/evidence-pack.js +0 -29
- package/dist/evidence-pair.js +0 -17
- package/dist/evidence.js +4 -280
- package/dist/exec.js +19 -404
- package/dist/exhaustion.js +0 -30
- package/dist/export-ui.js +0 -7
- package/dist/export.js +1 -38
- package/dist/failing-first.js +0 -6
- package/dist/fallback-schema.js +0 -5
- package/dist/fallback.js +0 -81
- package/dist/fast-start.js +0 -97
- package/dist/fast-terms.js +0 -3
- package/dist/fenced-check-coverage.js +0 -11
- package/dist/findings.js +1 -63
- package/dist/first-run.js +4 -57
- package/dist/first-tasks-child.js +0 -5
- package/dist/flaky-ci.js +1 -24
- package/dist/flaky-cli.js +0 -4
- package/dist/flaky.js +0 -43
- package/dist/fleet-schema.js +0 -11
- package/dist/flow-actions.js +0 -31
- package/dist/flow-browser.js +0 -42
- package/dist/flow-cadence.js +1 -24
- package/dist/flow-card-task.js +0 -11
- package/dist/flow-changed.js +0 -16
- package/dist/flow-code.js +1 -45
- package/dist/flow-draft.js +0 -17
- package/dist/flow-engine.js +2 -76
- package/dist/flow-gallery-ui.js +0 -28
- package/dist/flow-gallery.js +0 -54
- package/dist/flow-insights.js +0 -12
- package/dist/flow-items.js +0 -27
- package/dist/flow-live.js +0 -31
- package/dist/flow-people.js +0 -14
- package/dist/flow-pull-request.js +0 -32
- package/dist/flow-replies.js +0 -9
- package/dist/flow-result-card.js +0 -8
- package/dist/flow-schedule.js +0 -74
- package/dist/flow-scripts.js +0 -13
- package/dist/flow-secrets.js +0 -10
- package/dist/flow-send.js +0 -45
- package/dist/flow-share.js +0 -60
- package/dist/flow-sort.js +1 -24
- package/dist/flow-starters-ui.js +0 -2
- package/dist/flow-starters.js +0 -13
- package/dist/flow-steps.js +0 -80
- package/dist/flow-triggers.js +2 -256
- package/dist/flow-unattended-words.js +0 -13
- package/dist/flow-unattended.js +2 -115
- package/dist/flows-cli.js +2 -36
- package/dist/flows-ui.js +0 -51
- package/dist/flows.js +0 -158
- package/dist/folder-gate.js +0 -21
- package/dist/folder-look.js +0 -42
- package/dist/follow-through-brief.js +0 -6
- package/dist/follow-through-cli.js +0 -5
- package/dist/fonts.js +0 -13
- package/dist/gaps.js +0 -20
- package/dist/gate-failure.js +0 -7
- package/dist/git-floor.js +0 -12
- package/dist/git-incident.js +2 -38
- package/dist/git-views.js +0 -24
- package/dist/git.js +0 -31
- package/dist/github-import.js +0 -22
- package/dist/github-jobs.js +0 -12
- package/dist/google-mail.js +2 -27
- package/dist/grant.js +0 -110
- package/dist/graph.js +0 -108
- package/dist/guides.js +4 -15
- package/dist/handover-note.js +0 -12
- package/dist/health-cli.js +0 -2
- package/dist/home-groups.js +0 -15
- package/dist/html.js +0 -54
- package/dist/install-method.js +0 -12
- package/dist/integrations-ui.js +0 -15
- package/dist/integrations.js +7 -50
- package/dist/invoke.js +1 -381
- package/dist/is-record.js +0 -1
- package/dist/issues.js +0 -48
- package/dist/jsonl-discriminants.js +0 -6
- package/dist/keymap.js +2 -16
- package/dist/keys.js +0 -56
- package/dist/kits-ui.js +0 -3
- package/dist/kits.js +1 -24
- package/dist/knowledge-cli.js +0 -4
- package/dist/knowledge-ui.js +0 -8
- package/dist/landed-cleanup.js +0 -119
- package/dist/laptop-background.js +0 -85
- package/dist/laptop-service.js +0 -67
- package/dist/latency-timeline.js +2 -23
- package/dist/lead-about.js +0 -7
- package/dist/lead-answer-eval.js +0 -39
- package/dist/lead-capabilities.js +0 -19
- package/dist/lead-cli-live.js +0 -22
- package/dist/lead-cli.js +0 -27
- package/dist/lead-commitments.js +1 -27
- package/dist/lead-context.js +2 -42
- package/dist/lead-contract.js +0 -8
- package/dist/lead-doors.js +0 -105
- package/dist/lead-follow.js +0 -41
- package/dist/lead-identity.js +1 -4
- package/dist/lead-latency-schema.js +0 -13
- package/dist/lead-people.js +3 -18
- package/dist/lead-progress.js +0 -12
- package/dist/lead-queue-runtime.js +0 -26
- package/dist/lead-queue.js +0 -35
- package/dist/lead-route.js +0 -33
- package/dist/lead-status.js +0 -37
- package/dist/lead-sweep.js +0 -18
- package/dist/lead-tools.js +0 -160
- package/dist/lead-voice.js +0 -54
- package/dist/lead.js +2 -105
- package/dist/learning-child.js +0 -6
- package/dist/learning-look.js +0 -14
- package/dist/ledger-chain.js +0 -34
- package/dist/ledger-csv.js +0 -2
- package/dist/ledger-view.js +0 -3
- package/dist/lesson-notes.js +0 -56
- package/dist/limits-ui.js +0 -14
- package/dist/link.js +0 -79
- package/dist/live-backup.js +3 -33
- package/dist/live-bus.js +7 -81
- package/dist/live-children-read.js +4 -47
- package/dist/live-children.js +4 -44
- package/dist/live-detail.js +0 -17
- package/dist/live-input.js +5 -68
- package/dist/live-main-read.js +1 -14
- package/dist/live-notes.js +0 -12
- package/dist/live-open.js +1 -23
- package/dist/live-records.js +4 -151
- package/dist/live-reply.js +1 -51
- package/dist/live-terminal.js +12 -111
- package/dist/live.js +4 -130
- package/dist/local-owner-acts.js +168 -0
- package/dist/local-owner.js +15 -80
- package/dist/log.js +0 -8
- package/dist/login-secrets.js +2 -38
- package/dist/machine-check.js +0 -2
- package/dist/machine-identity.js +1 -46
- package/dist/mailbox.js +0 -30
- package/dist/maintenance.js +1 -3
- package/dist/mcp-connect.js +0 -88
- package/dist/mcp-core.js +0 -45
- package/dist/mcp-http.js +0 -13
- package/dist/mcp-oauth.js +0 -37
- package/dist/mcp-person.js +0 -11
- package/dist/mcp.js +3 -73
- package/dist/memory-cli.js +0 -3
- package/dist/memory-pass.js +0 -53
- package/dist/memory-tidy.js +0 -55
- package/dist/memory-use.js +2 -24
- package/dist/merge-checklist.js +21 -29
- package/dist/metrics.js +0 -10
- package/dist/mobile-viewport.js +0 -6
- package/dist/model-catalog.js +1 -33
- package/dist/model-choices.js +9 -84
- package/dist/model-names.js +0 -9
- package/dist/models-cli.js +0 -13
- package/dist/models-ui.js +0 -17
- package/dist/modes.js +0 -35
- package/dist/monitoring-settings.js +2 -27
- package/dist/monitoring-ui.js +2 -14
- package/dist/monitoring.js +2 -38
- package/dist/names.js +0 -39
- package/dist/needs-you.js +7 -70
- package/dist/never-index.js +0 -9
- package/dist/nightly-check.js +0 -74
- package/dist/nightly-github.js +0 -168
- package/dist/notification-delivery.js +0 -3
- package/dist/notification-rows.js +0 -17
- package/dist/oauth-run-token.js +1 -37
- package/dist/observations.js +0 -16
- package/dist/oidc.js +1 -20
- package/dist/onboard.js +4 -57
- package/dist/one-step-chat-schema.js +0 -15
- package/dist/openrouter-models.js +0 -6
- package/dist/operate-remote-arguments.js +2 -17
- package/dist/operate-remote.js +0 -33
- package/dist/operate.js +280 -2304
- package/dist/orphan-sweep.js +3 -37
- package/dist/page-work-contract.js +0 -3
- package/dist/password-bearer.js +1 -11
- package/dist/passwordless.js +0 -3
- package/dist/peek-cli.js +0 -46
- package/dist/peek.js +2 -61
- package/dist/people-audit-ui.js +0 -6
- package/dist/person-proof.js +0 -6
- package/dist/phase-routing.js +8 -183
- package/dist/plain-schema.js +0 -14
- package/dist/plain-words.js +18 -12
- package/dist/plan-auto.js +3 -18
- package/dist/plan-login.js +0 -16
- package/dist/plan.js +0 -68
- package/dist/plane-review.js +0 -56
- package/dist/planner-source.js +0 -96
- package/dist/planner.js +0 -117
- package/dist/policy-ui.js +0 -8
- package/dist/policy.js +0 -47
- package/dist/prepared-evidence.js +0 -5
- package/dist/principal.js +0 -29
- package/dist/probe.js +0 -30
- package/dist/process-custody.js +0 -15
- package/dist/process-liveness.js +0 -32
- package/dist/process-tree.js +3 -29
- package/dist/project-access.js +0 -10
- package/dist/project-admission.js +1 -41
- package/dist/project-cli.js +0 -6
- package/dist/project-concurrency.js +0 -35
- package/dist/project-delete-ui.js +4 -29
- package/dist/project-delete.js +1 -73
- package/dist/project-demo.js +0 -13
- package/dist/project-file.js +0 -2
- package/dist/project-identity.js +0 -41
- package/dist/project-knowledge.js +0 -39
- package/dist/project-learning.js +3 -55
- package/dist/project-memory.js +2 -45
- package/dist/project-outcomes.js +0 -6
- package/dist/project-sandbox.js +0 -23
- package/dist/project-skills.js +0 -12
- package/dist/project-tools.js +6 -184
- package/dist/project.js +0 -48
- package/dist/prompt.js +0 -31
- package/dist/proof.js +0 -220
- package/dist/proposal.js +0 -50
- package/dist/protected-storage-look.js +0 -6
- package/dist/protected-storage.js +1 -84
- package/dist/provider-auth.js +3 -69
- package/dist/provider-capture.js +1 -15
- package/dist/provider-connection.js +0 -8
- package/dist/provider-home.js +0 -25
- package/dist/provider-limits.js +0 -14
- package/dist/provider.js +0 -324
- package/dist/public-access.js +11 -30
- package/dist/public-check.js +0 -16
- package/dist/publish.js +1 -150
- package/dist/pull-request-flow.js +6 -74
- package/dist/pull-request-schema.js +0 -4
- package/dist/pull-request-ui.js +0 -5
- package/dist/pulls.js +0 -80
- package/dist/push.js +5 -89
- package/dist/quick-start.js +1 -23
- package/dist/read-executor-worker.js +0 -1
- package/dist/read-executor.js +0 -10
- package/dist/read-only-request.js +0 -7
- package/dist/recipe-ui.js +0 -6
- package/dist/recipes.js +0 -13
- package/dist/release-adapters.js +6 -214
- package/dist/release-approval.js +0 -74
- package/dist/release-authority.js +0 -42
- package/dist/release-auto.js +0 -142
- package/dist/release-card.js +26 -103
- package/dist/release-carry.js +0 -132
- package/dist/release-ci-hold.js +0 -20
- package/dist/release-cli.js +0 -46
- package/dist/release-coverage.js +0 -16
- package/dist/release-gate.js +0 -30
- package/dist/release-git.js +0 -24
- package/dist/release-links.js +0 -17
- package/dist/release-net.js +0 -42
- package/dist/release-next.js +0 -25
- package/dist/release-recheck.js +0 -89
- package/dist/release-refusal.js +0 -18
- package/dist/release-view.js +0 -5
- package/dist/release.js +7 -341
- package/dist/releases.js +0 -49
- package/dist/remote-audit.js +0 -25
- package/dist/remote-command.js +0 -16
- package/dist/remote-destination.js +5 -26
- package/dist/remote-exec.js +1 -27
- package/dist/remote-main.js +1 -53
- package/dist/remote-run.js +0 -5
- package/dist/remote.js +0 -49
- package/dist/render.js +0 -133
- package/dist/reply-shape.js +0 -85
- package/dist/reply-voice.js +0 -7
- package/dist/report-summary.js +0 -5
- package/dist/reported-usage.js +0 -30
- package/dist/repos.js +9 -62
- package/dist/repository-context.js +1 -24
- package/dist/request-budget-ui.js +0 -4
- package/dist/request-budget.js +0 -23
- package/dist/restart-certification.js +0 -37
- package/dist/result-actions.js +0 -62
- package/dist/result-acts.js +0 -34
- package/dist/result-completion.js +9 -28
- package/dist/result-evidence-readers.js +0 -3
- package/dist/result-follow-ups.js +1 -39
- package/dist/result-review.js +0 -86
- package/dist/result-shots.js +0 -39
- package/dist/retention-ui.js +0 -7
- package/dist/retention.js +2 -46
- package/dist/review-context.js +0 -129
- package/dist/review-evidence.js +0 -4
- package/dist/review-switch.js +1 -7
- package/dist/reviewer.js +0 -35
- package/dist/route-change-check.js +0 -2
- package/dist/route-change.js +0 -16
- package/dist/route-hooks.js +0 -27
- package/dist/route-results.js +2 -58
- package/dist/route-rules.js +1 -106
- package/dist/route-savings.js +0 -36
- package/dist/route-store.js +1 -133
- package/dist/run-closeout.js +2 -50
- package/dist/run-efficiency.js +2 -44
- package/dist/run-ending.js +0 -13
- package/dist/runner-process.js +0 -33
- package/dist/runner.js +17 -189
- package/dist/sample-project.js +2 -27
- package/dist/sandbox-launch.js +4 -25
- package/dist/sandbox-runtime.js +1 -88
- package/dist/scan.js +0 -27
- package/dist/scope.js +88 -566
- package/dist/scout-browser-lock.js +0 -6
- package/dist/scout-browser.js +2 -68
- package/dist/scout-net.js +1 -32
- package/dist/scout-report.js +0 -22
- package/dist/scout.js +1 -116
- package/dist/secret-mint.js +0 -6
- package/dist/serve.js +29 -564
- package/dist/server/agents-computers.js +0 -10
- package/dist/server/agents-live-filed.js +0 -13
- package/dist/server/agents-live-lead.js +0 -19
- package/dist/server/agents-live-room.js +0 -19
- package/dist/server/chat.js +2 -194
- package/dist/server/chrome.js +17 -263
- package/dist/server/console.css +4 -4
- package/dist/server/edge-refusal.js +0 -3
- package/dist/server/flows.js +5 -74
- package/dist/server/guards.js +9 -86
- package/dist/server/handler-registry.js +0 -2
- package/dist/server/home-asks.js +1 -22
- package/dist/server/home.js +1 -30
- package/dist/server/http.js +0 -82
- package/dist/server/in-place.js +0 -15
- package/dist/server/kit-standalone.js +0 -20
- package/dist/server/kit.js +2 -114
- package/dist/server/last-checks.js +0 -2
- package/dist/server/live.js +1 -36
- package/dist/server/merge-ready-view.js +0 -6
- package/dist/server/mutation-key.js +3 -40
- package/dist/server/pages-assets.js +0 -16
- package/dist/server/pages.js +7 -195
- package/dist/server/people-tokens.js +3 -101
- package/dist/server/remote-hooks.js +0 -13
- package/dist/server/remote.js +0 -28
- package/dist/server/render-chat.js +8 -144
- package/dist/server/render-code-map.js +0 -5
- package/dist/server/render-flaky.js +0 -8
- package/dist/server/render-follow-through.js +2 -5
- package/dist/server/render-history.js +2 -34
- package/dist/server/render-new-task.js +2 -29
- package/dist/server/render-pages.js +1 -111
- package/dist/server/render-people.js +2 -46
- package/dist/server/render-projects.js +15 -32
- package/dist/server/render-release.js +1 -14
- package/dist/server/render-results.js +4 -355
- package/dist/server/render-settings.js +0 -15
- package/dist/server/render-tasks.js +17 -497
- package/dist/server/request-context.js +2 -9
- package/dist/server/retired-routes.js +0 -11
- package/dist/server/route-policy.js +0 -3
- package/dist/server/route-table.js +8 -133
- package/dist/server/runtime.js +0 -1
- package/dist/server/session.js +0 -28
- package/dist/server/settings.js +40 -246
- package/dist/server/signup-gate.js +0 -11
- package/dist/server/sweeps.js +0 -6
- package/dist/server/task-views.js +12 -227
- package/dist/server/tasks.js +37 -531
- package/dist/server/terminals.js +2 -46
- package/dist/server/welcome.js +2 -22
- package/dist/server-telemetry.js +0 -9
- package/dist/settings-groups-ui.js +50 -63
- package/dist/settings-kit-script.js +0 -19
- package/dist/settings-kit.js +0 -63
- package/dist/settings-proofs.js +0 -23
- package/dist/setup-guide.js +1 -9
- package/dist/shared-deps.js +9 -84
- package/dist/sign-in-guard.js +0 -27
- package/dist/skills-ui.js +0 -2
- package/dist/skills.js +2 -54
- package/dist/slack-api.js +0 -3
- package/dist/slack-chat.js +0 -25
- package/dist/slack-settings.js +0 -1
- package/dist/slack-socket.js +0 -5
- package/dist/slack.js +0 -4
- package/dist/sleep.js +0 -1
- package/dist/source-key.js +0 -10
- package/dist/spend-report.js +0 -29
- package/dist/spend-ui.js +0 -26
- package/dist/spend.js +0 -40
- package/dist/sqlite-runtime.js +0 -2
- package/dist/sqlite-telemetry.js +0 -9
- package/dist/sso-settings.js +0 -13
- package/dist/sso-ui.js +0 -2
- package/dist/staged-runtimes.js +5 -39
- package/dist/steer-capabilities.js +1 -7
- package/dist/steer-controls.js +0 -10
- package/dist/steer-live.js +0 -31
- package/dist/steer-mailbox.js +4 -65
- package/dist/steer-status.js +0 -7
- package/dist/stop-proof.js +5 -62
- package/dist/storage-sweep-child.js +1 -5
- package/dist/storage-sweep-process.js +2 -20
- package/dist/storage-sweep-schedule.js +0 -32
- package/dist/storage-sweep.js +2 -51
- package/dist/storage-ui.js +0 -18
- package/dist/storage.js +0 -31
- package/dist/store-baseline.js +0 -14
- package/dist/store.js +109 -4763
- package/dist/stream-scope.js +0 -16
- package/dist/structured-output.js +0 -39
- package/dist/style-asset.js +0 -2
- package/dist/subagent-admin.js +0 -9
- package/dist/subagent-desk.js +0 -29
- package/dist/subagent-memory.js +0 -38
- package/dist/subagent-question.js +0 -29
- package/dist/subagent-tools.js +1 -60
- package/dist/subagent-week.js +0 -28
- package/dist/subagent-work.js +1 -39
- package/dist/subagents-ui.js +1 -13
- package/dist/subagents.js +0 -40
- package/dist/subscription-chat.js +1 -42
- package/dist/summary.js +0 -19
- package/dist/surface.js +8 -73
- package/dist/sweep-gate.js +0 -2
- package/dist/sweep-quarantine.js +2 -13
- package/dist/sync.js +0 -47
- package/dist/tailnet.js +0 -9
- package/dist/tamper-scan.js +0 -15
- package/dist/task-activity.js +1 -16
- package/dist/task-aliases.js +0 -3
- package/dist/task-archive.js +0 -7
- package/dist/task-base.js +0 -18
- package/dist/task-composer.js +0 -2
- package/dist/task-control.js +0 -74
- package/dist/task-live.js +0 -23
- package/dist/task-moves.js +0 -28
- package/dist/task-outcome-cli.js +66 -19
- package/dist/task-review-brief.js +0 -7
- package/dist/task-sizing.js +0 -47
- package/dist/task-source.js +0 -23
- package/dist/task-status.js +0 -106
- package/dist/task-text.js +0 -12
- package/dist/team-chat-authorization.js +0 -3
- package/dist/team-contract.js +0 -2
- package/dist/team-http.js +0 -4
- package/dist/team-leads.js +1 -16
- package/dist/team-runtime.js +0 -13
- package/dist/team-ui.js +0 -1
- package/dist/team-updates.js +0 -4
- package/dist/teams-api.js +0 -12
- package/dist/teams-chat.js +0 -28
- package/dist/teams.js +0 -12
- package/dist/teardown-git.js +6 -294
- package/dist/telegram-flow.js +0 -51
- package/dist/telegram-lead.js +2 -203
- package/dist/telegram-live.js +1 -42
- package/dist/telegram-progress.js +0 -18
- package/dist/telegram-settings.js +0 -7
- package/dist/telegram-status.js +0 -46
- package/dist/telegram-team.js +1 -33
- package/dist/telegram.js +6 -454
- package/dist/templates.js +0 -24
- package/dist/terminal-catalog.js +2 -20
- package/dist/terminal-text.js +0 -12
- package/dist/test-infra.js +0 -50
- package/dist/test-temp.js +3 -26
- package/dist/text-limits.js +0 -92
- package/dist/tidy.js +0 -76
- package/dist/tier-report.js +0 -2
- package/dist/token-notices.js +1 -9
- package/dist/tokens-cli.js +0 -13
- package/dist/tool-broker.js +2 -53
- package/dist/tool-launcher.js +0 -14
- package/dist/tool-secret-store.js +3 -125
- package/dist/toolroll-update-cli.js +0 -9
- package/dist/toolroll-update-ui.js +0 -14
- package/dist/toolroll-update.js +13 -252
- package/dist/tools-ui.js +0 -17
- package/dist/transitions-recipes.js +0 -2
- package/dist/tree-proof.js +0 -23
- package/dist/tui-contract.js +0 -8
- package/dist/tui-source.js +91 -40
- package/dist/tui.js +54 -54
- package/dist/typed-start.js +0 -27
- package/dist/unfenced-test-support.js +0 -5
- package/dist/up-processes.js +1 -40
- package/dist/up-role-child.js +1 -13
- package/dist/update-notice.js +0 -1
- package/dist/vanished-retry.js +0 -40
- package/dist/verification-evidence.js +0 -39
- package/dist/version.js +0 -1
- package/dist/wake-hub.js +0 -28
- package/dist/webhook-limits.js +0 -7
- package/dist/webhook-readers.js +0 -30
- package/dist/webhook-signing.js +0 -14
- package/dist/webhooks.js +0 -54
- package/dist/welcome-facts.js +2 -14
- package/dist/when-html.js +0 -27
- package/dist/work-index.js +26 -98
- package/dist/work-summary.js +2 -17
- package/dist/workspace-motion.js +0 -2
- package/dist/workspace-revision.js +1 -21
- package/dist/workspace-ui.js +15 -135
- package/dist/worktree-notices.js +0 -3
- package/dist/worktree.js +0 -308
- package/dist/writes-mode.js +0 -1
- package/dist/youiyoux-intake.js +4 -159
- package/package.json +5 -4
- package/dist/accent-colors.d.ts +0 -51
- package/dist/acp-agents.d.ts +0 -43
- package/dist/acp-attest.d.ts +0 -44
- package/dist/acp-check.d.ts +0 -37
- package/dist/acp-client.d.ts +0 -163
- package/dist/acp-inspect.d.ts +0 -23
- package/dist/action-ledger.d.ts +0 -27
- package/dist/activity-line.d.ts +0 -29
- package/dist/actor.d.ts +0 -11
- package/dist/agent-board.d.ts +0 -229
- package/dist/agent-fence.d.ts +0 -479
- package/dist/agent-onboard.d.ts +0 -158
- package/dist/agent-pulse.d.ts +0 -43
- package/dist/agent-state-words.d.ts +0 -19
- package/dist/agent-state.d.ts +0 -65
- package/dist/agent-turns.d.ts +0 -52
- package/dist/agentconfig.d.ts +0 -191
- package/dist/agents-board.d.ts +0 -145
- package/dist/agents-live.d.ts +0 -31
- package/dist/api-tokens.d.ts +0 -80
- package/dist/approval-authority.d.ts +0 -51
- package/dist/approval-password.d.ts +0 -31
- package/dist/approval-policy.d.ts +0 -69
- package/dist/approval-rules-ui.d.ts +0 -40
- package/dist/assignment-adapters.d.ts +0 -152
- package/dist/assignment-brief.d.ts +0 -83
- package/dist/assignment-delivery.d.ts +0 -86
- package/dist/assignment-presentation.d.ts +0 -37
- package/dist/assignment-status.d.ts +0 -71
- package/dist/assignment-ui.d.ts +0 -68
- package/dist/assignment.d.ts +0 -318
- package/dist/attest.d.ts +0 -59
- package/dist/audit-cli.d.ts +0 -17
- package/dist/backend.d.ts +0 -97
- package/dist/backup-ui.d.ts +0 -32
- package/dist/backup.d.ts +0 -92
- package/dist/batch-checks.d.ts +0 -15
- package/dist/batch-policy.d.ts +0 -23
- package/dist/beads.d.ts +0 -34
- package/dist/bin.d.ts +0 -2
- package/dist/board.d.ts +0 -134
- package/dist/boot-identity.d.ts +0 -64
- package/dist/bounded-spawn.d.ts +0 -57
- package/dist/brand-icons.d.ts +0 -168
- package/dist/brand-mark.d.ts +0 -28
- package/dist/brief-fence.d.ts +0 -9
- package/dist/browser-crew.d.ts +0 -12
- package/dist/browser-shell.d.ts +0 -9
- package/dist/browser-workspace.d.ts +0 -1972
- package/dist/budget-alerts.d.ts +0 -19
- package/dist/build-review.d.ts +0 -38
- package/dist/builder-restart.d.ts +0 -21
- package/dist/builder.d.ts +0 -409
- package/dist/canonical-json.d.ts +0 -14
- package/dist/capscan.d.ts +0 -35
- package/dist/card-catalog.d.ts +0 -209
- package/dist/card-cli.d.ts +0 -43
- package/dist/card-render.d.ts +0 -43
- package/dist/card-sources.d.ts +0 -68
- package/dist/chat-acceptance.d.ts +0 -74
- package/dist/chat-actions.d.ts +0 -460
- package/dist/chat-admission.d.ts +0 -19
- package/dist/chat-approval.d.ts +0 -58
- package/dist/chat-ask.d.ts +0 -32
- package/dist/chat-card-part.d.ts +0 -11
- package/dist/chat-card.d.ts +0 -46
- package/dist/chat-channel.d.ts +0 -126
- package/dist/chat-continuity.d.ts +0 -32
- package/dist/chat-controls.d.ts +0 -117
- package/dist/chat-core.d.ts +0 -177
- package/dist/chat-decide.d.ts +0 -269
- package/dist/chat-delivery-state.d.ts +0 -132
- package/dist/chat-delivery.d.ts +0 -71
- package/dist/chat-display.d.ts +0 -1
- package/dist/chat-evidence.d.ts +0 -123
- package/dist/chat-flow.d.ts +0 -70
- package/dist/chat-follow.d.ts +0 -20
- package/dist/chat-inbox.d.ts +0 -57
- package/dist/chat-live-schema.d.ts +0 -17
- package/dist/chat-live.d.ts +0 -161
- package/dist/chat-message-states.d.ts +0 -75
- package/dist/chat-messages.d.ts +0 -338
- package/dist/chat-migration.d.ts +0 -30
- package/dist/chat-polish.d.ts +0 -17
- package/dist/chat-quiet.d.ts +0 -40
- package/dist/chat-review.d.ts +0 -51
- package/dist/chat-rooms.d.ts +0 -123
- package/dist/chat-settings-page.d.ts +0 -43
- package/dist/chat-task-actions.d.ts +0 -59
- package/dist/chat-terms.d.ts +0 -29
- package/dist/chat-voice.d.ts +0 -69
- package/dist/chat-warmth.d.ts +0 -21
- package/dist/check-access.d.ts +0 -54
- package/dist/check-facts.d.ts +0 -126
- package/dist/check-failure.d.ts +0 -113
- package/dist/check-levels-ui.d.ts +0 -36
- package/dist/check-levels.d.ts +0 -70
- package/dist/check-load.d.ts +0 -85
- package/dist/check-only-standing.d.ts +0 -36
- package/dist/check-only.d.ts +0 -15
- package/dist/check-progress.d.ts +0 -78
- package/dist/check-repair.d.ts +0 -47
- package/dist/check-report.d.ts +0 -177
- package/dist/check-stamp.d.ts +0 -46
- package/dist/checkout-cleanup.d.ts +0 -157
- package/dist/checkout-proof.d.ts +0 -28
- package/dist/child-database.d.ts +0 -12
- package/dist/claim.d.ts +0 -627
- package/dist/claude-print.d.ts +0 -12
- package/dist/cli-fast.d.ts +0 -8
- package/dist/cli-help.d.ts +0 -8
- package/dist/cli-http.d.ts +0 -58
- package/dist/cli.d.ts +0 -149
- package/dist/code-extract.d.ts +0 -44
- package/dist/code-map-acts.d.ts +0 -24
- package/dist/code-map-admission.d.ts +0 -52
- package/dist/code-map-build.d.ts +0 -63
- package/dist/code-map-cli.d.ts +0 -153
- package/dist/code-map-main.d.ts +0 -1
- package/dist/code-map-read.d.ts +0 -106
- package/dist/code-map-report.d.ts +0 -37
- package/dist/code-map-shape.d.ts +0 -172
- package/dist/code-map-store.d.ts +0 -136
- package/dist/codex-limits.d.ts +0 -15
- package/dist/coding-context.d.ts +0 -18
- package/dist/coding-handoff.d.ts +0 -39
- package/dist/coding-provider.d.ts +0 -88
- package/dist/coding-shipping-ui.d.ts +0 -5
- package/dist/coding-types.d.ts +0 -16
- package/dist/coding-ui.d.ts +0 -19
- package/dist/coding-update.d.ts +0 -28
- package/dist/coding-workspace.d.ts +0 -141
- package/dist/commit-extract.d.ts +0 -135
- package/dist/connect-cli.d.ts +0 -34
- package/dist/console-chrome.d.ts +0 -41
- package/dist/console-instance.d.ts +0 -157
- package/dist/container-state.d.ts +0 -5
- package/dist/containment.d.ts +0 -205
- package/dist/contract-changes.d.ts +0 -52
- package/dist/contracts/acceptance-terms.d.ts +0 -14
- package/dist/contracts/chat-actions.d.ts +0 -465
- package/dist/contracts/chat-callback-rows.d.ts +0 -59
- package/dist/contracts/chat-card.d.ts +0 -91
- package/dist/contracts/chat-content.d.ts +0 -551
- package/dist/contracts/chat-tables.d.ts +0 -12
- package/dist/contracts/cli.d.ts +0 -987
- package/dist/contracts/coding-activity.d.ts +0 -64
- package/dist/contracts/coding-context.d.ts +0 -97
- package/dist/contracts/coding-handoff.d.ts +0 -44
- package/dist/contracts/coding-workspace.d.ts +0 -165
- package/dist/contracts/console-api.d.ts +0 -539
- package/dist/contracts/contract-test.d.ts +0 -45
- package/dist/contracts/contract.d.ts +0 -92
- package/dist/contracts/decision.d.ts +0 -45
- package/dist/contracts/diff-stat.d.ts +0 -58
- package/dist/contracts/discord-callback.d.ts +0 -45
- package/dist/contracts/flow-card.d.ts +0 -53
- package/dist/contracts/flow-propose.d.ts +0 -334
- package/dist/contracts/flow-send.d.ts +0 -245
- package/dist/contracts/flow.d.ts +0 -19565
- package/dist/contracts/gateway-tools.d.ts +0 -472
- package/dist/contracts/handoff.d.ts +0 -91
- package/dist/contracts/health.d.ts +0 -82
- package/dist/contracts/integration-metadata.d.ts +0 -100
- package/dist/contracts/lead-context.d.ts +0 -165
- package/dist/contracts/lead-tools.d.ts +0 -2312
- package/dist/contracts/mcp-oauth.d.ts +0 -53
- package/dist/contracts/memory-pass.d.ts +0 -157
- package/dist/contracts/model-catalog.d.ts +0 -21
- package/dist/contracts/observation-request.d.ts +0 -37
- package/dist/contracts/plan.d.ts +0 -58
- package/dist/contracts/project-knowledge.d.ts +0 -159
- package/dist/contracts/project-memory.d.ts +0 -119
- package/dist/contracts/project-skills.d.ts +0 -120
- package/dist/contracts/proof.d.ts +0 -136
- package/dist/contracts/provider.d.ts +0 -40
- package/dist/contracts/recipes.d.ts +0 -166
- package/dist/contracts/release-check.d.ts +0 -371
- package/dist/contracts/release-terms.d.ts +0 -107
- package/dist/contracts/retention.d.ts +0 -42
- package/dist/contracts/review-findings.d.ts +0 -46
- package/dist/contracts/route-results.d.ts +0 -121
- package/dist/contracts/route.d.ts +0 -897
- package/dist/contracts/scope.d.ts +0 -105
- package/dist/contracts/scout-report.d.ts +0 -234
- package/dist/contracts/slack-callback.d.ts +0 -43
- package/dist/contracts/sort-answer.d.ts +0 -83
- package/dist/contracts/stage-output.d.ts +0 -127
- package/dist/contracts/storage.d.ts +0 -37
- package/dist/contracts/store-json.d.ts +0 -313
- package/dist/contracts/subagent-turn.d.ts +0 -43
- package/dist/contracts/task-sizing.d.ts +0 -24
- package/dist/contracts/teams-callback.d.ts +0 -13
- package/dist/contracts/telegram-callback.d.ts +0 -120
- package/dist/contracts/trigger-payloads.d.ts +0 -389
- package/dist/contracts/update-journal.d.ts +0 -254
- package/dist/contracts/verification-receipt.d.ts +0 -200
- package/dist/contracts/verification-view.d.ts +0 -102
- package/dist/contracts/youiyoux-request.d.ts +0 -248
- package/dist/control-setup.d.ts +0 -44
- package/dist/control-ui.d.ts +0 -37
- package/dist/controller-service.d.ts +0 -1
- package/dist/controller-supervisor.d.ts +0 -38
- package/dist/converse.d.ts +0 -316
- package/dist/coordinator-proposals.d.ts +0 -29
- package/dist/coordinator.d.ts +0 -186
- package/dist/credentials-ui.d.ts +0 -33
- package/dist/daemon.d.ts +0 -226
- package/dist/database-reclaim.d.ts +0 -4
- package/dist/decision.d.ts +0 -119
- package/dist/demo-chat.d.ts +0 -32
- package/dist/demo.d.ts +0 -153
- package/dist/deploy-gate.d.ts +0 -20
- package/dist/deploy-lock.d.ts +0 -8
- package/dist/deploy-phase.d.ts +0 -37
- package/dist/deploy-rescue.d.ts +0 -42
- package/dist/deprecations.d.ts +0 -20
- package/dist/design/kit.d.ts +0 -216
- package/dist/desktop-access.d.ts +0 -28
- package/dist/desktop-bundle.d.ts +0 -16
- package/dist/desktop-host.d.ts +0 -54
- package/dist/desktop-update-gate.d.ts +0 -12
- package/dist/desktop-update-recovery.d.ts +0 -14
- package/dist/desktop-update.d.ts +0 -147
- package/dist/digest-times.d.ts +0 -3
- package/dist/disclosure.d.ts +0 -6
- package/dist/discord-api.d.ts +0 -24
- package/dist/discord-chat.d.ts +0 -27
- package/dist/discord-settings.d.ts +0 -4
- package/dist/discord.d.ts +0 -10
- package/dist/discover.d.ts +0 -75
- package/dist/dispatch.d.ts +0 -123
- package/dist/dispose.d.ts +0 -194
- package/dist/doctor.d.ts +0 -67
- package/dist/easy-start-args.d.ts +0 -13
- package/dist/easy-start.d.ts +0 -77
- package/dist/egress.d.ts +0 -121
- package/dist/email-settings.d.ts +0 -34
- package/dist/envelope.d.ts +0 -47
- package/dist/eval-gate.d.ts +0 -51
- package/dist/eval-hooks.d.ts +0 -94
- package/dist/eval-oracle-main.d.ts +0 -1
- package/dist/eval-oracle.d.ts +0 -60
- package/dist/eval-world.d.ts +0 -17
- package/dist/evals.d.ts +0 -299
- package/dist/evidence-pack.d.ts +0 -186
- package/dist/evidence-pair.d.ts +0 -53
- package/dist/evidence.d.ts +0 -371
- package/dist/exec.d.ts +0 -355
- package/dist/exhaustion.d.ts +0 -58
- package/dist/export-ui.d.ts +0 -11
- package/dist/export.d.ts +0 -48
- package/dist/failing-first.d.ts +0 -31
- package/dist/fallback-schema.d.ts +0 -8
- package/dist/fallback.d.ts +0 -138
- package/dist/fast-start.d.ts +0 -213
- package/dist/fast-terms.d.ts +0 -9
- package/dist/fenced-check-coverage.d.ts +0 -62
- package/dist/findings.d.ts +0 -224
- package/dist/first-run.d.ts +0 -197
- package/dist/first-tasks-child.d.ts +0 -1
- package/dist/flaky-ci.d.ts +0 -31
- package/dist/flaky-cli.d.ts +0 -60
- package/dist/flaky.d.ts +0 -83
- package/dist/fleet-schema.d.ts +0 -17
- package/dist/flow-actions.d.ts +0 -79
- package/dist/flow-browser.d.ts +0 -103
- package/dist/flow-cadence.d.ts +0 -48
- package/dist/flow-card-task.d.ts +0 -11
- package/dist/flow-changed.d.ts +0 -14
- package/dist/flow-code.d.ts +0 -84
- package/dist/flow-draft.d.ts +0 -42
- package/dist/flow-engine.d.ts +0 -82
- package/dist/flow-gallery-ui.d.ts +0 -73
- package/dist/flow-gallery.d.ts +0 -147
- package/dist/flow-insights.d.ts +0 -104
- package/dist/flow-items.d.ts +0 -37
- package/dist/flow-live.d.ts +0 -16
- package/dist/flow-people.d.ts +0 -23
- package/dist/flow-pull-request.d.ts +0 -14
- package/dist/flow-replies.d.ts +0 -48
- package/dist/flow-result-card.d.ts +0 -22
- package/dist/flow-schedule.d.ts +0 -154
- package/dist/flow-scripts.d.ts +0 -31
- package/dist/flow-secrets.d.ts +0 -13
- package/dist/flow-send.d.ts +0 -54
- package/dist/flow-share.d.ts +0 -78
- package/dist/flow-sort.d.ts +0 -63
- package/dist/flow-starters-ui.d.ts +0 -15
- package/dist/flow-starters.d.ts +0 -63
- package/dist/flow-steps.d.ts +0 -52
- package/dist/flow-triggers.d.ts +0 -303
- package/dist/flow-unattended-words.d.ts +0 -48
- package/dist/flow-unattended.d.ts +0 -259
- package/dist/flows-cli.d.ts +0 -358
- package/dist/flows-ui.d.ts +0 -70
- package/dist/flows.d.ts +0 -136
- package/dist/folder-gate.d.ts +0 -32
- package/dist/folder-look.d.ts +0 -110
- package/dist/follow-through-brief.d.ts +0 -12
- package/dist/follow-through-cli.d.ts +0 -23
- package/dist/fonts.d.ts +0 -19
- package/dist/gaps.d.ts +0 -35
- package/dist/gate-failure.d.ts +0 -40
- package/dist/git-floor.d.ts +0 -16
- package/dist/git-incident.d.ts +0 -65
- package/dist/git-views.d.ts +0 -20
- package/dist/git.d.ts +0 -54
- package/dist/github-import.d.ts +0 -62
- package/dist/github-jobs.d.ts +0 -25
- package/dist/google-mail.d.ts +0 -59
- package/dist/grant.d.ts +0 -136
- package/dist/graph.d.ts +0 -164
- package/dist/guides.d.ts +0 -22
- package/dist/handover-note.d.ts +0 -33
- package/dist/health-cli.d.ts +0 -3
- package/dist/home-groups.d.ts +0 -39
- package/dist/html.d.ts +0 -85
- package/dist/install-method.d.ts +0 -17
- package/dist/integrations-ui.d.ts +0 -17
- package/dist/integrations.d.ts +0 -138
- package/dist/invoke.d.ts +0 -228
- package/dist/is-record.d.ts +0 -2
- package/dist/issues.d.ts +0 -41
- package/dist/jsonl-discriminants.d.ts +0 -11
- package/dist/keymap.d.ts +0 -41
- package/dist/keys.d.ts +0 -108
- package/dist/kits-ui.d.ts +0 -16
- package/dist/kits.d.ts +0 -88
- package/dist/knowledge-cli.d.ts +0 -132
- package/dist/knowledge-ui.d.ts +0 -45
- package/dist/landed-cleanup.d.ts +0 -175
- package/dist/laptop-background.d.ts +0 -187
- package/dist/laptop-service.d.ts +0 -111
- package/dist/latency-timeline.d.ts +0 -46
- package/dist/lead-about.d.ts +0 -35
- package/dist/lead-answer-eval.d.ts +0 -93
- package/dist/lead-capabilities.d.ts +0 -57
- package/dist/lead-cli-live.d.ts +0 -56
- package/dist/lead-cli.d.ts +0 -58
- package/dist/lead-commitments.d.ts +0 -84
- package/dist/lead-context.d.ts +0 -45
- package/dist/lead-contract.d.ts +0 -10
- package/dist/lead-doors.d.ts +0 -122
- package/dist/lead-follow.d.ts +0 -26
- package/dist/lead-identity.d.ts +0 -23
- package/dist/lead-latency-schema.d.ts +0 -24
- package/dist/lead-people.d.ts +0 -55
- package/dist/lead-progress.d.ts +0 -67
- package/dist/lead-queue-runtime.d.ts +0 -46
- package/dist/lead-queue.d.ts +0 -104
- package/dist/lead-route.d.ts +0 -56
- package/dist/lead-status.d.ts +0 -116
- package/dist/lead-sweep.d.ts +0 -67
- package/dist/lead-tools.d.ts +0 -167
- package/dist/lead-voice.d.ts +0 -85
- package/dist/lead.d.ts +0 -142
- package/dist/learning-child.d.ts +0 -1
- package/dist/learning-look.d.ts +0 -25
- package/dist/ledger-chain.d.ts +0 -46
- package/dist/ledger-csv.d.ts +0 -4
- package/dist/ledger-view.d.ts +0 -27
- package/dist/lesson-notes.d.ts +0 -81
- package/dist/limits-ui.d.ts +0 -34
- package/dist/link.d.ts +0 -72
- package/dist/live-backup.d.ts +0 -39
- package/dist/live-bus.d.ts +0 -141
- package/dist/live-children-read.d.ts +0 -52
- package/dist/live-children.d.ts +0 -73
- package/dist/live-detail.d.ts +0 -27
- package/dist/live-input.d.ts +0 -68
- package/dist/live-main-read.d.ts +0 -19
- package/dist/live-notes.d.ts +0 -20
- package/dist/live-open.d.ts +0 -28
- package/dist/live-records.d.ts +0 -149
- package/dist/live-reply.d.ts +0 -83
- package/dist/live-terminal.d.ts +0 -273
- package/dist/live.d.ts +0 -152
- package/dist/local-owner.d.ts +0 -124
- package/dist/log.d.ts +0 -7
- package/dist/login-secrets.d.ts +0 -60
- package/dist/machine-check.d.ts +0 -16
- package/dist/machine-identity.d.ts +0 -75
- package/dist/mailbox.d.ts +0 -57
- package/dist/maintenance.d.ts +0 -13
- package/dist/mcp-connect.d.ts +0 -181
- package/dist/mcp-core.d.ts +0 -110
- package/dist/mcp-http.d.ts +0 -32
- package/dist/mcp-oauth.d.ts +0 -92
- package/dist/mcp-person.d.ts +0 -22
- package/dist/mcp.d.ts +0 -20
- package/dist/memory-cli.d.ts +0 -768
- package/dist/memory-pass.d.ts +0 -151
- package/dist/memory-tidy.d.ts +0 -181
- package/dist/memory-use.d.ts +0 -35
- package/dist/merge-checklist.d.ts +0 -55
- package/dist/metrics.d.ts +0 -6
- package/dist/mobile-viewport.d.ts +0 -7
- package/dist/model-catalog.d.ts +0 -123
- package/dist/model-choices.d.ts +0 -235
- package/dist/model-names.d.ts +0 -6
- package/dist/models-cli.d.ts +0 -307
- package/dist/models-ui.d.ts +0 -161
- package/dist/modes.d.ts +0 -99
- package/dist/monitoring-settings.d.ts +0 -44
- package/dist/monitoring-ui.d.ts +0 -23
- package/dist/monitoring.d.ts +0 -34
- package/dist/names.d.ts +0 -67
- package/dist/needs-you.d.ts +0 -164
- package/dist/never-index.d.ts +0 -3
- package/dist/nightly-check.d.ts +0 -107
- package/dist/nightly-github.d.ts +0 -318
- package/dist/notification-delivery.d.ts +0 -19
- package/dist/notification-rows.d.ts +0 -30
- package/dist/oauth-run-token.d.ts +0 -51
- package/dist/observations.d.ts +0 -36
- package/dist/oidc.d.ts +0 -71
- package/dist/onboard.d.ts +0 -108
- package/dist/one-step-chat-schema.d.ts +0 -22
- package/dist/openrouter-models.d.ts +0 -34
- package/dist/operate-remote-arguments.d.ts +0 -36
- package/dist/operate-remote.d.ts +0 -98
- package/dist/operate.d.ts +0 -401
- package/dist/orphan-sweep.d.ts +0 -65
- package/dist/page-work-contract.d.ts +0 -21
- package/dist/password-bearer.d.ts +0 -25
- package/dist/passwordless.d.ts +0 -23
- package/dist/peek-cli.d.ts +0 -112
- package/dist/peek.d.ts +0 -110
- package/dist/people-audit-ui.d.ts +0 -16
- package/dist/person-proof.d.ts +0 -2
- package/dist/phase-routing.d.ts +0 -401
- package/dist/plain-schema.d.ts +0 -23
- package/dist/plain-words.d.ts +0 -20
- package/dist/plan-auto.d.ts +0 -25
- package/dist/plan-login.d.ts +0 -14
- package/dist/plan.d.ts +0 -188
- package/dist/plane-review.d.ts +0 -54
- package/dist/planner-source.d.ts +0 -225
- package/dist/planner.d.ts +0 -76
- package/dist/policy-ui.d.ts +0 -22
- package/dist/policy.d.ts +0 -92
- package/dist/prepared-evidence.d.ts +0 -17
- package/dist/principal.d.ts +0 -42
- package/dist/probe.d.ts +0 -46
- package/dist/process-custody.d.ts +0 -17
- package/dist/process-liveness.d.ts +0 -13
- package/dist/process-tree.d.ts +0 -39
- package/dist/project-access.d.ts +0 -17
- package/dist/project-activity.d.ts +0 -20
- package/dist/project-admission.d.ts +0 -105
- package/dist/project-cli.d.ts +0 -19
- package/dist/project-concurrency.d.ts +0 -62
- package/dist/project-delete-ui.d.ts +0 -96
- package/dist/project-delete.d.ts +0 -59
- package/dist/project-demo.d.ts +0 -12
- package/dist/project-file.d.ts +0 -3
- package/dist/project-identity.d.ts +0 -52
- package/dist/project-knowledge.d.ts +0 -124
- package/dist/project-learning.d.ts +0 -120
- package/dist/project-memory.d.ts +0 -70
- package/dist/project-outcomes.d.ts +0 -119
- package/dist/project-sandbox.d.ts +0 -59
- package/dist/project-skills.d.ts +0 -139
- package/dist/project-tools.d.ts +0 -318
- package/dist/project.d.ts +0 -65
- package/dist/prompt.d.ts +0 -33
- package/dist/proof.d.ts +0 -457
- package/dist/proposal.d.ts +0 -70
- package/dist/protected-storage-look.d.ts +0 -1
- package/dist/protected-storage.d.ts +0 -98
- package/dist/provider-auth.d.ts +0 -143
- package/dist/provider-capture.d.ts +0 -34
- package/dist/provider-connection.d.ts +0 -23
- package/dist/provider-home.d.ts +0 -22
- package/dist/provider-limits.d.ts +0 -37
- package/dist/provider.d.ts +0 -369
- package/dist/public-access.d.ts +0 -52
- package/dist/public-check.d.ts +0 -37
- package/dist/publish.d.ts +0 -146
- package/dist/pull-request-flow.d.ts +0 -189
- package/dist/pull-request-schema.d.ts +0 -5
- package/dist/pull-request-ui.d.ts +0 -25
- package/dist/pulls.d.ts +0 -121
- package/dist/push.d.ts +0 -120
- package/dist/quality.d.ts +0 -8
- package/dist/quick-start.d.ts +0 -26
- package/dist/read-executor-worker.d.ts +0 -1
- package/dist/read-executor.d.ts +0 -66
- package/dist/read-only-request.d.ts +0 -4
- package/dist/recipe-ui.d.ts +0 -21
- package/dist/recipes.d.ts +0 -56
- package/dist/release-adapters.d.ts +0 -205
- package/dist/release-approval.d.ts +0 -180
- package/dist/release-authority.d.ts +0 -173
- package/dist/release-auto.d.ts +0 -184
- package/dist/release-card.d.ts +0 -156
- package/dist/release-carry.d.ts +0 -261
- package/dist/release-ci-hold.d.ts +0 -41
- package/dist/release-cli.d.ts +0 -34
- package/dist/release-coverage.d.ts +0 -16
- package/dist/release-gate.d.ts +0 -84
- package/dist/release-git.d.ts +0 -43
- package/dist/release-links.d.ts +0 -29
- package/dist/release-net.d.ts +0 -90
- package/dist/release-next.d.ts +0 -48
- package/dist/release-recheck.d.ts +0 -146
- package/dist/release-refusal.d.ts +0 -32
- package/dist/release-view.d.ts +0 -37
- package/dist/release.d.ts +0 -806
- package/dist/releases.d.ts +0 -94
- package/dist/remote-audit.d.ts +0 -79
- package/dist/remote-command.d.ts +0 -45
- package/dist/remote-destination.d.ts +0 -36
- package/dist/remote-exec.d.ts +0 -38
- package/dist/remote-main.d.ts +0 -111
- package/dist/remote-run.d.ts +0 -20
- package/dist/remote.d.ts +0 -67
- package/dist/render.d.ts +0 -64
- package/dist/reply-shape.d.ts +0 -106
- package/dist/reply-voice.d.ts +0 -23
- package/dist/report-summary.d.ts +0 -22
- package/dist/reported-usage.d.ts +0 -69
- package/dist/repos.d.ts +0 -67
- package/dist/repository-context-ui.d.ts +0 -3
- package/dist/repository-context.d.ts +0 -66
- package/dist/request-budget-ui.d.ts +0 -14
- package/dist/request-budget.d.ts +0 -127
- package/dist/restart-certification.d.ts +0 -133
- package/dist/result-actions.d.ts +0 -36
- package/dist/result-acts.d.ts +0 -112
- package/dist/result-completion.d.ts +0 -35
- package/dist/result-evidence-readers.d.ts +0 -42
- package/dist/result-follow-ups.d.ts +0 -118
- package/dist/result-review.d.ts +0 -220
- package/dist/result-shots.d.ts +0 -59
- package/dist/retention-ui.d.ts +0 -21
- package/dist/retention.d.ts +0 -77
- package/dist/review-context.d.ts +0 -245
- package/dist/review-evidence.d.ts +0 -33
- package/dist/review-switch.d.ts +0 -36
- package/dist/reviewer.d.ts +0 -99
- package/dist/route-change-check.d.ts +0 -4
- package/dist/route-change.d.ts +0 -22
- package/dist/route-hooks.d.ts +0 -54
- package/dist/route-results.d.ts +0 -75
- package/dist/route-rules.d.ts +0 -324
- package/dist/route-savings.d.ts +0 -136
- package/dist/route-store.d.ts +0 -300
- package/dist/run-closeout.d.ts +0 -89
- package/dist/run-efficiency.d.ts +0 -74
- package/dist/run-ending.d.ts +0 -21
- package/dist/runner-process.d.ts +0 -76
- package/dist/runner.d.ts +0 -324
- package/dist/sample-project.d.ts +0 -31
- package/dist/sandbox-launch.d.ts +0 -1
- package/dist/sandbox-runtime.d.ts +0 -128
- package/dist/scan.d.ts +0 -32
- package/dist/scope.d.ts +0 -1067
- package/dist/scout-browser-lock.d.ts +0 -69
- package/dist/scout-browser.d.ts +0 -107
- package/dist/scout-net.d.ts +0 -25
- package/dist/scout-report.d.ts +0 -23
- package/dist/scout.d.ts +0 -142
- package/dist/secret-mint.d.ts +0 -1
- package/dist/serve.d.ts +0 -11
- package/dist/server/agents-computers.d.ts +0 -9
- package/dist/server/agents-live-filed.d.ts +0 -17
- package/dist/server/agents-live-lead.d.ts +0 -47
- package/dist/server/agents-live-room.d.ts +0 -23
- package/dist/server/chat.d.ts +0 -39
- package/dist/server/chrome.d.ts +0 -328
- package/dist/server/edge-refusal.d.ts +0 -7
- package/dist/server/flows.d.ts +0 -8
- package/dist/server/guards.d.ts +0 -80
- package/dist/server/handler-context.d.ts +0 -22
- package/dist/server/handler-registry.d.ts +0 -23
- package/dist/server/home-asks.d.ts +0 -45
- package/dist/server/home.d.ts +0 -65
- package/dist/server/http.d.ts +0 -337
- package/dist/server/in-place.d.ts +0 -15
- package/dist/server/kit-standalone.d.ts +0 -22
- package/dist/server/kit.d.ts +0 -452
- package/dist/server/last-checks.d.ts +0 -17
- package/dist/server/live.d.ts +0 -74
- package/dist/server/merge-ready-view.d.ts +0 -10
- package/dist/server/mutation-key.d.ts +0 -70
- package/dist/server/pages-assets.d.ts +0 -11
- package/dist/server/pages.d.ts +0 -8
- package/dist/server/people-tokens.d.ts +0 -18
- package/dist/server/remote-hooks.d.ts +0 -29
- package/dist/server/remote.d.ts +0 -59
- package/dist/server/render-chat.d.ts +0 -439
- package/dist/server/render-code-map.d.ts +0 -30
- package/dist/server/render-flaky.d.ts +0 -20
- package/dist/server/render-follow-through.d.ts +0 -11
- package/dist/server/render-history.d.ts +0 -51
- package/dist/server/render-new-task.d.ts +0 -54
- package/dist/server/render-pages.d.ts +0 -236
- package/dist/server/render-people.d.ts +0 -102
- package/dist/server/render-projects.d.ts +0 -104
- package/dist/server/render-release.d.ts +0 -19
- package/dist/server/render-results.d.ts +0 -754
- package/dist/server/render-settings.d.ts +0 -93
- package/dist/server/render-tasks.d.ts +0 -774
- package/dist/server/request-context.d.ts +0 -78
- package/dist/server/retired-routes.d.ts +0 -17
- package/dist/server/route-policy.d.ts +0 -18
- package/dist/server/route-table.d.ts +0 -114
- package/dist/server/runtime.d.ts +0 -342
- package/dist/server/session.d.ts +0 -192
- package/dist/server/settings.d.ts +0 -76
- package/dist/server/signup-gate.d.ts +0 -9
- package/dist/server/sweeps.d.ts +0 -4
- package/dist/server/task-views.d.ts +0 -98
- package/dist/server/tasks.d.ts +0 -83
- package/dist/server/terminals.d.ts +0 -31
- package/dist/server/welcome.d.ts +0 -28
- package/dist/server-telemetry.d.ts +0 -87
- package/dist/settings-groups-ui.d.ts +0 -286
- package/dist/settings-kit-script.d.ts +0 -21
- package/dist/settings-kit.d.ts +0 -173
- package/dist/settings-proofs.d.ts +0 -64
- package/dist/setup-guide.d.ts +0 -39
- package/dist/shared-deps.d.ts +0 -115
- package/dist/sign-in-guard.d.ts +0 -70
- package/dist/skills-ui.d.ts +0 -12
- package/dist/skills.d.ts +0 -99
- package/dist/slack-api.d.ts +0 -59
- package/dist/slack-chat.d.ts +0 -37
- package/dist/slack-settings.d.ts +0 -4
- package/dist/slack-socket.d.ts +0 -12
- package/dist/slack.d.ts +0 -6
- package/dist/sleep.d.ts +0 -2
- package/dist/source-key.d.ts +0 -2
- package/dist/spend-report.d.ts +0 -87
- package/dist/spend-ui.d.ts +0 -80
- package/dist/spend.d.ts +0 -142
- package/dist/sqlite-runtime.d.ts +0 -3
- package/dist/sqlite-telemetry.d.ts +0 -9
- package/dist/sso-settings.d.ts +0 -33
- package/dist/sso-ui.d.ts +0 -26
- package/dist/staged-runtimes.d.ts +0 -54
- package/dist/steer-capabilities.d.ts +0 -32
- package/dist/steer-controls.d.ts +0 -14
- package/dist/steer-live.d.ts +0 -19
- package/dist/steer-mailbox.d.ts +0 -46
- package/dist/steer-status.d.ts +0 -25
- package/dist/stop-proof.d.ts +0 -67
- package/dist/storage-sweep-child.d.ts +0 -1
- package/dist/storage-sweep-process.d.ts +0 -55
- package/dist/storage-sweep-schedule.d.ts +0 -30
- package/dist/storage-sweep.d.ts +0 -77
- package/dist/storage-ui.d.ts +0 -23
- package/dist/storage.d.ts +0 -68
- package/dist/store-baseline.d.ts +0 -19
- package/dist/store.d.ts +0 -8613
- package/dist/stream-scope.d.ts +0 -18
- package/dist/structured-output.d.ts +0 -57
- package/dist/style-asset.d.ts +0 -7
- package/dist/subagent-admin.d.ts +0 -53
- package/dist/subagent-desk.d.ts +0 -59
- package/dist/subagent-memory.d.ts +0 -65
- package/dist/subagent-question.d.ts +0 -59
- package/dist/subagent-tools.d.ts +0 -125
- package/dist/subagent-week.d.ts +0 -68
- package/dist/subagent-work.d.ts +0 -76
- package/dist/subagents-ui.d.ts +0 -22
- package/dist/subagents.d.ts +0 -146
- package/dist/subscription-chat.d.ts +0 -54
- package/dist/summary.d.ts +0 -33
- package/dist/surface.d.ts +0 -49
- package/dist/sweep-gate.d.ts +0 -10
- package/dist/sweep-quarantine.d.ts +0 -29
- package/dist/sync.d.ts +0 -94
- package/dist/tailnet.d.ts +0 -11
- package/dist/tamper-scan.d.ts +0 -4
- package/dist/task-activity.d.ts +0 -27
- package/dist/task-aliases.d.ts +0 -5
- package/dist/task-archive.d.ts +0 -13
- package/dist/task-base.d.ts +0 -39
- package/dist/task-composer.d.ts +0 -14
- package/dist/task-control.d.ts +0 -159
- package/dist/task-live.d.ts +0 -8
- package/dist/task-moves.d.ts +0 -90
- package/dist/task-outcome-cli.d.ts +0 -30
- package/dist/task-review-brief.d.ts +0 -69
- package/dist/task-sizing.d.ts +0 -58
- package/dist/task-source.d.ts +0 -77
- package/dist/task-status.d.ts +0 -324
- package/dist/task-text.d.ts +0 -31
- package/dist/team-chat-authorization.d.ts +0 -11
- package/dist/team-contract.d.ts +0 -103
- package/dist/team-http.d.ts +0 -25
- package/dist/team-leads.d.ts +0 -85
- package/dist/team-runtime.d.ts +0 -25
- package/dist/team-ui.d.ts +0 -4
- package/dist/team-updates.d.ts +0 -8
- package/dist/teams-api.d.ts +0 -33
- package/dist/teams-chat.d.ts +0 -36
- package/dist/teams-settings.d.ts +0 -14
- package/dist/teams.d.ts +0 -24
- package/dist/teardown-git.d.ts +0 -164
- package/dist/telegram-flow.d.ts +0 -112
- package/dist/telegram-lead.d.ts +0 -151
- package/dist/telegram-live.d.ts +0 -116
- package/dist/telegram-progress.d.ts +0 -20
- package/dist/telegram-settings.d.ts +0 -9
- package/dist/telegram-status.d.ts +0 -83
- package/dist/telegram-team.d.ts +0 -68
- package/dist/telegram.d.ts +0 -271
- package/dist/templates.d.ts +0 -69
- package/dist/terminal-catalog.d.ts +0 -11
- package/dist/terminal-text.d.ts +0 -11
- package/dist/test-infra.d.ts +0 -34
- package/dist/test-temp.d.ts +0 -40
- package/dist/text-limits.d.ts +0 -297
- package/dist/tidy.d.ts +0 -130
- package/dist/tier-report.d.ts +0 -44
- package/dist/token-notices.d.ts +0 -11
- package/dist/tokens-cli.d.ts +0 -21
- package/dist/tool-broker.d.ts +0 -52
- package/dist/tool-launcher.d.ts +0 -1
- package/dist/tool-secret-store.d.ts +0 -167
- package/dist/toolroll-update-cli.d.ts +0 -15
- package/dist/toolroll-update-ui.d.ts +0 -47
- package/dist/toolroll-update.d.ts +0 -265
- package/dist/tools-ui.d.ts +0 -51
- package/dist/transitions-recipes.d.ts +0 -1
- package/dist/tree-proof.d.ts +0 -34
- package/dist/tui-contract.d.ts +0 -144
- package/dist/tui-source.d.ts +0 -14
- package/dist/typed-start.d.ts +0 -51
- package/dist/unfenced-test-support.d.ts +0 -2
- package/dist/up-processes.d.ts +0 -162
- package/dist/up-role-child.d.ts +0 -1
- package/dist/update-notice.d.ts +0 -5
- package/dist/vanished-retry.d.ts +0 -30
- package/dist/verification-evidence.d.ts +0 -68
- package/dist/version.d.ts +0 -2
- package/dist/wake-hub.d.ts +0 -72
- package/dist/webhook-limits.d.ts +0 -23
- package/dist/webhook-readers.d.ts +0 -56
- package/dist/webhook-signing.d.ts +0 -27
- package/dist/webhooks.d.ts +0 -84
- package/dist/welcome-facts.d.ts +0 -18
- package/dist/when-html.d.ts +0 -40
- package/dist/work-index.d.ts +0 -175
- package/dist/work-summary.d.ts +0 -61
- package/dist/workspace-motion.d.ts +0 -4
- package/dist/workspace-revision.d.ts +0 -48
- package/dist/workspace-ui.d.ts +0 -385
- package/dist/worktree-notices.d.ts +0 -13
- package/dist/worktree.d.ts +0 -365
- package/dist/writes-mode.d.ts +0 -9
- package/dist/youiyoux-intake.d.ts +0 -234
package/dist/server/tasks.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { advancedShownNow } from "../advanced-view.js";
|
|
1
2
|
import { titleWithin } from "../task-text.js";
|
|
2
3
|
import { parseFeedbackImage, sameFeedbackImage } from "../result-review.js";
|
|
3
4
|
import { archiveTaskFamily, dropFeedbackImage, releaseAuthorityOfTask, restoreTaskFamily, revokeRelease, runCheckStamp, runLiveCommands } from "../store.js";
|
|
@@ -5,7 +6,6 @@ import { ranWords } from "../check-stamp.js";
|
|
|
5
6
|
import { applyTidy, approverStandsNow, familyRepoOf, releaseFactsOf, tidyDays, tidyDigest, tidyPreview, TIDY_DEFAULT_DAYS } from "../tidy.js";
|
|
6
7
|
import { steerCapabilityOf } from "../steer-capabilities.js";
|
|
7
8
|
import { canReveal, localCheckoutOf, revealInFinder } from "../checkout-proof.js";
|
|
8
|
-
/** A form's way back to a flow card ("flow:<flow>:<card>"), read strictly: numbers only, never a path. */
|
|
9
9
|
function returnedFlow(value) {
|
|
10
10
|
const match = /^flow:([1-9][0-9]{0,9}):([1-9][0-9]{0,9})$/.exec(value ?? "");
|
|
11
11
|
return match === null ? null : { flow: Number(match[1]), card: Number(match[2]) };
|
|
@@ -15,7 +15,6 @@ import { ACP_AGENTS, isAcpProvider } from "../acp-agents.js";
|
|
|
15
15
|
import { handlersOf } from './handler-registry.js';
|
|
16
16
|
import { closedQuestionWords, LIMITS } from "../decision.js";
|
|
17
17
|
import { DEPRECATED_PAGE } from "../deprecations.js";
|
|
18
|
-
/** tasks handlers, moved without changing their route bodies. */
|
|
19
18
|
import { html, htmlString, joinHtml, postForm, textHtml } from "../html.js";
|
|
20
19
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
21
20
|
import { existsSync, lstatSync, realpathSync } from "node:fs";
|
|
@@ -30,6 +29,7 @@ import { codingShippingHtml } from '../coding-shipping-ui.js';
|
|
|
30
29
|
import { codingWorkspaceHtml, codingWorkspaceScript } from '../coding-ui.js';
|
|
31
30
|
import { CodingActionError } from '../coding-workspace.js';
|
|
32
31
|
import { checkResponse, CONSOLE_FORMS, readForm } from "../contracts/console-api.js";
|
|
32
|
+
import { LOCAL_TASK_CHANGED, requestPlanAsLocalOwner, retryAsLocalOwner, retryPinsOf } from "../local-owner-acts.js";
|
|
33
33
|
import { hasForbiddenControls, validateNote } from "../decision.js";
|
|
34
34
|
import { builderReadyFor, diagnoseTaskDispatch, firstRunBuilderRepo } from "../dispatch.js";
|
|
35
35
|
import { firstTaskSuggestions, withBuilderStep } from "../first-run.js";
|
|
@@ -93,12 +93,9 @@ import { approvalFactsNow } from "./kit.js";
|
|
|
93
93
|
import { localOwnerRefusal } from "../local-owner.js";
|
|
94
94
|
export function createTasksHandlers(runtime) {
|
|
95
95
|
const { identities, store, peekSay, peekCache, PEEK_CACHE_TTL_MS, peekInFlight, PEEK_GLOBAL_INFLIGHT, peekBySession, PEEK_SESSION_INFLIGHT, clock, peekName, PEEK_FRAGMENT_BYTES, peekEvict, evidenceRoot, sendScreen, chromeFor, visible, consumeApprovalNonce, authenticateApprover, options, mintApprovalNonce, taskScreen, unscopedMode, admissionList, planViewOf, revisionViewOf, runIsTaskResult, leadPrincipal, familyOf, armTaskResume, runIsLive, revisionLedgerOf, resultDetailOf, reviewFactsFor, taskRepoOf, runVisible, restricted, codingActorAllowed, codingProjectAllowed, managedRepos, routeViewOf, workAccess, firstRunStepsNow, revisionDocOf, failureOf, dockedConversation, planContractViewOf, familiesInView, explainAttempt, taskChatFocus, familyTasksInView, liveCeiling, projectOf, ceiling, bustBadge, revisionDestination } = runtime;
|
|
96
|
-
/** A row admitted the address but its path parameter does not parse: the console's unknown page. */
|
|
97
96
|
function noPage(who, response) {
|
|
98
97
|
return refuse(response, who, 404, "There's no page at this address.", "/chat");
|
|
99
98
|
}
|
|
100
|
-
// `posted`: the session page's own POST (form token). A GET of changes or the shipping preview runs no git in the
|
|
101
|
-
// agent's checkout: changes go back to the session page, the preview asks for one click.
|
|
102
99
|
const showCode = (part, posted = false) => async (ctx) => {
|
|
103
100
|
const { url, who, response, project } = ctx;
|
|
104
101
|
if (who.via !== 'cookie' || !codingActorAllowed({ name: who.name, generation: who.session.generation }))
|
|
@@ -154,14 +151,7 @@ export function createTasksHandlers(runtime) {
|
|
|
154
151
|
};
|
|
155
152
|
async function showWork(ctx) {
|
|
156
153
|
const { url, who, response, now, project } = ctx;
|
|
157
|
-
// The Work destination (workspace package 1): every task in view as
|
|
158
|
-
// one row wearing the shared status projection, with All, Needs you,
|
|
159
|
-
// Running, and Completed as shortcuts over the same rows — never a
|
|
160
|
-
// persisted state. With no project open in scoped mode this rolls
|
|
161
|
-
// up like the inbox: admission binds the query and every row's repo
|
|
162
|
-
// is re-proved here.
|
|
163
154
|
const view = parseWorkView(url.searchParams.get("view"));
|
|
164
|
-
// The stored-state filter the old task list had (`?state=`): an unknown state is refused, as it was there.
|
|
165
155
|
const wantedState = url.searchParams.get("state");
|
|
166
156
|
if (wantedState !== null && !TASK_STATES.includes(wantedState))
|
|
167
157
|
return refuse(response, who, 400, "no such state", "/tasks");
|
|
@@ -171,10 +161,7 @@ export function createTasksHandlers(runtime) {
|
|
|
171
161
|
try {
|
|
172
162
|
work = workIndexPage(store, now, workAccess(), { view, limit: 40, cursor: url.searchParams.get('cursor'), project, root: evidenceRoot, ...(state === null ? {} : { state }) });
|
|
173
163
|
const facts = requestContext.getStore();
|
|
174
|
-
// A filtered page never stands in for the counts or the Crew: those read the unfiltered work.
|
|
175
164
|
if (facts !== undefined && state === null) {
|
|
176
|
-
// These counts cover the exact admitted project lens, including
|
|
177
|
-
// unplaced tasks where permitted. Crew excludes unplaced rows.
|
|
178
165
|
if (project === null)
|
|
179
166
|
facts.workCounts = work.projects;
|
|
180
167
|
const admitted = workAccess().repos;
|
|
@@ -188,10 +175,6 @@ export function createTasksHandlers(runtime) {
|
|
|
188
175
|
return refuse(response, who, 400, 'This task page has expired. Open the first page.', '/tasks');
|
|
189
176
|
throw error;
|
|
190
177
|
}
|
|
191
|
-
// A failed row says what its latest attempt missed, as its task page does (a stop reason already reads so), from
|
|
192
|
-
// the database alone: a row reads no check log. A live build's row says which step it is on, or the step it is
|
|
193
|
-
// stuck on, from that live attempt's own progress only, never a stopped attempt's; the step's words come from its
|
|
194
|
-
// current plan (one saved file, for live rows only), and without it the row names the step by number.
|
|
195
178
|
const enrich = (page) => ({ ...page, items: page.items.map((item) => {
|
|
196
179
|
if (item.liveRunId !== null) {
|
|
197
180
|
const ref = store.lookupRef(item.activeTaskId);
|
|
@@ -213,7 +196,6 @@ export function createTasksHandlers(runtime) {
|
|
|
213
196
|
return failure.kind === "reason" ? item : { ...item, status: { ...item.status, detail: failure.line } };
|
|
214
197
|
}) });
|
|
215
198
|
work = enrich(work);
|
|
216
|
-
// The Board view: the same index as four columns (needs you, queued, running, finished), never a second classifier.
|
|
217
199
|
const board = url.searchParams.get("layout") !== "board" ? null : (() => {
|
|
218
200
|
const column = (view) => enrich(workIndexPage(store, now, workAccess(), { view, limit: BOARD_COLUMN_LIMIT, project, root: evidenceRoot, ...(state === null ? {} : { state }) }));
|
|
219
201
|
return { needs: column("needs-you"), queued: column("queued"), running: column("running"), finished: column("completed") };
|
|
@@ -230,69 +212,50 @@ export function createTasksHandlers(runtime) {
|
|
|
230
212
|
now,
|
|
231
213
|
state,
|
|
232
214
|
canPutAway: who.via === "cookie" && who.role === "approver",
|
|
233
|
-
|
|
234
|
-
limits: store.isInstanceOperator(who.name)
|
|
215
|
+
limits: store.isInstanceOperator(who.name) && advancedShownNow()
|
|
235
216
|
? limitsView(store.providerLimits(), store.budgets().length === 0 ? [] : store.monthSpendCached(now).budgets, { project: projectName, subagent: id => subagentNamesOf(store.handle).get(id) ?? `Subagent ${id}` }, now)
|
|
236
217
|
: null,
|
|
237
218
|
});
|
|
238
|
-
// One project's Tasks dock that project's own conversation (v77).
|
|
239
219
|
const projectThread = url.searchParams.has('project') && project !== null && managedRepos().includes(project) ? project : null;
|
|
240
220
|
const docked = projectThread === null ? null : dockedConversation(who, null, projectThread, now, `/tasks?project=${encodeURIComponent(projectThread)}`);
|
|
241
221
|
if (docked !== null)
|
|
242
222
|
page.workspace = { ...page.workspace, conversation: docked, pageHtml: page.body };
|
|
243
|
-
// Without a docked chat the list reads itself: 10 s while any of its tasks is building, else 30 s.
|
|
244
223
|
page.refreshSeconds = work.totals.running > 0 ? 10 : 30;
|
|
245
224
|
return sendScreen(response, 200, page);
|
|
246
225
|
}
|
|
247
|
-
/** A completed (or attempted) row as the review list ranks it: its proof reasons, CI standing, and the assignment
|
|
248
|
-
* when that assignment's receipt is this very row. */
|
|
249
226
|
function reviewRowOf(row, now) {
|
|
250
227
|
const assignment = assignmentOf(store, row.taskId, now, workAccess(), evidenceRoot);
|
|
251
228
|
return { ...row, proofReasons: row.runId === null ? [] : store.proofVerdictFor(row.runId)?.reasons ?? [], ciFailing: ciFailingFor(row.runId, row.prNumber),
|
|
252
229
|
assignment: assignment?.activeTaskId === row.taskId && (assignment.receipt?.runId ?? null) === row.runId ? assignment : null };
|
|
253
230
|
}
|
|
254
|
-
/** The result a link names (the task's own result, or the exact run `namedRun` of it): its completed row when the
|
|
255
|
-
* task is done (`inQueue` when the review list already holds it), else that attempt's own result (a failed or stopped
|
|
256
|
-
* build has a result page too), with what went wrong and Retry / Accept anyway as the review page offers them.
|
|
257
|
-
* Shared by /review and the task page's Result tab (docs/plans/one-page-task-and-agent.md). */
|
|
258
231
|
function selectResultFor(wantedId, namedRun, project, who, now, inQueue = null) {
|
|
259
232
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
260
233
|
const beyond = inQueue !== null ? null : completedRowFor(wantedId, project);
|
|
261
234
|
const beyondRow = beyond === null ? null : reviewRowOf(beyond, now);
|
|
262
235
|
const completedChoice = inQueue ?? (beyondRow === null ? null : { ...beyondRow, priority: reviewPriorityOf(beyondRow) });
|
|
263
|
-
// A build that failed (or stopped) has its own result page too: the run named, or a failed task's latest attempt.
|
|
264
236
|
const attempt = (completedChoice !== null && (namedRun === null || completedChoice.runId === namedRun)) ? null : attemptRowFor(wantedId, namedRun, project);
|
|
265
237
|
const attemptRow = attempt === null ? null : reviewRowOf(attempt, now);
|
|
266
238
|
const chosen = attemptRow !== null ? { ...attemptRow, priority: reviewPriorityOf(attemptRow) } : completedChoice;
|
|
267
239
|
const selected = chosen === null ? null : reviewCockpitViewOf(chosen, who, now);
|
|
268
|
-
// A build that delivered nothing reads Failed here, and so does a failed task's delivered result: what went wrong
|
|
269
|
-
// is the card and Retry the ink act. That result may still be accepted, but only in outline, as Accept anyway, with
|
|
270
|
-
// a reason.
|
|
271
240
|
const delivered = selected?.run?.outcome === "built" || selected?.run?.outcome === "no-change";
|
|
272
241
|
const failedTask = selected === null ? null : store.getTask(selected.taskId);
|
|
273
242
|
if (selected !== null && attemptRow !== null && selected.run !== null && (!delivered || failedTask?.state === "failed")) {
|
|
274
243
|
const attemptRun = store.getRun(selected.run.id);
|
|
275
244
|
const runs = attemptRun === null ? [] : store.runsFor(attemptRun.taskRef);
|
|
276
245
|
const latest = latestFinishedAttempt(runs);
|
|
277
|
-
// Retry from here only when the task failed, nothing holds it, and this is its latest attempt or a result it delivered.
|
|
278
246
|
const retry = failedTask?.state === "failed" && (latest?.id === selected.run.id || delivered) && csrf !== "" && who.role === "approver" && store.currentLiveLease(attemptRun.taskRef, now) === null
|
|
279
|
-
? { action: `${taskHref(selected.taskId)}/requeue
|
|
280
|
-
// Accept anyway: the same acceptance this task's latest result takes, never for an older one or one already accepted.
|
|
247
|
+
? { action: `${taskHref(selected.taskId)}/requeue`, pins: retryPinsOf(store, selected.taskId) } : null;
|
|
281
248
|
const family = delivered ? familyOf(selected.taskId) : null;
|
|
282
249
|
const acceptAnyway = delivered && csrf !== "" && who.role === "approver" && family?.current.id === selected.taskId && family.problem === null &&
|
|
283
250
|
runs.find(runIsTaskResult)?.id === selected.run.id && store.proofAcceptance(selected.run.id) === null
|
|
284
251
|
? { action: `${taskHref(selected.taskId)}/accept-proof`, run: selected.run.id } : null;
|
|
285
252
|
if (attemptRun !== null) {
|
|
286
|
-
// A delivered result didn't fail itself: the task's failure is its latest attempt's.
|
|
287
253
|
const failure = delivered ? failureOf(runs, null) : explainAttempt(attemptRun, null);
|
|
288
254
|
selected.failure = { ...failure, retry: retry === null ? null : { ...retry, note: retryNoteOf(failure.suggestion) }, ...(acceptAnyway === null ? {} : { acceptAnyway }) };
|
|
289
255
|
}
|
|
290
256
|
}
|
|
291
257
|
return { chosen, attemptRow, beyond, selected };
|
|
292
258
|
}
|
|
293
|
-
/** Whether `run` is a result selectResultFor shows for version `taskId`: a finished attempt that didn't deliver (failed,
|
|
294
|
-
* stopped, refused…), or the delivered one that is the version's own result — its completed row's, or, for a failed
|
|
295
|
-
* version, its latest finished attempt. An older delivered build is not (its version's result is the newer one). */
|
|
296
259
|
function resultRunAdmissible(taskId, run, project) {
|
|
297
260
|
if ((run.role !== "builder" && run.role !== "scout") || (run.finishedAt === null && run.outcome === null) || runIsLive(run))
|
|
298
261
|
return false;
|
|
@@ -303,21 +266,12 @@ export function createTasksHandlers(runtime) {
|
|
|
303
266
|
return latestFinishedAttempt(store.runsFor(run.taskRef).filter(one => (one.role === "builder" || one.role === "scout") && (one.finishedAt !== null || one.outcome !== null)))?.id === run.id;
|
|
304
267
|
return completedRowFor(taskId, project)?.runId === run.id;
|
|
305
268
|
}
|
|
306
|
-
/** A run's own task and its family's root: the task pages a result form may return to. */
|
|
307
269
|
function runTasks(taskRef) {
|
|
308
270
|
const task = store.externalIdFor(taskRef);
|
|
309
271
|
return task === null ? [] : [task, familyOf(task)?.root.id ?? task];
|
|
310
272
|
}
|
|
311
273
|
async function showReview(ctx) {
|
|
312
274
|
const { url, who, response, now, project, chosenProject } = ctx;
|
|
313
|
-
// The review cockpit (Priority 5): every visible COMPLETED task,
|
|
314
|
-
// ranked by review priority, with one selected result projected
|
|
315
|
-
// from the records the task, run, and done pages already read —
|
|
316
|
-
// scope, plan, run, artifacts, verdict, publication. The
|
|
317
|
-
// ranking is a labeled presentation aid: it never rewrites the
|
|
318
|
-
// stored verdict, and the sealed patch downloads exactly as stored.
|
|
319
|
-
// Admission binds BEFORE the SQL limit (the done page's own rule),
|
|
320
|
-
// and every row is re-proved against the ceiling before ranking.
|
|
321
275
|
const resultRow = (row) => reviewRowOf(row, now);
|
|
322
276
|
const rows = familiesInView(project, { states: ["done"], limit: REVIEW_QUEUE_CAP }).flatMap(family => {
|
|
323
277
|
const row = completedRowFor(family.current.id, project);
|
|
@@ -327,34 +281,23 @@ export function createTasksHandlers(runtime) {
|
|
|
327
281
|
const wanted = url.searchParams.get("result");
|
|
328
282
|
const wantedId = wanted === null || wanted.length === 0 || wanted.length > 64 || hasForbiddenControls(wanted) ? null : wanted;
|
|
329
283
|
const inQueue = wantedId === null ? null : ranked.find(one => one.taskId === wantedId) ?? null;
|
|
330
|
-
// A stable deep link outlives the queue window (v2 review, comment
|
|
331
|
-
// 1): a completion older than the newest REVIEW_QUEUE_CAP resolves
|
|
332
|
-
// directly — re-proved as done, in this project, and inside the
|
|
333
|
-
// ceiling — so an old receipt never reads as unfinished or foreign.
|
|
334
|
-
// The ranked queue itself stays bounded and says so.
|
|
335
284
|
const expectedRun = url.searchParams.get("run");
|
|
336
285
|
const namedRun = expectedRun !== null && /^[1-9]\d*$/.test(expectedRun) ? Number(expectedRun) : null;
|
|
337
286
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
338
287
|
const picked = wantedId === null ? null : selectResultFor(wantedId, namedRun, project, who, now, inQueue);
|
|
339
288
|
const chosen = picked?.chosen ?? null, attemptRow = picked?.attemptRow ?? null, beyond = picked?.beyond ?? null;
|
|
340
289
|
const selectedRow = wantedId === null ? ranked[0] ?? null : chosen;
|
|
341
|
-
// An exact link to a result this person can't see (or that never existed) reads the same either way.
|
|
342
290
|
if (expectedRun !== null && wantedId !== null && chosen === null)
|
|
343
291
|
return refuse(response, who, 404, "No such result in your projects.", "/tasks");
|
|
344
292
|
if (expectedRun !== null && (!/^[1-9]\d*$/.test(expectedRun) || selectedRow?.runId !== Number(expectedRun))) {
|
|
345
293
|
return sendScreen(response, 409, screen("Result changed", html `<h1>Result changed</h1><p>This acceptance link no longer matches the current result. Review the current task before accepting.</p><p class="refusal-back"><a class="button-link" href="/tasks?view=ready">Review results</a></p>`, { chrome: chromeFor(project, "runs") }));
|
|
346
294
|
}
|
|
347
295
|
const selected = picked !== null ? picked.selected : selectedRow === null ? null : reviewCockpitViewOf(selectedRow, who, now);
|
|
348
|
-
// Opening a run's own result page is viewing it: the shell says so with a keyed POST /agents/seen (easy-start N1:
|
|
349
|
-
// a page load never writes), which leaves this person's unread Done once the run has finished.
|
|
350
296
|
const reviewPage = reviewCockpitPage(chromeFor(wantedId === null ? project : chosenProject, "runs"), {
|
|
351
297
|
queue: ranked,
|
|
352
298
|
queueCap: REVIEW_QUEUE_CAP,
|
|
353
299
|
selected,
|
|
354
300
|
beyondQueue: beyond !== null && attemptRow === null,
|
|
355
|
-
// A deep link to a result this console cannot show — not done,
|
|
356
|
-
// not admitted, or never existed — says so in one sentence and
|
|
357
|
-
// shows the top of the queue; the three cases read identically.
|
|
358
301
|
missing: wantedId !== null && chosen === null ? wantedId : null,
|
|
359
302
|
csrf,
|
|
360
303
|
canRetryReview: who.via === "cookie" && who.role === "approver",
|
|
@@ -364,8 +307,6 @@ export function createTasksHandlers(runtime) {
|
|
|
364
307
|
user: who.name,
|
|
365
308
|
now,
|
|
366
309
|
});
|
|
367
|
-
// The result's task conversation, docked beside it (v77); messages
|
|
368
|
-
// sent here carry the result being viewed.
|
|
369
310
|
const reviewFocus = selected === null ? null : taskChatFocus(selected.taskId, now, who, { mintNonce: false });
|
|
370
311
|
const reviewDocked = reviewFocus === null || selected === null ? null
|
|
371
312
|
: dockedConversation(who, reviewFocus, null, now, reviewHref(selected.taskId), selected.run !== null && reviewFocus.family.versions.some(one => one.refId === store.getRun(selected.run.id)?.taskRef) ? selected.run.id : null);
|
|
@@ -373,11 +314,6 @@ export function createTasksHandlers(runtime) {
|
|
|
373
314
|
reviewPage.workspace = { ...reviewPage.workspace, conversation: reviewDocked, pageHtml: reviewPage.body };
|
|
374
315
|
return sendScreen(response, 200, reviewPage);
|
|
375
316
|
}
|
|
376
|
-
/** The old task list, retired into /work (docs/plans/reui-polish.md slice 7): its address keeps answering, as a
|
|
377
|
-
* redirect, so links and bookmarks still land. `state` carries over (an unknown one is still refused); `template`
|
|
378
|
-
* goes to the add page, which now pre-fills it. Anything else is dropped. */
|
|
379
|
-
/** Tasks (docs/plans/plain-toolroll.md P1.4): the one list, with List, Board, Ready, Archived and an every-project
|
|
380
|
-
* scope (`scope=all`). `view=board` is the Board, `view=order` the queue's order, `view=done` Finished. */
|
|
381
317
|
async function showTasks(ctx) {
|
|
382
318
|
const { url } = ctx;
|
|
383
319
|
const template = url.searchParams.get("template");
|
|
@@ -386,7 +322,6 @@ export function createTasksHandlers(runtime) {
|
|
|
386
322
|
const view = url.searchParams.get("view");
|
|
387
323
|
if (view === "order")
|
|
388
324
|
return showOrder(ctx);
|
|
389
|
-
// The list reads its own keys: Board is its layout, every project its roll-up, Finished its completed view.
|
|
390
325
|
const read = new URL(url.href);
|
|
391
326
|
if (view === "board") {
|
|
392
327
|
read.searchParams.delete("view");
|
|
@@ -400,7 +335,6 @@ export function createTasksHandlers(runtime) {
|
|
|
400
335
|
}
|
|
401
336
|
return showWork({ ...ctx, url: read });
|
|
402
337
|
}
|
|
403
|
-
/** The queue's order view, under Tasks: dispatch order with drag handles (scheduling, never authority). */
|
|
404
338
|
async function showOrder(ctx) {
|
|
405
339
|
const { url, who, response, project } = ctx;
|
|
406
340
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
@@ -415,8 +349,6 @@ export function createTasksHandlers(runtime) {
|
|
|
415
349
|
html `<p class="meta" id="queue-region-stamp"></p>`,
|
|
416
350
|
], "\n"), { chrome: chromeFor(project, "work"), functional: { script: queueScript(), fetches: true } }));
|
|
417
351
|
}
|
|
418
|
-
/** /n/<number>: a push's task link, by the task's stored number, never its title. It opens the task's page only
|
|
419
|
-
* inside the viewer's own projects; anything else is the same not-found as an unknown number. */
|
|
420
352
|
async function showNumberedTask(ctx) {
|
|
421
353
|
const { url, who, response } = ctx;
|
|
422
354
|
const number = Number(url.pathname.slice("/n/".length));
|
|
@@ -432,7 +364,6 @@ export function createTasksHandlers(runtime) {
|
|
|
432
364
|
const prefill = picked !== null && picked.kind === "task"
|
|
433
365
|
? { title: picked.title, goal: picked.goal, not: picked.outOfScope ?? "", touches: picked.touches.join(", "), acceptance: acceptanceToLines(picked.acceptance).join("\n") }
|
|
434
366
|
: null;
|
|
435
|
-
// An idea's link (or any ?text=) puts words in the box: bounded to what the box takes, nothing filed.
|
|
436
367
|
const text = ctx.url.searchParams.get("text");
|
|
437
368
|
return newTaskScreen(ctx, 200, null, prefill, text === null ? null : text.slice(0, 200));
|
|
438
369
|
}
|
|
@@ -447,24 +378,17 @@ export function createTasksHandlers(runtime) {
|
|
|
447
378
|
const version = url.searchParams.get("version");
|
|
448
379
|
if (version !== null && !family.versions.some(one => one.id === version))
|
|
449
380
|
return refuse(response, who, 404, "That version is not available for this task.", taskHref(family.root.id));
|
|
450
|
-
// A version's own address lands on its family's page, still asking for the plan editor when it did (Chat's Edit plan).
|
|
451
381
|
if (task.taskId !== family.root.id) {
|
|
452
|
-
// Everything else the address asked for (its tab, result run and view, a form's feedback) rides along.
|
|
453
382
|
const kept = new URLSearchParams(url.searchParams);
|
|
454
383
|
kept.delete("version");
|
|
455
384
|
return redirect(response, `${taskHref(family.root.id)}?version=${encodeURIComponent(task.taskId)}${kept.size === 0 ? "" : `&${kept.toString()}`}`);
|
|
456
385
|
}
|
|
457
|
-
// One page per task (docs/plans/one-page-task-and-agent.md): the tab named, and the Result tab's result — the shown
|
|
458
|
-
// version's own, or the exact run `run=` names, which must be a result of that very version.
|
|
459
386
|
const tabWord = url.searchParams.get("tab");
|
|
460
|
-
// The first tab (Plan, or Result once there is one) unless the address names Activity or Attempts.
|
|
461
387
|
const tab = tabWord === "result" || tabWord === "activity" || tabWord === "attempts" ? tabWord : "plan";
|
|
462
388
|
const runWord = url.searchParams.get("run");
|
|
463
389
|
const named = runWord === null ? null : /^[1-9][0-9]{0,14}$/.test(runWord) ? Number(runWord) : -1;
|
|
464
390
|
if (named === -1)
|
|
465
391
|
return refuse(response, who, 404, "No such result for this task.", taskHref(family.root.id));
|
|
466
|
-
// A run named without a version is shown with the version it belongs to: a saved link to a result outlives a newer
|
|
467
|
-
// revision becoming current. A run of no version of this family is no result of it.
|
|
468
392
|
const owner = named === null || version !== null ? null : (() => { const ref = store.getRun(named)?.taskRef; const id = ref === undefined ? null : store.externalIdFor(ref); return id !== null && family.versions.some(one => one.id === id) ? id : null; })();
|
|
469
393
|
const shown = version ?? owner ?? family.current.id;
|
|
470
394
|
const picked = selectResultFor(shown, named, ctx.project, who, ctx.now);
|
|
@@ -474,19 +398,15 @@ export function createTasksHandlers(runtime) {
|
|
|
474
398
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
475
399
|
const result = picked.selected === null ? null : (() => {
|
|
476
400
|
const parts = reviewCockpitDetailParts(picked.selected, csrf, url.searchParams.get("noted") !== null, who.via === "cookie" && who.role === "approver", parseResultTab(url.searchParams.get("section")), who.name, { kind: "task", base });
|
|
477
|
-
// Current: the result the task itself would show (its latest), however the address named it — the header then
|
|
478
|
-
// owns its status and ceremonies, so no form is ever on the page twice.
|
|
479
401
|
const latest = named === null ? picked.chosen?.runId ?? null : selectResultFor(shown, null, ctx.project, who, ctx.now).chosen?.runId ?? null;
|
|
480
402
|
return { html: parts.html, selected: parts.selected, current: shown === family.current.id && latest !== null && latest === picked.chosen?.runId };
|
|
481
403
|
})();
|
|
482
|
-
// The attempts the picker offers: exactly the runs this page would show for their version (the same rule as above).
|
|
483
404
|
const admissible = new Set(family.versions.flatMap(one => {
|
|
484
405
|
const ref = store.lookupRef(one.id);
|
|
485
406
|
return ref === null ? [] : store.runsFor(ref.id).filter(run => resultRunAdmissible(one.id, run, ctx.project)).map(run => run.id);
|
|
486
407
|
}));
|
|
487
408
|
return taskScreen(response, who, shown, null, 200, undefined, undefined, url.searchParams.get("edit") === "plan", { tab, result, admissible });
|
|
488
409
|
}
|
|
489
|
-
// v103: a task's evidence pack, as a printable page or JSON (the whole family, sealed ledger entries included).
|
|
490
410
|
async function showTaskEvidence(ctx) {
|
|
491
411
|
const { url, who, response, now } = ctx;
|
|
492
412
|
const evidence = matchTaskPath(url.pathname, "/evidence$");
|
|
@@ -508,8 +428,6 @@ export function createTasksHandlers(runtime) {
|
|
|
508
428
|
}
|
|
509
429
|
return sendScreen(response, 200, evidenceRecordPage(chromeFor(family.root.repo, "tasks"), pack));
|
|
510
430
|
}
|
|
511
|
-
/** Build history lives on Agents now ("Finished in the last …"), and each task keeps its own attempts: the old address
|
|
512
|
-
* keeps answering, as a GET alias. */
|
|
513
431
|
async function showRuns(ctx) {
|
|
514
432
|
return redirectGet(ctx.response, "/agents");
|
|
515
433
|
}
|
|
@@ -529,14 +447,9 @@ export function createTasksHandlers(runtime) {
|
|
|
529
447
|
return respond(response, 200, "text/html; charset=utf-8", checkProgressHtml(store.checkProgress(found.id)));
|
|
530
448
|
}
|
|
531
449
|
if (url.searchParams.get("fragment") === "facts") {
|
|
532
|
-
// The facts region alone — same auth and ceiling as the page; a
|
|
533
|
-
// finished or no-longer-live run says so rather than growing forms
|
|
534
|
-
// (finding 5; round-4 finding 15).
|
|
535
450
|
return respond(response, 200, "text/html; charset=utf-8", runFactsFragment(found, taskId, running, store.runRoute(found.id)));
|
|
536
451
|
}
|
|
537
452
|
if (url.searchParams.get("fragment") === "peek") {
|
|
538
|
-
// The live peek: cookie sessions only (v2 §3), never stored, never
|
|
539
|
-
// cached by anything downstream.
|
|
540
453
|
if (who.via !== "cookie")
|
|
541
454
|
return respond(response, 403, "text/plain; charset=utf-8", "the live peek is a browser session's view");
|
|
542
455
|
const peeked = await peekFragment(found.id, who.session.csrf, options.editorLinks !== undefined && found.runner === options.localRunner && who.session.editorLinks === true);
|
|
@@ -546,18 +459,10 @@ export function createTasksHandlers(runtime) {
|
|
|
546
459
|
return respond(response, peeked.status, "text/html; charset=utf-8", peeked.body);
|
|
547
460
|
}
|
|
548
461
|
if (url.searchParams.get("fragment") === "transcript") {
|
|
549
|
-
// The live conversation's window (arc 1; live-conversation.md §3–4):
|
|
550
|
-
// JSON over sanitized text or records — the sinks are textContent and
|
|
551
|
-
// React text, never innerHTML. Guards, enumerated: cookie session; run
|
|
552
|
-
// visible (proved above); this machine's runner asserted AND owning
|
|
553
|
-
// the run; byte offsets validated; the file read through its own
|
|
554
|
-
// descriptor with the exact numeric-id name, and its generation
|
|
555
|
-
// matched. Display state, not evidence — and never cached.
|
|
556
462
|
response.setHeader("cache-control", "no-store");
|
|
557
463
|
if (who.via !== "cookie")
|
|
558
464
|
return respond(response, 403, "application/json", JSON.stringify({ error: "session" }));
|
|
559
465
|
const records = url.searchParams.get("shape") === "records";
|
|
560
|
-
// Notes come from the store, not the file: they show even where the transcript cannot be read.
|
|
561
466
|
const notesOf = () => (records ? runNotes(store, found, who.name, now) : {});
|
|
562
467
|
if (options.localRunner === undefined || found.runner !== options.localRunner) {
|
|
563
468
|
return respond(response, 200, "application/json", JSON.stringify({ error: "off", ...notesOf() }));
|
|
@@ -569,27 +474,19 @@ export function createTasksHandlers(runtime) {
|
|
|
569
474
|
}
|
|
570
475
|
const sawGen = url.searchParams.get("gen");
|
|
571
476
|
const live = runIsLive(found);
|
|
572
|
-
// The final drain: a finished run's tail — including a torn last
|
|
573
|
-
// line — may be read until the sweep removes the file.
|
|
574
477
|
const window = readLiveWindow(evidenceRoot, found.id, from, !live);
|
|
575
478
|
if (!window.ok) {
|
|
576
479
|
if (window.reason === "replaced") {
|
|
577
480
|
return respond(response, 409, "application/json", JSON.stringify({ error: "replaced" }));
|
|
578
481
|
}
|
|
579
|
-
// Missing or unreadable: nothing to show. Final only when the
|
|
580
|
-
// run can never write again.
|
|
581
|
-
// Nothing was read, so the key state the cursor carried is handed straight back.
|
|
582
482
|
const inKey = url.searchParams.get("inkey") === "1";
|
|
583
483
|
const keyTail = validKeyTail(url.searchParams.get("ktail") ?? "") ? url.searchParams.get("ktail") ?? "" : "";
|
|
584
484
|
const empty = records ? { records: [], nextOffset: from, gen: sawGen, inKey, keyTail, final: !live } : { text: "", nextOffset: from, inKey, keyTail, final: !live };
|
|
585
485
|
return respond(response, 200, "application/json", JSON.stringify({ ...empty, ...notesOf() }));
|
|
586
486
|
}
|
|
587
|
-
// An offset belongs to the file it was read from: another file starts over, visibly.
|
|
588
487
|
if (sawGen !== null && sawGen !== "" && sawGen !== window.gen) {
|
|
589
488
|
return respond(response, 409, "application/json", JSON.stringify({ error: "replaced" }));
|
|
590
489
|
}
|
|
591
|
-
// Re-proof after the read (peek discipline): the run row still says
|
|
592
|
-
// what admission said — visible, and still this machine's — or nothing is shown.
|
|
593
490
|
const again = store.getRun(found.id);
|
|
594
491
|
if (again === null || !runVisible(again) || again.runner !== options.localRunner) {
|
|
595
492
|
const inKey = url.searchParams.get("inkey") === "1";
|
|
@@ -597,35 +494,25 @@ export function createTasksHandlers(runtime) {
|
|
|
597
494
|
return respond(response, 200, "application/json", JSON.stringify(records ? { records: [], nextOffset: from, gen: window.gen, inKey, keyTail, final: true } : { text: "", nextOffset: from, inKey, keyTail, final: true }));
|
|
598
495
|
}
|
|
599
496
|
const final = !live && window.eof;
|
|
600
|
-
// A key block split across reads stays hidden: the cursor carries whether the last read ended inside one.
|
|
601
497
|
const tailRaw = url.searchParams.get("ktail") ?? "";
|
|
602
498
|
const keys = { inKey: url.searchParams.get("inkey") === "1", tail: validKeyTail(tailRaw) ? tailRaw : "" };
|
|
603
499
|
if (records) {
|
|
604
|
-
// Command text and output only under this run's own captured answer, never the file's `open` record (v136).
|
|
605
500
|
const commands = runLiveCommands(store, found.id);
|
|
606
501
|
const shown = liveWindowRecords(window, commands, keys);
|
|
607
502
|
return respond(response, 200, "application/json", JSON.stringify({ records: shown, nextOffset: window.nextOffset, gen: window.gen, inKey: keys.inKey, keyTail: keys.tail ?? "", final, ...notesOf() }));
|
|
608
503
|
}
|
|
609
|
-
// The plain words, whatever the file's format; the offset moves by the bytes read even when nothing shows.
|
|
610
504
|
const lines = liveWindowLines(window, runLiveCommands(store, found.id), keys);
|
|
611
505
|
return respond(response, 200, "application/json", JSON.stringify({ text: lines.length === 0 ? "" : `${lines.join("\n")}\n`, nextOffset: window.nextOffset, gen: window.gen, inKey: keys.inKey, keyTail: keys.tail ?? "", final }));
|
|
612
506
|
}
|
|
613
|
-
// One result page (2026-10-02): a builder's finished result opens on
|
|
614
|
-
// its task's result page, titled with the task. The raw run record
|
|
615
|
-
// waits there under Details, and here with ?record=1.
|
|
616
507
|
if (url.searchParams.get("record") === null && !running && found.role === "builder" && (found.outcome === "built" || found.outcome === "no-change") &&
|
|
617
508
|
completedRowFor(taskId, null)?.runId === found.id) {
|
|
618
509
|
const tab = parseResultTab(url.searchParams.get("tab"));
|
|
619
510
|
return redirect(response, `${reviewHref(taskId, found.id)}${tab === "summary" ? "" : `&tab=${tab}`}`);
|
|
620
511
|
}
|
|
621
|
-
// A build that failed or stopped opens on its own result page too: its changes, its checks and what went wrong.
|
|
622
512
|
if (url.searchParams.get("record") === null && !running && (found.role === "builder" || found.role === "scout") && attemptRowFor(taskId, found.id, null) !== null) {
|
|
623
513
|
const tab = parseResultTab(url.searchParams.get("tab"));
|
|
624
514
|
return redirect(response, `${reviewHref(taskId, found.id)}${tab === "summary" ? "" : `&tab=${tab}`}`);
|
|
625
515
|
}
|
|
626
|
-
// Pollers exist only for a LIVE run — an orphaned null-outcome run
|
|
627
|
-
// would otherwise be refetched forever (finding 15). The nonce is
|
|
628
|
-
// sendScreen's business now.
|
|
629
516
|
const artifacts = store.artifactsFor(found.id);
|
|
630
517
|
return sendScreen(response, 200, runPage(chromeFor(project, "runs", runListPane(project, found.id)), found, taskId, artifacts, terminalDiffView(artifacts, evidenceRoot), store.notesForRun(found.id), who.via === "cookie" ? who.session.csrf : "", store.liveDiffComments(found.id).filter(isRevisionFeedback), (() => {
|
|
631
518
|
const publication = store.publicationForRun(found.id);
|
|
@@ -636,18 +523,12 @@ export function createTasksHandlers(runtime) {
|
|
|
636
523
|
? undefined
|
|
637
524
|
: regionScript("run-facts", "facts") +
|
|
638
525
|
(options.localRunner === undefined ? "" : regionScript("run-peek", "peek")) +
|
|
639
|
-
(options.localRunner === undefined ? "" : transcriptScript()), options.localRunner !== undefined, running,
|
|
640
|
-
// Editor links (arc 6): three statements align or nothing renders —
|
|
641
|
-
// the deployment capability, THIS machine's runner owning the run,
|
|
642
|
-
// and the session's own device-side yes.
|
|
643
|
-
options.editorLinks !== undefined &&
|
|
526
|
+
(options.localRunner === undefined ? "" : transcriptScript()), options.localRunner !== undefined, running, options.editorLinks !== undefined &&
|
|
644
527
|
options.localRunner !== undefined &&
|
|
645
528
|
found.runner === options.localRunner &&
|
|
646
529
|
who.via === "cookie" &&
|
|
647
530
|
who.session.editorLinks === true &&
|
|
648
|
-
// A reviewer run (v29) never had a checkout — no files to open.
|
|
649
531
|
found.worktree !== null &&
|
|
650
|
-
// Idle cleanup removes the folder and a later run makes it again: no link to a folder that isn't there.
|
|
651
532
|
existsSync(found.worktree)
|
|
652
533
|
? { worktree: found.worktree }
|
|
653
534
|
: null, options.editorLinks !== undefined &&
|
|
@@ -655,9 +536,7 @@ export function createTasksHandlers(runtime) {
|
|
|
655
536
|
found.runner === options.localRunner &&
|
|
656
537
|
who.via === "cookie"
|
|
657
538
|
? { on: who.session.editorLinks === true }
|
|
658
|
-
: null, url.searchParams.get("noted") !== null, structuredHandoffView(artifacts, evidenceRoot), proofBundleView(store, found, artifacts, evidenceRoot), store.runRoute(found.id), store.publicationForRun(found.id), reviewFactsFor(found.id),
|
|
659
|
-
// The shared result presentation (package 3) for a finished result.
|
|
660
|
-
!running && (found.outcome === "built" || found.outcome === "no-change")
|
|
539
|
+
: null, url.searchParams.get("noted") !== null, structuredHandoffView(artifacts, evidenceRoot), proofBundleView(store, found, artifacts, evidenceRoot), store.runRoute(found.id), store.publicationForRun(found.id), reviewFactsFor(found.id), !running && (found.outcome === "built" || found.outcome === "no-change")
|
|
661
540
|
? { detail: resultDetailOf(found, who, now), tab: parseResultTab(url.searchParams.get("tab")), user: who.name, requestToken: randomBytes(16).toString("hex") }
|
|
662
541
|
: null, store.getScope(taskId)?.digest ?? null));
|
|
663
542
|
}
|
|
@@ -668,7 +547,6 @@ export function createTasksHandlers(runtime) {
|
|
|
668
547
|
return noPage(who, response);
|
|
669
548
|
return runEvidence(response, Number(runArtifact[1]), Number(runArtifact[2]));
|
|
670
549
|
}
|
|
671
|
-
// v115: routines became scheduled flows; an old link to the list or to one routine lands on the flows page.
|
|
672
550
|
async function showRoutines(ctx) {
|
|
673
551
|
return redirect(ctx.response, "/flows");
|
|
674
552
|
}
|
|
@@ -707,8 +585,6 @@ export function createTasksHandlers(runtime) {
|
|
|
707
585
|
const permitted = (repo) => visible(repo) && codingProjectAllowed(repo);
|
|
708
586
|
const starting = verb === 'start';
|
|
709
587
|
const sessionId = starting || verb === 'unknown' ? null : /^\/code\/([a-f0-9]{32})/.exec(url.pathname)[1];
|
|
710
|
-
// Sprint 8: a coding session is Codex taking turns: the organisation policy decides whether it may (provider,
|
|
711
|
-
// model, and a ceiling Codex can't run under), when it starts and on every action that makes it take another turn.
|
|
712
588
|
const turnAction = ['send', 'resume', 'recover', 'continue', 'answer'].includes(verb);
|
|
713
589
|
if (starting || turnAction) {
|
|
714
590
|
const stopped = store.sessionPolicyRefusal('codex', starting ? body.get('model')?.trim() || null : null, 'coding sessions');
|
|
@@ -761,7 +637,6 @@ export function createTasksHandlers(runtime) {
|
|
|
761
637
|
runtime.coding.answer(id, actor, token, decision, answers);
|
|
762
638
|
}
|
|
763
639
|
}
|
|
764
|
-
// Authorization is checked again after asynchronous startup/transport work.
|
|
765
640
|
if (!codingActorAllowed(actor))
|
|
766
641
|
return fail(403, 'Your access changed. Sign in again.', 'unknown', id);
|
|
767
642
|
return wantsJson ? respond(response, 200, 'application/json', JSON.stringify({ ok: true, id })) : redirect(response, `/code/${id}`);
|
|
@@ -787,8 +662,6 @@ export function createTasksHandlers(runtime) {
|
|
|
787
662
|
if (project === undefined) {
|
|
788
663
|
return refuse(response, who, 403, "that project is outside what this server was configured to show");
|
|
789
664
|
}
|
|
790
|
-
// Stale-tab guard: a form rendered under one open project must not
|
|
791
|
-
// create into a different one switched-to since (finding 6).
|
|
792
665
|
if (who.via === "cookie") {
|
|
793
666
|
const seen = body.get("projectRevision");
|
|
794
667
|
if (seen !== null && seen !== String(who.session.projectRevision)) {
|
|
@@ -796,38 +669,21 @@ export function createTasksHandlers(runtime) {
|
|
|
796
669
|
}
|
|
797
670
|
}
|
|
798
671
|
const id = (body.get("id") ?? "").trim();
|
|
799
|
-
// The New task box stops at a title's length (render-new-task.ts): the title is all the planner reads of a no-goal
|
|
800
|
-
// filing. A direct POST longer than that is cut at a whole word, with an ellipsis (task-text.ts titleWithin), as a
|
|
801
|
-
// belt; a refusal keeps the person's own words (the draft below).
|
|
802
672
|
const typed = body.get("title") ?? "";
|
|
803
673
|
const title = titleWithin(typed);
|
|
804
|
-
// The EFFECTIVE placement (repo onboarding, findings 15/35): the
|
|
805
|
-
// trimmed, nonempty posted repo, else the open project — an empty
|
|
806
|
-
// input falls through correctly. In root mode the effective path is
|
|
807
|
-
// proved by authorizedProject EXACTLY as typed-then-canonicalized,
|
|
808
|
-
// and [canonical] is the admitted list — a fresh clone under a root
|
|
809
|
-
// must be able to receive its first task without waiting to appear
|
|
810
|
-
// in any table.
|
|
811
674
|
const repoGiven = (body.get("repo") ?? "").trim();
|
|
812
675
|
const effective = repoGiven !== "" ? repoGiven : (project ?? "");
|
|
813
676
|
if (restricted() && !visible(effective === "" ? null : effective))
|
|
814
677
|
return refuse(response, who, 403, "That project is outside your access.", "/projects");
|
|
815
|
-
// A scoped console refuses an EMPTY placement server-side (verification
|
|
816
|
-
// finding 1): the form's `required` is a courtesy, not the guard — a
|
|
817
|
-
// direct POST with no project open must not mint an unplaced task
|
|
818
|
-
// under a ceiling. Unscoped mode keeps its historic unplaced filings.
|
|
819
|
-
// A refusal from here on is the add page again with the person's own words (the old task list kept them too).
|
|
820
678
|
const draft = { title: typed, goal: body.get("goal") ?? "", not: body.get("not") ?? "", touches: body.get("touches") ?? "", acceptance: body.get("acceptance") ?? "", values: body.sent };
|
|
821
679
|
if (!unscopedMode && effective === "") {
|
|
822
680
|
return newTaskScreen(ctx, 400, "name a repository — no project is open, so the task must say where it belongs", draft);
|
|
823
681
|
}
|
|
824
682
|
let repo = effective;
|
|
825
683
|
let admitted = unscopedMode ? null : admissionList() ?? [];
|
|
826
|
-
// What this filing is decided on: re-checked inside the write below, after every await (project-identity.ts).
|
|
827
684
|
const decidedOn = identities.generation();
|
|
828
685
|
const rootMode = !unscopedMode && ceiling.roots.length > 0;
|
|
829
686
|
if (rootMode && effective !== "") {
|
|
830
|
-
// Resolved off the console's thread (project-identity.ts), then proved against the ceiling as that identity.
|
|
831
687
|
const resolved = await identities.resolveNow(effective);
|
|
832
688
|
if (resolved === "no-answer")
|
|
833
689
|
return newTaskScreen(ctx, 503, `${effective} didn't answer — its folder may be on a drive that's disconnected, or waiting on macOS; try again in a moment`, draft);
|
|
@@ -853,9 +709,7 @@ export function createTasksHandlers(runtime) {
|
|
|
853
709
|
if (qualityMode !== null && !isQualityMode(qualityMode)) {
|
|
854
710
|
return refuse(response, who, 400, "quality must be Default or Strict / release", "/tasks/new");
|
|
855
711
|
}
|
|
856
|
-
// One filing door for every surface (Codex adoption review, finding 7).
|
|
857
712
|
const after = (body.get("after") ?? "").trim();
|
|
858
|
-
// From an issue or pull request (github-import.ts): read and quoted first; filing is the second press, on what was read.
|
|
859
713
|
const fromLink = (body.get("from") ?? "").trim();
|
|
860
714
|
if (fromLink !== "") {
|
|
861
715
|
if (who.via !== "cookie" || repo === "")
|
|
@@ -871,8 +725,6 @@ export function createTasksHandlers(runtime) {
|
|
|
871
725
|
return newTaskScreen(ctx, filed.reason === "head-moved" ? 409 : 400, filed.message, draft);
|
|
872
726
|
return redirect(response, taskHref(filed.taskId));
|
|
873
727
|
}
|
|
874
|
-
// Small work a person starts themselves: their words become the exact terms, and Build is their yes (fast-start.ts).
|
|
875
|
-
// Anything else, or any doubt, is the ordinary filing below. `plain` is "Plan it first" from that form.
|
|
876
728
|
if (who.via === "cookie" && body.get("plain") !== "1" && repo !== "" && goal === "" && notThis === "" && touchesGiven.length === 0 && !scout && id === "" && after === ""
|
|
877
729
|
&& (qualityMode === null || qualityMode === "default") && (permissionMode === null || permissionMode === "auto")) {
|
|
878
730
|
const fast = await prepareFastStart(store, { actor: who.name, repo, title: typed.trim(), via: "console", ...(permissionMode === null ? {} : { permissionMode }), password: fastPasswordFacts(who) }, now);
|
|
@@ -881,8 +733,6 @@ export function createTasksHandlers(runtime) {
|
|
|
881
733
|
}
|
|
882
734
|
let chainProblem = null;
|
|
883
735
|
const made = store.transact(() => {
|
|
884
|
-
// A project folder's identity changed while this request waited (a root or link now leads elsewhere): what was
|
|
885
|
-
// proved above may no longer hold, so nothing is filed on it.
|
|
886
736
|
if (identities.generation() !== decidedOn || (rootMode && repo !== "" && !visible(repo)))
|
|
887
737
|
return null;
|
|
888
738
|
const filed = fileTaskProposal(store, {
|
|
@@ -910,8 +760,6 @@ export function createTasksHandlers(runtime) {
|
|
|
910
760
|
if (!chained.ok)
|
|
911
761
|
chainProblem = chained.reason;
|
|
912
762
|
}
|
|
913
|
-
// Missing dependencies leave a reviewable, inert task. They must
|
|
914
|
-
// never be silently dropped before automatic approval starts work.
|
|
915
763
|
if (filed.ok && chainProblem === null && who.via === "cookie")
|
|
916
764
|
applyModeToNewFiling(store, filed.id, who.name, now);
|
|
917
765
|
return filed;
|
|
@@ -924,8 +772,6 @@ export function createTasksHandlers(runtime) {
|
|
|
924
772
|
const actionContext = requestContext.getStore();
|
|
925
773
|
if (actionContext !== undefined)
|
|
926
774
|
actionContext.createdTask = made.id;
|
|
927
|
-
// A proved root-mode placement joins the project table (finding 15):
|
|
928
|
-
// the new task's home is openable and admissible from now on.
|
|
929
775
|
if (rootMode && repo !== "")
|
|
930
776
|
store.upsertProject(repo, projectName(repo), now);
|
|
931
777
|
if (chainProblem !== null)
|
|
@@ -939,9 +785,6 @@ export function createTasksHandlers(runtime) {
|
|
|
939
785
|
if (project === undefined) {
|
|
940
786
|
return refuse(response, who, 403, "that project is outside what this server was configured to show");
|
|
941
787
|
}
|
|
942
|
-
// The note is a global runner label, not project-scoped work: the
|
|
943
|
-
// fleet screen (project-less) posts it too, so the null-project gate
|
|
944
|
-
// applies only to moves, which their task-level check re-proves.
|
|
945
788
|
const worker = (body.get("runner") ?? "").trim();
|
|
946
789
|
const note = (body.get("note") ?? "").trim();
|
|
947
790
|
if (note.length > 200 || hasForbiddenControls(note)) {
|
|
@@ -965,8 +808,6 @@ export function createTasksHandlers(runtime) {
|
|
|
965
808
|
return refuse(response, who, 409, "the open project changed since this form was rendered — reload and try again", QUEUE_VIEW);
|
|
966
809
|
}
|
|
967
810
|
}
|
|
968
|
-
// A drag posts in place (fetch) when it can; the page re-renders its
|
|
969
|
-
// own fragment on success. A plain form still works with no script.
|
|
970
811
|
const inPlace = body.get("respond") === "fragment";
|
|
971
812
|
const fromFleet = who.via === "cookie" && body.get("projectRevision") === null;
|
|
972
813
|
const respondMove = (status, message) => {
|
|
@@ -988,8 +829,6 @@ export function createTasksHandlers(runtime) {
|
|
|
988
829
|
const toRunner = columnGiven === "" || columnGiven === "anyone" ? null : columnGiven;
|
|
989
830
|
const beforeGiven = (body.get("before") ?? "").trim();
|
|
990
831
|
const revisionGiven = Number(body.get("queueRevision") ?? "");
|
|
991
|
-
// The queue's own screen enforces the open project; the fleet screen
|
|
992
|
-
// is cross-project, so the ceiling is the only wall it needs.
|
|
993
832
|
const belongs = (id) => {
|
|
994
833
|
const ref = store.lookupRef(id);
|
|
995
834
|
return ref !== null && visible(ref.repo) && (fromFleet || project === null || ref.repo === null || ref.repo === project);
|
|
@@ -997,12 +836,6 @@ export function createTasksHandlers(runtime) {
|
|
|
997
836
|
if (!belongs(taskId) || (beforeGiven !== "" && beforeGiven !== QUEUE_FRONT && !belongs(beforeGiven))) {
|
|
998
837
|
return respondMove(404, "that task is not in this queue");
|
|
999
838
|
}
|
|
1000
|
-
// The no-script "move to the front" button cannot name the front: the
|
|
1001
|
-
// front of a task's partition is decided by the store's exact repo AND
|
|
1002
|
-
// assignment, and the page's snapshot is bounded — so the sentinel is
|
|
1003
|
-
// resolved HERE, against a fresh snapshot, into a real task id (slice
|
|
1004
|
-
// 1b, fix 1). It is honored only within the task's own column; a
|
|
1005
|
-
// cross-column front is not provable from a bounded snapshot.
|
|
1006
839
|
let beforeTaskId = beforeGiven === "" ? null : beforeGiven;
|
|
1007
840
|
if (beforeGiven === QUEUE_FRONT) {
|
|
1008
841
|
const ref = store.lookupRef(taskId);
|
|
@@ -1014,11 +847,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1014
847
|
const now = clock();
|
|
1015
848
|
const snapshot = store.queueScoped(ref.repo, now);
|
|
1016
849
|
const self = snapshot.find(one => one.id === taskId);
|
|
1017
|
-
// A claim can land after the form rendered WITHOUT
|
|
1018
|
-
// bumping queueRevision, so the snapshot — not the form — decides
|
|
1019
|
-
// whether the card is still free. A taken or vanished card is the
|
|
1020
|
-
// typed refusal, never a silent no-op that would skip moveTask()'s
|
|
1021
|
-
// own claimed recheck.
|
|
1022
850
|
if (self === undefined)
|
|
1023
851
|
return respondMove(409, moveReason("unknown-task"));
|
|
1024
852
|
if (self.taken)
|
|
@@ -1028,9 +856,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1028
856
|
if (front === undefined)
|
|
1029
857
|
return respondMove(409, moveReason("unknown-task"));
|
|
1030
858
|
if (front.id === taskId) {
|
|
1031
|
-
// Already the front: a no-op, but only against the revision the
|
|
1032
|
-
// form was rendered with — this branch never reaches moveTask()'s
|
|
1033
|
-
// CAS, so the check is made here.
|
|
1034
859
|
if (!Number.isSafeInteger(revisionGiven) || revisionGiven !== store.queueRevision()) {
|
|
1035
860
|
return respondMove(409, moveReason("stale"));
|
|
1036
861
|
}
|
|
@@ -1071,10 +896,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1071
896
|
}
|
|
1072
897
|
const choice = body.get("choice") ?? "";
|
|
1073
898
|
const chosen = decision.options.find(option => option.id === choice);
|
|
1074
|
-
// Irreversible options never ride one accidental tap: the form arms
|
|
1075
|
-
// them behind an explicit confirmation field, and the server checks —
|
|
1076
|
-
// the client rendering is convenience, this is the rule.
|
|
1077
|
-
// The question page's own form hears a refusal in its box, with nothing changed; /next keeps its refusal page.
|
|
1078
899
|
const inPlace = requestedReturn !== "next";
|
|
1079
900
|
const pageBack = requestedReturn === null ? null : decisionBack;
|
|
1080
901
|
if (chosen !== undefined && !chosen.reversible && body.get("confirm") !== "yes") {
|
|
@@ -1107,8 +928,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1107
928
|
if (act === null)
|
|
1108
929
|
return noPage(who, response);
|
|
1109
930
|
const body = readForm(posted, CONSOLE_FORMS.recheckStopped);
|
|
1110
|
-
// Check again: Toolroll looks at this computer's processes for the build once more (stop-proof.ts) and settles it
|
|
1111
|
-
// when none of them is the build's. Nobody vouches that a build stopped, so there is nothing to confirm here.
|
|
1112
931
|
const back = taskHref(act.taskId);
|
|
1113
932
|
const ref = store.lookupRef(act.taskId);
|
|
1114
933
|
if (ref === null || !visible(ref.repo))
|
|
@@ -1141,8 +960,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1141
960
|
if (act === null)
|
|
1142
961
|
return noPage(who, response);
|
|
1143
962
|
const body = readForm(posted, CONSOLE_FORMS.merge);
|
|
1144
|
-
// Merging is a person's act behind their password, typed again: a browser session, an approver, the exact
|
|
1145
|
-
// result's pull request. The flow re-reads GitHub before merging and records who merged in the ledger.
|
|
1146
963
|
if (store.isDemo())
|
|
1147
964
|
return taskScreen(response, who, act.taskId, "The demo merges nothing.", 403);
|
|
1148
965
|
const ref = store.lookupRef(act.taskId);
|
|
@@ -1159,7 +976,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1159
976
|
return taskScreen(response, who, act.taskId, merged.message, merged.reason === "password" ? 403 : 409);
|
|
1160
977
|
return redirect(response, `${taskHref(act.taskId)}#merge`);
|
|
1161
978
|
}
|
|
1162
|
-
/** A task act bound to its verb: taskMutation owns each verb's checks. */
|
|
1163
979
|
const taskAct = (verb) => async (ctx) => {
|
|
1164
980
|
const { url, who, response, now, posted } = ctx;
|
|
1165
981
|
const act = matchTaskPath(url.pathname, `/${verb}$`);
|
|
@@ -1167,8 +983,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1167
983
|
return noPage(who, response);
|
|
1168
984
|
return taskMutation(response, who, act.taskId, verb, posted, now, ctx.request);
|
|
1169
985
|
};
|
|
1170
|
-
// Cockpit E: Show in Finder — the checkout proved again right now (live, this machine's runner, inside the pool),
|
|
1171
|
-
// then Finder asked to reveal it with a fixed argv. Nothing runs in it; a Mac only.
|
|
1172
986
|
async function runReveal(ctx) {
|
|
1173
987
|
const { url, who, response, now, posted } = ctx;
|
|
1174
988
|
const asked = /^\/r\/([0-9]{1,15})\/reveal$/.exec(url.pathname);
|
|
@@ -1195,10 +1009,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1195
1009
|
if (noted === null)
|
|
1196
1010
|
return noPage(who, response);
|
|
1197
1011
|
const body = readForm(posted, CONSOLE_FORMS.runNote);
|
|
1198
|
-
// An operator's verdict beside the machine's record (M6): immutable,
|
|
1199
|
-
// bounded by the same validator as decision notes, ceiling-checked
|
|
1200
|
-
// like every run resource. Ordinary authenticated mutation — no
|
|
1201
|
-
// nonce, because nothing here approves anything.
|
|
1202
1012
|
const id = Number(noted[1]);
|
|
1203
1013
|
const found = store.getRun(id);
|
|
1204
1014
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1216,31 +1026,17 @@ export function createTasksHandlers(runtime) {
|
|
|
1216
1026
|
if (diffComment === null)
|
|
1217
1027
|
return noPage(who, response);
|
|
1218
1028
|
const body = readForm(posted, CONSOLE_FORMS.diffComment);
|
|
1219
|
-
// A review comment on the IMMUTABLE terminal diff (M6.8): bound to
|
|
1220
|
-
// the exact artifact and its hash. Ordinary authenticated mutation —
|
|
1221
|
-
// the nonce belongs to the approval screen that later restates the
|
|
1222
|
-
// batch, never to the comment box.
|
|
1223
1029
|
const id = Number(diffComment[1]);
|
|
1224
1030
|
const found = store.getRun(id);
|
|
1225
1031
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
1226
1032
|
return refuse(response, who, 404, "no such run");
|
|
1227
1033
|
}
|
|
1228
|
-
// Where the reader came from (package 3): the cockpit's deep link,
|
|
1229
|
-
// the chat's result view, or the run page — validated to those exact
|
|
1230
|
-
// shapes. A refusal sends them back THERE, where the browser has kept
|
|
1231
|
-
// their draft, so a failed submission is recoverable in place.
|
|
1232
1034
|
const returnTo = resultReturnTarget(body.get("return"), id, runTasks(found.taskRef));
|
|
1233
1035
|
const selectedTab = parseResultTab(body.get("tab"));
|
|
1234
|
-
// A task page's Result tab keeps the result's own view in `section=` (its `tab` is the task's).
|
|
1235
1036
|
const viewParam = returnTo.startsWith("/t/") ? "section" : "tab";
|
|
1236
1037
|
const back = selectedTab === "summary" ? returnTo
|
|
1237
1038
|
: `${returnTo.replace(/§ion=(?:summary|changes|checks)$/, "")}${returnTo.includes("?") ? "&" : "?"}${viewParam}=${selectedTab}`;
|
|
1238
1039
|
if (body.get("intent") === "drop-image") {
|
|
1239
|
-
// A saved note whose screenshot is gone or changed would block every revision that seals it. Its words stay:
|
|
1240
|
-
// the note is superseded by an exact imageless copy, and the original remains in history.
|
|
1241
|
-
// Who: a signed-in browser approver admitted to this run's project (checked above) — the same authority that
|
|
1242
|
-
// seals any saved note into a revision. What: only a screenshot that is unusable right now, re-proved inside
|
|
1243
|
-
// dropFeedbackImage's transaction, and recorded in the ledger under this person.
|
|
1244
1040
|
if (who.via !== "cookie" || who.role !== "approver")
|
|
1245
1041
|
return refuse(response, who, 403, "Only a signed-in approver can change saved feedback.", back);
|
|
1246
1042
|
const comment = Number(body.get("comment") ?? "");
|
|
@@ -1261,14 +1057,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1261
1057
|
const result = requestResultChanges(store, evidenceRoot, {
|
|
1262
1058
|
run: id, batch: body.get("batch"), source: body.get("source"), actor: who.name,
|
|
1263
1059
|
repos: admissionList(), includeUnplaced: visible(null), allowMode: who.via === "cookie",
|
|
1264
|
-
// A browser session is a person's proof; a bearer credential is a machine's.
|
|
1265
1060
|
origin: who.via === "cookie" ? "person" : "machine",
|
|
1266
1061
|
note: body.get("note") ?? "", path: body.get("path") ?? "", line: body.get("line") ?? "", request: body.get("request"), image,
|
|
1267
1062
|
}, now);
|
|
1268
1063
|
if (!result.ok) {
|
|
1269
1064
|
const request = body.get("request") ?? "";
|
|
1270
|
-
// The queue's link can stop resolving when a newer attempt finishes. The exact
|
|
1271
|
-
// run record still hosts this account/run's recoverable feedback draft.
|
|
1272
1065
|
const retryBase = image === null ? back : `/r/${id}?record=1`;
|
|
1273
1066
|
const retryBack = /^[a-f0-9]{32}$/.test(request) ? `${retryBase}${retryBase.includes("?") ? "&" : "?"}conflict=${request}#request-changes` : retryBase;
|
|
1274
1067
|
return refuse(response, who, result.status, result.message, retryBack);
|
|
@@ -1279,9 +1072,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1279
1072
|
if (terminal === undefined) {
|
|
1280
1073
|
return refuse(response, who, 400, "this run has no terminal diff to comment on", back);
|
|
1281
1074
|
}
|
|
1282
|
-
// The bytes must VERIFY before words attach to them (audit IV-10):
|
|
1283
|
-
// "a comment on the exact reviewed bytes" is a lie if the bytes are
|
|
1284
|
-
// gone or no longer hash to their record.
|
|
1285
1075
|
const proven = readVerifiedArtifact(evidenceRoot, terminal);
|
|
1286
1076
|
if (!proven.ok) {
|
|
1287
1077
|
return refuse(response, who, 409, `the terminal diff no longer verifies (${proven.problem}) — nothing to comment on`, back);
|
|
@@ -1298,15 +1088,9 @@ export function createTasksHandlers(runtime) {
|
|
|
1298
1088
|
if (line !== null && (!Number.isInteger(line) || line < 1 || line > 1_000_000)) {
|
|
1299
1089
|
return refuse(response, who, 400, "Enter a whole line number from 1 to 1,000,000, or leave it blank.", back);
|
|
1300
1090
|
}
|
|
1301
|
-
// The form's own request token (package 3) is the dedupe key: a
|
|
1302
|
-
// replayed or double submission finds its note already recorded and
|
|
1303
|
-
// lands on the same receipt instead of a second note. The token is
|
|
1304
|
-
// bound to the account, so nobody else's replay can consume it.
|
|
1305
1091
|
const request = body.get("request");
|
|
1306
1092
|
const sourceKey = commentSourceKey(who.name, request);
|
|
1307
1093
|
const path = rawPath === "" ? null : rawPath;
|
|
1308
|
-
// Freshness, custody and the insert in one write transaction: a newer attempt finishing in between can't leave a
|
|
1309
|
-
// stale screenshot attached (check and write together).
|
|
1310
1094
|
const saved = store.transact(() => {
|
|
1311
1095
|
const imageProblem = feedbackImageProblem(store, evidenceRoot, id, image);
|
|
1312
1096
|
if (imageProblem !== null)
|
|
@@ -1317,13 +1101,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1317
1101
|
return refuse(response, who, 409, saved.problem, `/r/${id}?record=1#request-changes`);
|
|
1318
1102
|
const inserted = saved.inserted;
|
|
1319
1103
|
if (inserted === null && sourceKey !== undefined) {
|
|
1320
|
-
// The token was used before (repair 2026-09-14, finding 1). A
|
|
1321
|
-
// request identity is IMMUTABLE: it names exactly one note on
|
|
1322
|
-
// exactly one result. The unchanged retry — same run, same file,
|
|
1323
|
-
// line and words — lands on its original receipt; any other reuse
|
|
1324
|
-
// is refused, and the refusal's way back carries `conflict=<token>`
|
|
1325
|
-
// so the browser mints a fresh identity for the words it still
|
|
1326
|
-
// holds. Nothing typed is lost either way.
|
|
1327
1104
|
const earlier = store.diffCommentBySourceKey(sourceKey);
|
|
1328
1105
|
const conflictBack = `${back}${back.includes("?") ? "&" : "?"}conflict=${request}#request-changes`;
|
|
1329
1106
|
if (earlier === null || earlier.run !== id) {
|
|
@@ -1333,21 +1110,12 @@ export function createTasksHandlers(runtime) {
|
|
|
1333
1110
|
return refuse(response, who, 409, `this request identity already recorded a different note on this result (${earlier.path === null ? "no file" : `${earlier.path}${earlier.line === null ? "" : `:${earlier.line}`}`}: "${oneLineOf(earlier.note, 80)}") — go back; your edited words are kept as a new note, and the form will carry a new identity`, conflictBack);
|
|
1334
1111
|
}
|
|
1335
1112
|
}
|
|
1336
|
-
// Land back AT the request-changes form with the note field ready —
|
|
1337
|
-
// writing five notes in a row must cost five keystrokes of
|
|
1338
|
-
// navigation, not five scrolls (arc 6, finding 5/6). The receipt
|
|
1339
|
-
// names the request token, so the browser clears exactly the draft
|
|
1340
|
-
// that landed and no other.
|
|
1341
1113
|
const receipt = sourceKey === undefined ? "1" : request;
|
|
1342
1114
|
return redirect(response, `${back}${back.includes("?") ? "&" : "?"}noted=${receipt}#request-changes`);
|
|
1343
1115
|
}
|
|
1344
1116
|
async function sessionEditorLinks(ctx) {
|
|
1345
1117
|
const { who, response, posted } = ctx;
|
|
1346
1118
|
const body = readForm(posted, CONSOLE_FORMS.editorLinks);
|
|
1347
|
-
// The session half of the editor-link activation (arc 6, finding 1):
|
|
1348
|
-
// only the person at the browser can say "this device holds the
|
|
1349
|
-
// worktrees". Per-session, dies with the session, grants nothing —
|
|
1350
|
-
// it only lets already-authorized pages RENDER vscode links.
|
|
1351
1119
|
if (who.via !== "cookie")
|
|
1352
1120
|
return refuse(response, who, 403, "editor links are a browser session's choice");
|
|
1353
1121
|
if (options.editorLinks === undefined)
|
|
@@ -1362,10 +1130,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1362
1130
|
if (revise === null)
|
|
1363
1131
|
return noPage(who, response);
|
|
1364
1132
|
const body = readForm(posted, CONSOLE_FORMS.revise);
|
|
1365
|
-
// Seal the live comment batch into ONE unapproved revision task with
|
|
1366
|
-
// an immutable brief (M6.8). Deterministic — no model reads anything
|
|
1367
|
-
// here — and every revision takes its own approval: comments can
|
|
1368
|
-
// semantically widen work, and no path check can prove they did not.
|
|
1369
1133
|
const id = Number(revise[1]);
|
|
1370
1134
|
const found = store.getRun(id);
|
|
1371
1135
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1381,8 +1145,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1381
1145
|
return refuse(response, who, result.status, result.message, back);
|
|
1382
1146
|
return redirect(response, revisionDestination(result.id, back));
|
|
1383
1147
|
}
|
|
1384
|
-
// Follow-ups on a result: Run checks on its exact commit (a worker runs the
|
|
1385
|
-
// approved command once and seals the log), or file a task to add tests.
|
|
1386
1148
|
const runFollowUp = (op) => async (ctx) => {
|
|
1387
1149
|
const { url, who, response, now, posted } = ctx;
|
|
1388
1150
|
const followUp = /^\/r\/([0-9]{1,15})\//.exec(url.pathname);
|
|
@@ -1393,7 +1155,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1393
1155
|
const found = store.getRun(id);
|
|
1394
1156
|
if (found === null || !visible(taskRepoOf(found.taskRef)))
|
|
1395
1157
|
return refuse(response, who, 404, "no such run");
|
|
1396
|
-
// The task page that offered Run checks in place is a return target too: this run's own task, or its family's root.
|
|
1397
1158
|
const back = resultReturnTarget(body.get("return"), id, runTasks(found.taskRef));
|
|
1398
1159
|
if (who.via !== "cookie")
|
|
1399
1160
|
return refuse(response, who, 403, "Sign in with a browser session to do this.", back);
|
|
@@ -1406,7 +1167,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1406
1167
|
const asked = requestFollowUpChecks(store, { runId: id, level, actor: who.name }, now);
|
|
1407
1168
|
if (!asked.ok)
|
|
1408
1169
|
return refuse(response, who, 409, asked.message, back);
|
|
1409
|
-
// Back where it was asked: the task page's status row says the checks are running; a result page shows them under #follow-ups.
|
|
1410
1170
|
return redirect(response, back.startsWith("/t/") ? back : `${back.split("#")[0]}#follow-ups`);
|
|
1411
1171
|
}
|
|
1412
1172
|
const filed = fileAddTestsTask(store, evidenceRoot, { runId: id, actor: who.name, filedVia: "console", ...(admissionList() === null ? {} : { admittedRepos: admissionList() }) }, now);
|
|
@@ -1419,10 +1179,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1419
1179
|
const draftRepair = /^\/r\/([0-9]{1,15})\/draft-repair$/.exec(url.pathname);
|
|
1420
1180
|
if (draftRepair === null)
|
|
1421
1181
|
return noPage(who, response);
|
|
1422
|
-
// CI repair, suggestion-first (M8.18): a red episode never spawns an
|
|
1423
|
-
// agent by itself — it EARNS a button, and the button creates one
|
|
1424
|
-
// unapproved task through the same revision machinery as review
|
|
1425
|
-
// comments. One draft per task/PR, ever: the merge blocker records it.
|
|
1426
1182
|
const id = Number(draftRepair[1]);
|
|
1427
1183
|
const found = store.getRun(id);
|
|
1428
1184
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1437,9 +1193,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1437
1193
|
}
|
|
1438
1194
|
const sourceTaskId = store.externalIdFor(found.taskRef) ?? "?";
|
|
1439
1195
|
const sourceScope = store.getScope(sourceTaskId);
|
|
1440
|
-
// The observed episode, not the click: the brief binds the head the
|
|
1441
|
-
// failure was SEEN on and when (audit C-2) — a PR that advanced since
|
|
1442
|
-
// is a different failure, and the click time is not an observation.
|
|
1443
1196
|
const episode = store.latestOpenCiEpisode(publication.githubRepo, publication.prNumber);
|
|
1444
1197
|
const brief = {
|
|
1445
1198
|
schema: 1,
|
|
@@ -1457,11 +1210,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1457
1210
|
const briefBytes = Buffer.from(JSON.stringify(brief, null, 2), "utf8");
|
|
1458
1211
|
const briefName = `ci-repair-brief-${randomBytes(6).toString("hex")}.json`;
|
|
1459
1212
|
const key = writeEvidenceFile(evidenceRoot, id, briefName, briefBytes);
|
|
1460
|
-
// The SAME revision boundary the annotation road and the criterion
|
|
1461
|
-
// repair use (contract handoff task 2): the inherited terms come from
|
|
1462
|
-
// the source rows inside the seal; the scope read above only names
|
|
1463
|
-
// the digest this draft was composed against.
|
|
1464
|
-
// One draft per task/PR, ever: the PR's merge blocker names it, lifted or not, and is written in the seal's transaction.
|
|
1465
1213
|
const sealed = store.transact(() => {
|
|
1466
1214
|
const prior = store.raw().prepare("SELECT task_id FROM merge_blocker WHERE publication = ? AND task_id IS NOT NULL ORDER BY rowid LIMIT 1").get(publication.id);
|
|
1467
1215
|
if (prior !== undefined)
|
|
@@ -1477,9 +1225,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1477
1225
|
commentIds: null,
|
|
1478
1226
|
requestedBy: who.name,
|
|
1479
1227
|
}, now);
|
|
1480
|
-
// The merge blocker rides the SAME breath as the draft (merge grant,
|
|
1481
|
-
// findings 3/12/13): while this repair exists, the source PR merges
|
|
1482
|
-
// NOTHING — sticky until the operator's unblock act or the PR closes.
|
|
1483
1228
|
if (result.ok)
|
|
1484
1229
|
store.createMergeBlocker(publication.id, result.id, now);
|
|
1485
1230
|
return result;
|
|
@@ -1496,11 +1241,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1496
1241
|
return noPage(who, response);
|
|
1497
1242
|
const body = readForm(posted, CONSOLE_FORMS.resolveIncident);
|
|
1498
1243
|
const id = Number(resolve[1]);
|
|
1499
|
-
// The ceiling applies to incident mutation exactly as to every other
|
|
1500
|
-
// resource (v3 review, finding 3): resolve incident → run → task, and
|
|
1501
|
-
// an incident outside this server's scope does not exist here. The
|
|
1502
|
-
// task id is captured BEFORE resolving — afterwards the incident is
|
|
1503
|
-
// no longer open and could not be found again.
|
|
1504
1244
|
const openRow = store.openIncidents().find(one => one.id === id);
|
|
1505
1245
|
const incidentRun = openRow === undefined ? null : store.getRun(openRow.run);
|
|
1506
1246
|
if (openRow !== undefined && incidentRun !== null && !visible(taskRepoOf(incidentRun.taskRef))) {
|
|
@@ -1512,7 +1252,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1512
1252
|
const back = body.get("return") === "inbox" ? "/" : openRow === undefined ? "/" : taskHref(openRow.taskId);
|
|
1513
1253
|
return redirect(response, back);
|
|
1514
1254
|
}
|
|
1515
|
-
/** The compact recent-runs list for the master pane. */
|
|
1516
1255
|
function runListPane(project, currentId) {
|
|
1517
1256
|
const rows = store.listRunsBefore(null, 50, project);
|
|
1518
1257
|
const live = liveRunIds(rows);
|
|
@@ -1521,15 +1260,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1521
1260
|
return html `<h2>Builds</h2>\n${rows.length === 0 ? html `<p class="meta">None yet</p>` : items}`;
|
|
1522
1261
|
}
|
|
1523
1262
|
async function peekFragment(runId, sessionKey, editorMode = false) {
|
|
1524
|
-
// The cache and the in-flight coalescer hold the fragment's bytes (runtime's types); they are markup this made.
|
|
1525
1263
|
const said = (message, final) => peekSay(message, final);
|
|
1526
1264
|
const guarded = peekGuards(runId);
|
|
1527
1265
|
if (!guarded.ok)
|
|
1528
1266
|
return { status: 200, body: said(guarded.message, guarded.final === true) };
|
|
1529
1267
|
const { run, worktree, epoch, entries } = guarded.admit;
|
|
1530
|
-
// The cache and the in-flight coalescer both vary by LINK MODE (arc 6,
|
|
1531
|
-
// finding 3): a linked fragment rendered for one session must never be
|
|
1532
|
-
// served to a session that has not activated links on its device.
|
|
1533
1268
|
const key = `${runId}:${run.baseRevision}:${epoch}:${editorMode ? "links" : "plain"}`;
|
|
1534
1269
|
const cached = peekCache.get(key);
|
|
1535
1270
|
if (cached !== undefined && Date.now() - cached.at <= PEEK_CACHE_TTL_MS) {
|
|
@@ -1539,7 +1274,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1539
1274
|
peekCache.delete(key);
|
|
1540
1275
|
runtime.peekCacheBytes -= cached.bytes;
|
|
1541
1276
|
}
|
|
1542
|
-
// Coalesce per run; bound per session and globally (finding 10).
|
|
1543
1277
|
const flightKey = `${runId}:${editorMode ? "links" : "plain"}`;
|
|
1544
1278
|
const inFlight = peekInFlight.get(flightKey);
|
|
1545
1279
|
if (inFlight !== undefined)
|
|
@@ -1552,9 +1286,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1552
1286
|
peekBySession.set(sessionKey, (peekBySession.get(sessionKey) ?? 0) + 1);
|
|
1553
1287
|
const work = (async () => {
|
|
1554
1288
|
const seen = await observeWorktree(worktree, entries.entries, PEEK_LIMITS);
|
|
1555
|
-
// The fence, proved AGAIN after the walk (findings 16/28): the same
|
|
1556
|
-
// run still open, the same claim, the SAME epoch — or the whole
|
|
1557
|
-
// observation is discarded, never rendered, never cached.
|
|
1558
1289
|
const after = peekGuards(runId);
|
|
1559
1290
|
if (!after.ok || after.admit.epoch !== epoch) {
|
|
1560
1291
|
return peekSay("the checkout changed hands mid-look — nothing is shown");
|
|
@@ -1572,9 +1303,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1572
1303
|
if (changed.length === 0 && deleted.length === 0 && fresh.total === 0) {
|
|
1573
1304
|
parts.push(html `<p class="row">nothing has changed against the starting point yet</p>`);
|
|
1574
1305
|
}
|
|
1575
|
-
// A name is linked ONLY when sanitize provably changed nothing (arc 6,
|
|
1576
|
-
// finding 3): a masked or normalized label must never carry an href
|
|
1577
|
-
// that discloses what the mask hid. Collapsed labels never link.
|
|
1578
1306
|
const shownName = (path) => peekName(path);
|
|
1579
1307
|
const linkedName = (path) => {
|
|
1580
1308
|
const shown = shownName(path);
|
|
@@ -1608,8 +1336,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1608
1336
|
parts.push(html `<p class="meta">${seen.partial}</p>`);
|
|
1609
1337
|
let fragment = joinHtml(parts, "\n");
|
|
1610
1338
|
if (Buffer.byteLength(htmlString(fragment)) > PEEK_FRAGMENT_BYTES) {
|
|
1611
|
-
// The byte cap is enforced AFTER escaping (finding 32): an oversize
|
|
1612
|
-
// rendering is replaced whole by its exact counts.
|
|
1613
1339
|
fragment = html `<p class="meta">Best-effort look at ${stamp} UTC</p><p class="row">${changed.length} changed · ${deleted.length} deleted · ${fresh.total} new · ${unchecked.length} unverified — too much to render live; the final diff will hold the detail</p>`;
|
|
1614
1340
|
}
|
|
1615
1341
|
const bytes = Buffer.byteLength(htmlString(fragment));
|
|
@@ -1631,10 +1357,7 @@ export function createTasksHandlers(runtime) {
|
|
|
1631
1357
|
peekBySession.set(sessionKey, left);
|
|
1632
1358
|
}
|
|
1633
1359
|
}
|
|
1634
|
-
|
|
1635
|
-
function taskMutation(response, who, taskId, verb, posted, now,
|
|
1636
|
-
/** Read only to shape an answer in place (answersInPlace), after the act's proofs. */
|
|
1637
|
-
request = null) {
|
|
1360
|
+
function taskMutation(response, who, taskId, verb, posted, now, request = null) {
|
|
1638
1361
|
const ref = store.lookupRef(taskId);
|
|
1639
1362
|
if (ref === null || store.getTask(taskId) === null) {
|
|
1640
1363
|
return refuse(response, who, 404, "no such task", "/tasks");
|
|
@@ -1645,21 +1368,13 @@ export function createTasksHandlers(runtime) {
|
|
|
1645
1368
|
switch (verb) {
|
|
1646
1369
|
case "steer": {
|
|
1647
1370
|
const body = readForm(posted, CONSOLE_FORMS.taskSteer);
|
|
1648
|
-
// Steering is a browser session's act, explicitly (arc 1 v2 §3):
|
|
1649
|
-
// identify() accepts bearer credentials generically, and those are
|
|
1650
|
-
// for machines — a person watching steers, cookie + CSRF only.
|
|
1651
1371
|
if (who.via !== "cookie") {
|
|
1652
1372
|
return refuse(response, who, 403, "steering is a browser session's act");
|
|
1653
1373
|
}
|
|
1654
|
-
// The same gates as a pause or a stop (the route's act scope already refuses a viewer; this says why).
|
|
1655
1374
|
if (who.role !== "approver")
|
|
1656
1375
|
return taskScreen(response, who, taskId, "your login can watch — sending an agent a note is an approver's act", 403);
|
|
1657
1376
|
if (store.isDemo())
|
|
1658
1377
|
return taskScreen(response, who, taskId, "the demo authorizes nothing", 403);
|
|
1659
|
-
// From the Agents view, the note is for the exact run on screen (live-conversation.md §6): filed only while that
|
|
1660
|
-
// run is still the task's live build, once per draft key. Nothing is filed on a refusal; the view keeps the draft.
|
|
1661
|
-
// An unsent note from an attempt that ended, sent on to the task's next attempt from that agent's page: filed
|
|
1662
|
-
// task-level, back to the same agent with its draft key so only a confirmed send clears the draft.
|
|
1663
1378
|
if (body.has("after")) {
|
|
1664
1379
|
const afterRaw = body.get("after") ?? "";
|
|
1665
1380
|
const keyRaw = body.get("key") ?? "";
|
|
@@ -1669,9 +1384,7 @@ export function createTasksHandlers(runtime) {
|
|
|
1669
1384
|
if (ended === null || ended.taskRef !== ref.id || !/^[A-Za-z0-9-]{8,64}$/.test(keyRaw) || body.has("run") || (afterBack !== null && afterBack !== "task" && afterFlow === null)) {
|
|
1670
1385
|
return taskScreen(response, who, taskId, "that note did not say which agent it came from, so nothing was sent", 400);
|
|
1671
1386
|
}
|
|
1672
|
-
// The same receipt as a send to that run: a draft already filed while it ran comes back as sent, not twice.
|
|
1673
1387
|
const filed = store.fileSteerNoteForRun(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now, { run: ended.id, key: keyRaw, onward: true });
|
|
1674
|
-
// From the task page or a flow card: back there with the draft's key (only that draft clears), or the refusal in words.
|
|
1675
1388
|
if (afterBack !== null) {
|
|
1676
1389
|
if (filed.ok)
|
|
1677
1390
|
return redirect(response, afterFlow !== null ? `/flows/${afterFlow.flow}?card=${afterFlow.card}&sent=${keyRaw}` : `${taskHref(taskId)}?sent=${keyRaw}#steering`);
|
|
@@ -1681,7 +1394,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1681
1394
|
return redirect(response, `/agents?run=${ended.id}&said=steered-next&sent=${keyRaw}`);
|
|
1682
1395
|
return redirect(response, `/agents?run=${ended.id}&said=${filed.reason === "task-finished" ? "steer-next-finished" : filed.reason === "key-reused" ? "steer-stale" : "steer-invalid"}`);
|
|
1683
1396
|
}
|
|
1684
|
-
// A form that asks for a run but names none properly is refused — never quietly filed unbound.
|
|
1685
1397
|
if (body.get("return") === "agents" || body.get("return") === "task" || returnedFlow(body.get("return")) !== null || body.has("run") || body.has("key")) {
|
|
1686
1398
|
const runRaw = body.get("run") ?? "";
|
|
1687
1399
|
const keyRaw = body.get("key") ?? "";
|
|
@@ -1693,22 +1405,17 @@ export function createTasksHandlers(runtime) {
|
|
|
1693
1405
|
const shown = store.getRun(Number(runRaw));
|
|
1694
1406
|
if (shown === null || shown.taskRef !== ref.id)
|
|
1695
1407
|
return taskScreen(response, who, taskId, "that run is not part of this task", 404);
|
|
1696
|
-
// An attempt that takes no notes (a planner, a scout, a reviewer, one repairing its handoff) is never filed one:
|
|
1697
|
-
// it would never read it (cockpit §4).
|
|
1698
1408
|
const capability = steerCapabilityOf(store, shown.id, now);
|
|
1699
1409
|
if (capability !== null && capability.send === null) {
|
|
1700
1410
|
return from === "agents" ? redirect(response, `/agents?run=${shown.id}&said=steer-no-notes`) : taskScreen(response, who, taskId, capability.words, 409);
|
|
1701
1411
|
}
|
|
1702
1412
|
const bound = store.fileSteerNoteForRun(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now, { run: shown.id, key: keyRaw });
|
|
1703
|
-
// From the task page: back to its steering card, or the refusal in words (the page keeps nothing to restore).
|
|
1704
1413
|
if (from === "task") {
|
|
1705
|
-
// Back where it was written (the task page, or a flow card's task), with its draft's key: only that draft clears.
|
|
1706
1414
|
if (bound.ok)
|
|
1707
1415
|
return redirect(response, flowBack !== null ? `/flows/${flowBack.flow}?card=${flowBack.card}&sent=${keyRaw}` : `${taskHref(taskId)}?sent=${keyRaw}#steering`);
|
|
1708
1416
|
return taskScreen(response, who, taskId, bound.reason === "attempt-ended" || bound.reason === "task-finished" ? "that attempt ended before your note, so nothing was sent — reload and send it to the current one"
|
|
1709
1417
|
: bound.reason === "invalid-note" ? "that note will not store" : "that form was already used — reload and send it again", 409);
|
|
1710
1418
|
}
|
|
1711
|
-
// The draft's own key comes back: only that draft is cleared from the box.
|
|
1712
1419
|
if (bound.ok)
|
|
1713
1420
|
return redirect(response, `/agents?run=${shown.id}&said=steered&sent=${keyRaw}`);
|
|
1714
1421
|
if (bound.reason === "attempt-ended" || bound.reason === "task-finished")
|
|
@@ -1717,7 +1424,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1717
1424
|
return redirect(response, `/agents?run=${shown.id}&said=steer-invalid`);
|
|
1718
1425
|
return redirect(response, `/agents?run=${shown.id}&said=steer-stale`);
|
|
1719
1426
|
}
|
|
1720
|
-
// The session IS the verified principal here — cookie + CSRF proved it.
|
|
1721
1427
|
const filed = store.fileSteerNote(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now);
|
|
1722
1428
|
if (!filed.ok) {
|
|
1723
1429
|
const said = filed.reason === "task-finished"
|
|
@@ -1731,10 +1437,8 @@ export function createTasksHandlers(runtime) {
|
|
|
1731
1437
|
}
|
|
1732
1438
|
case "reply": {
|
|
1733
1439
|
const body = readForm(posted, CONSOLE_FORMS.taskReply);
|
|
1734
|
-
// A reply is steering, so it is a browser session's act too.
|
|
1735
1440
|
if (who.via !== "cookie")
|
|
1736
1441
|
return refuse(response, who, 403, "replying to an agent is a browser session's act");
|
|
1737
|
-
// The same gates as a pause: the route's act scope already refuses a viewer; these say why, and the demo answers nothing.
|
|
1738
1442
|
if (who.role !== "approver")
|
|
1739
1443
|
return taskScreen(response, who, taskId, "your login can watch — replying to an agent is an approver's act", 403);
|
|
1740
1444
|
if (store.isDemo())
|
|
@@ -1754,19 +1458,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1754
1458
|
if (reason.length > 200 || hasForbiddenControls(reason)) {
|
|
1755
1459
|
return taskScreen(response, who, taskId, "that reason will not render, so it will not store", 400);
|
|
1756
1460
|
}
|
|
1757
|
-
// Operator-owned only, always: the form supplies a reason, never an
|
|
1758
|
-
// owner. Decision, incident, and backoff holds are not reachable
|
|
1759
|
-
// from here, whatever a request claims.
|
|
1760
1461
|
store.hold(ref.id, reason, null, now);
|
|
1761
1462
|
return redirect(response, taskHref(taskId));
|
|
1762
1463
|
}
|
|
1763
1464
|
case "block": {
|
|
1764
1465
|
const body = readForm(posted, CONSOLE_FORMS.taskBlock);
|
|
1765
|
-
// Chains are scheduling, not authority (chains-and-next review,
|
|
1766
|
-
// finding 2): the edge decides WHEN the ready set admits the task;
|
|
1767
|
-
// approval still decides WHAT may build. Both ends are re-proved
|
|
1768
|
-
// here — existence and ceiling — and the
|
|
1769
|
-
// cycle refusal comes from the store's own closure check.
|
|
1770
1466
|
const on = (body.get("on") ?? "").trim();
|
|
1771
1467
|
const blocker = on === "" ? null : store.getTask(on);
|
|
1772
1468
|
const blockerRef = on === "" ? null : store.lookupRef(on);
|
|
@@ -1850,8 +1546,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1850
1546
|
}
|
|
1851
1547
|
case "reopen": {
|
|
1852
1548
|
const body = readForm(posted, CONSOLE_FORMS.taskReopen);
|
|
1853
|
-
// Authenticated like every approving act: the session alone may
|
|
1854
|
-
// read; resuming external work takes the password, typed again.
|
|
1855
1549
|
const token = (body.get("token") ?? "").trim();
|
|
1856
1550
|
const authenticated = token !== "" ? authenticateApprover(who, token) : null;
|
|
1857
1551
|
if (authenticated === null || !authenticated.ok) {
|
|
@@ -1878,7 +1572,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1878
1572
|
return redirect(response, taskHref(taskId));
|
|
1879
1573
|
}
|
|
1880
1574
|
case "stop-carrying": {
|
|
1881
|
-
// One click, any active approver (release-once.md): later commits of this release ask again. Only ever stricter.
|
|
1882
1575
|
const found = releaseAuthorityOfTask(store, taskId);
|
|
1883
1576
|
if (found === null)
|
|
1884
1577
|
return taskScreen(response, who, taskId, "This task isn't part of a release.", 409);
|
|
@@ -1889,29 +1582,33 @@ export function createTasksHandlers(runtime) {
|
|
|
1889
1582
|
}
|
|
1890
1583
|
case "requeue": {
|
|
1891
1584
|
const body = readForm(posted, CONSOLE_FORMS.taskRequeue);
|
|
1892
|
-
// Retry may carry a note for the next attempt: the same steering note, checked before anything changes.
|
|
1893
1585
|
const note = (body.get("note") ?? "").trim();
|
|
1894
1586
|
if (note !== "" && who.via !== "cookie")
|
|
1895
1587
|
return refuse(response, who, 403, "steering is a browser session's act");
|
|
1896
1588
|
if (note !== "" && !validateNote(note).ok)
|
|
1897
1589
|
return taskScreen(response, who, taskId, "that note will not store, so nothing was retried", 400);
|
|
1898
|
-
|
|
1899
|
-
if (
|
|
1900
|
-
|
|
1590
|
+
let replayed = false;
|
|
1591
|
+
if (who.via === "cookie" && who.authority === "local-owner") {
|
|
1592
|
+
const retried = localOwnerRetry(store, taskId, body.get("run"), body.get("digest"), now);
|
|
1593
|
+
if (!retried.ok)
|
|
1594
|
+
return taskScreen(response, who, taskId, retried.message, retried.status);
|
|
1595
|
+
replayed = retried.replayed;
|
|
1596
|
+
}
|
|
1597
|
+
else {
|
|
1598
|
+
const requeued = store.requeueTask(taskId, who.name, now);
|
|
1599
|
+
if (!requeued.ok) {
|
|
1600
|
+
return taskScreen(response, who, taskId, `not requeued: ${requeued.reason}`, 409);
|
|
1601
|
+
}
|
|
1901
1602
|
}
|
|
1902
|
-
if (note !== "") {
|
|
1603
|
+
if (note !== "" && !replayed) {
|
|
1903
1604
|
const filed = store.fileSteerNote(taskId, verifiedAuthor(who.name), note, now);
|
|
1904
1605
|
if (!filed.ok)
|
|
1905
1606
|
return taskScreen(response, who, taskId, "Retried. The note wasn't saved; add it under Steering.", 409);
|
|
1906
1607
|
}
|
|
1907
|
-
// Allow-listed return only — never an arbitrary URL from the form.
|
|
1908
1608
|
return redirect(response, body.get("return") === "inbox" || body.get("return") === "next" ? "/" : taskHref(taskId));
|
|
1909
1609
|
}
|
|
1910
1610
|
case "follow-up": {
|
|
1911
1611
|
const body = readForm(posted, CONSOLE_FORMS.taskFollowUp);
|
|
1912
|
-
// A scout's proposed follow-up, filed by the operator's tap (mate
|
|
1913
|
-
// arc §10): the ONE filing door, this task's repository, the scope
|
|
1914
|
-
// text stamped as the scout's — mode coverage never seals it.
|
|
1915
1612
|
const indexRaw = body.get("index") ?? "";
|
|
1916
1613
|
if (!/^[0-9]{1,2}$/.test(indexRaw))
|
|
1917
1614
|
return taskScreen(response, who, taskId, "which follow-up?", 400);
|
|
@@ -1925,10 +1622,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1925
1622
|
return taskScreen(response, who, taskId, "this task has no repository — file the follow-up by hand", 409);
|
|
1926
1623
|
if (!visible(ref.repo))
|
|
1927
1624
|
return taskScreen(response, who, taskId, "that repository is outside what this server shows", 403);
|
|
1928
|
-
// Idempotent by construction (v4 review, finding 10): the filing's
|
|
1929
|
-
// id is derived from the source task, the report's run, and the
|
|
1930
|
-
// follow-up's place — a retried POST lands on the task the first
|
|
1931
|
-
// one filed instead of minting a twin.
|
|
1932
1625
|
const followUpId = `${taskId.slice(0, 40)}-r${view.run}-f${Number(indexRaw) + 1}`;
|
|
1933
1626
|
if (store.getTask(followUpId) !== null)
|
|
1934
1627
|
return redirect(response, taskHref(followUpId));
|
|
@@ -1937,10 +1630,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1937
1630
|
title: followUp.title,
|
|
1938
1631
|
repo: ref.repo,
|
|
1939
1632
|
goal: followUp.goal,
|
|
1940
|
-
// v39: the scout's report format does not yet draft a rubric
|
|
1941
|
-
// per follow-up — a placeholder names the operator's own
|
|
1942
|
-
// review as the outstanding work, the same posture a
|
|
1943
|
-
// coordinator's bare intent takes.
|
|
1944
1633
|
acceptance: PLACEHOLDER_RUBRIC,
|
|
1945
1634
|
filedVia: "console", filedBy: { name: who.name, kind: "person" },
|
|
1946
1635
|
proposedVia: "scout",
|
|
@@ -1954,14 +1643,15 @@ export function createTasksHandlers(runtime) {
|
|
|
1954
1643
|
return redirect(response, taskHref(filed.id));
|
|
1955
1644
|
}
|
|
1956
1645
|
case "plan": {
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1646
|
+
if (who.via === "cookie" && who.authority === "local-owner") {
|
|
1647
|
+
const asked = localOwnerPlan(store, taskId, readForm(posted, CONSOLE_FORMS.taskPlan).get("source"), now);
|
|
1648
|
+
return asked.ok ? redirect(response, taskHref(taskId)) : taskScreen(response, who, taskId, asked.message, asked.status);
|
|
1649
|
+
}
|
|
1960
1650
|
const asked = store.requestPlan(ref.id, now);
|
|
1961
1651
|
if (!asked.ok) {
|
|
1962
1652
|
return taskScreen(response, who, taskId, `not planned: ${asked.reason}`, 409);
|
|
1963
1653
|
}
|
|
1964
|
-
if (who.via === "cookie")
|
|
1654
|
+
if (who.via === "cookie" && who.authority === "full")
|
|
1965
1655
|
authorizePlanUnderMode(store, taskId, who.name, now);
|
|
1966
1656
|
return redirect(response, taskHref(taskId));
|
|
1967
1657
|
}
|
|
@@ -2025,10 +1715,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2025
1715
|
case "accept-revision":
|
|
2026
1716
|
case "reject-revision": {
|
|
2027
1717
|
const body = readForm(posted, CONSOLE_FORMS.taskRevision);
|
|
2028
|
-
// Adaptive execution plans (v44): resolving a revision the builder
|
|
2029
|
-
// filed while its authority snapshot no longer matched the run it
|
|
2030
|
-
// started under — the ONLY road a 'blocked' plan_revision reaches,
|
|
2031
|
-
// since a plan-only proposal auto-applies without ever pausing here.
|
|
2032
1718
|
if (who.via !== "cookie") {
|
|
2033
1719
|
return refuse(response, who, 403, "resolving a plan revision is a browser session's act");
|
|
2034
1720
|
}
|
|
@@ -2039,9 +1725,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2039
1725
|
}
|
|
2040
1726
|
const outcome = verb === "accept-revision" ? "applied" : "rejected";
|
|
2041
1727
|
if (outcome === "applied") {
|
|
2042
|
-
// Accepting a revision that changed signed scope or publication
|
|
2043
|
-
// authority takes the password ceremony again — the same act
|
|
2044
|
-
// that would be required to approve that authority from scratch.
|
|
2045
1728
|
const token = (body.get("token") ?? "").trim();
|
|
2046
1729
|
if (!authenticateApprover(who, token).ok) {
|
|
2047
1730
|
return taskScreen(response, who, taskId, "accepting this revision takes your password, typed again", 403);
|
|
@@ -2070,23 +1753,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2070
1753
|
}
|
|
2071
1754
|
case "route": {
|
|
2072
1755
|
const body = readForm(posted, CONSOLE_FORMS.taskRoute);
|
|
2073
|
-
// THE AGENTS EDIT (v47): an approver's session sets the size,
|
|
2074
|
-
// overrides one role to an exact agent, or clears an override — ONE
|
|
2075
|
-
// authenticated transaction in the store that CAS-checks the scope
|
|
2076
|
-
// digest the form rendered (empty = "I saw no scope"), records the
|
|
2077
|
-
// change under this name, reconciles the planner pin, re-files the
|
|
2078
|
-
// scope so a sealed route goes visibly stale, and re-requests a
|
|
2079
|
-
// drafted plan when the planner changed. The viewer gate above
|
|
2080
|
-
// already refused a watcher; a live claim refuses
|
|
2081
|
-
// inside the transaction.
|
|
2082
1756
|
const sizeGiven = body.get("size");
|
|
2083
1757
|
const riskyGiven = body.getAll("risky");
|
|
2084
1758
|
const phaseGiven = body.get("phase");
|
|
2085
1759
|
const clearGiven = body.get("clear-phase");
|
|
2086
|
-
// The agent arrives as the form's `provider|model` choice (v48) or,
|
|
2087
|
-
// for older clients, as separate fields — either way it must be one
|
|
2088
|
-
// of the CONFIGURED, role-valid choices right now: the form offers
|
|
2089
|
-
// nothing else, and the server believes nothing else.
|
|
2090
1760
|
const agentGiven = (body.get("agent") ?? "").trim();
|
|
2091
1761
|
const providerGiven = agentGiven === "" ? body.get("provider") : agentGiven.slice(0, agentGiven.indexOf("|") === -1 ? agentGiven.length : agentGiven.indexOf("|"));
|
|
2092
1762
|
const modelGiven = agentGiven === "" ? (body.get("model") ?? "").trim() : agentGiven.indexOf("|") === -1 ? "" : agentGiven.slice(agentGiven.indexOf("|") + 1).trim();
|
|
@@ -2098,7 +1768,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2098
1768
|
return taskScreen(response, who, taskId, "size is small, medium, or large", 400);
|
|
2099
1769
|
if (riskyGiven.some(one => one !== "yes" && one !== "no"))
|
|
2100
1770
|
return taskScreen(response, who, taskId, "risky is yes or no", 400);
|
|
2101
|
-
// A size keeps the task's risky flag unless the form says otherwise; marking risky keeps the size.
|
|
2102
1771
|
const sizeEdit = sizeGiven === null && riskyGiven.length === 0 ? undefined : {
|
|
2103
1772
|
size: sizeGiven !== null && isTaskSize(sizeGiven) ? sizeGiven : ref.sizing?.size ?? "medium",
|
|
2104
1773
|
risky: riskyGiven.includes("yes") ? true : riskyGiven.includes("no") ? false : ref.sizing?.risky ?? false,
|
|
@@ -2118,17 +1787,12 @@ export function createTasksHandlers(runtime) {
|
|
|
2118
1787
|
if ((phaseGiven === "plan" || phaseGiven === "review") && isAcpProvider(providerGiven))
|
|
2119
1788
|
return taskScreen(response, who, taskId, `${ACP_AGENTS[providerGiven].name} builds and repairs only — choose another agent to ${phaseGiven}`, 400);
|
|
2120
1789
|
}
|
|
2121
|
-
// The configured-choice proof lives INSIDE the edit transaction
|
|
2122
|
-
// (`configured`): the pair is held to the role's choices under the
|
|
2123
|
-
// configuration standing at that instant, and a stale choice
|
|
2124
|
-
// mutates nothing.
|
|
2125
1790
|
const edited = store.editTaskRoute(ref.id, {
|
|
2126
1791
|
by: who.name,
|
|
2127
1792
|
authenticate: () => {
|
|
2128
1793
|
const account = store.accountOf(who.name);
|
|
2129
1794
|
return account !== null && account.revokedAt === null && account.role === "approver" ? { ok: true } : { ok: false, reason: "your login is no longer an approver" };
|
|
2130
1795
|
},
|
|
2131
|
-
// A person's size replaces the classifier's; the risky flag rides with it.
|
|
2132
1796
|
...(sizeEdit === undefined ? {} : { size: sizeEdit }),
|
|
2133
1797
|
...(phase === null
|
|
2134
1798
|
? {}
|
|
@@ -2139,7 +1803,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2139
1803
|
if (!edited.ok) {
|
|
2140
1804
|
return taskScreen(response, who, taskId, edited.reason === "not-configured" ? `agents not changed: ${edited.detail}` : edited.detail, edited.reason === "unauthenticated" ? 403 : edited.reason === "nothing" || edited.reason === "not-configured" ? 400 : 409);
|
|
2141
1805
|
}
|
|
2142
|
-
// v102: changing how a task runs is authoring it — the requester rule then refuses this person too.
|
|
2143
1806
|
const routed = store.getScope(taskId);
|
|
2144
1807
|
if (routed !== null)
|
|
2145
1808
|
store.recordScopeAuthor(taskId, routed.digest, who.name, now);
|
|
@@ -2173,14 +1836,11 @@ export function createTasksHandlers(runtime) {
|
|
|
2173
1836
|
: qualityGiven === "default"
|
|
2174
1837
|
? "default"
|
|
2175
1838
|
: ref.qualityMode ?? store.qualityDefault().mode;
|
|
2176
|
-
// The optional per-attempt dollar cap (v15) rides the same form.
|
|
2177
1839
|
const budgetGiven = (body.get("budget-usd") ?? "").trim();
|
|
2178
1840
|
const budgetUsd = budgetGiven === "" ? null : Number(budgetGiven);
|
|
2179
1841
|
if (budgetUsd !== null && (!Number.isFinite(budgetUsd) || budgetUsd <= 0)) {
|
|
2180
1842
|
return taskScreen(response, who, taskId, "the dollar cap is a positive amount", 400);
|
|
2181
1843
|
}
|
|
2182
|
-
// The approval sheet's in-place editor carries the cap it was shown
|
|
2183
|
-
// exactly, in millionths, and "none" for no limit (never a default).
|
|
2184
1844
|
const exactBudgetGiven = body.get("budget-microusd");
|
|
2185
1845
|
const exactBudget = exactBudgetGiven === null ? undefined : exactBudgetGiven === "none" ? null : /^[1-9][0-9]{0,14}$/.test(exactBudgetGiven) ? Number(exactBudgetGiven) : NaN;
|
|
2186
1846
|
if (Number.isNaN(exactBudget))
|
|
@@ -2189,13 +1849,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2189
1849
|
let saved;
|
|
2190
1850
|
try {
|
|
2191
1851
|
saved = store.transact(() => {
|
|
2192
|
-
// C1/M3: the signer's own credentialed filing auto-approves —
|
|
2193
|
-
// coverage is asked INSIDE this transaction, the escalated
|
|
2194
|
-
// default and budget ride the filing, and the seal commits
|
|
2195
|
-
// atomically with it.
|
|
2196
|
-
// COOKIE ONLY (C1's channel table; surfaces round 1, finding 1):
|
|
2197
|
-
// bearer credentials are for machines, and a machine road must
|
|
2198
|
-
// never spend the signer's mode.
|
|
2199
1852
|
const coverage = who.via === "cookie"
|
|
2200
1853
|
? modeFilingCoverage(store, ref.repo, who.name, now)
|
|
2201
1854
|
: null;
|
|
@@ -2205,7 +1858,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2205
1858
|
goal: body.has("goal-brief") ? `${(body.get("goal") ?? "").trim()}${body.get("goal-brief")}` : body.get("goal") ?? "",
|
|
2206
1859
|
outOfScope: body.get("not") ?? null,
|
|
2207
1860
|
touches: (body.get("touches") ?? "").split(/[\n,]/),
|
|
2208
|
-
// The approval sheet's in-place editor sends Done when line by line.
|
|
2209
1861
|
acceptance: inPlace
|
|
2210
1862
|
? requirementsFromEditor(body, before?.acceptance ?? [])
|
|
2211
1863
|
: acceptanceLinesToInput((body.get("acceptance") ?? "").split("\n")),
|
|
@@ -2230,9 +1882,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2230
1882
|
message: proposed.message ?? (proposed.reason === "acceptance-required" ? "Not saved: add at least one requirement under Done when." : `scope not saved: ${proposed.reason}`),
|
|
2231
1883
|
};
|
|
2232
1884
|
}
|
|
2233
|
-
// Editing the plan in place never changes what the agent may do:
|
|
2234
|
-
// a save that would (a legacy setting, a newer policy or mode)
|
|
2235
|
-
// rolls back whole.
|
|
2236
1885
|
if (inPlace && before?.profile != null && proposed.scope.profile != null && levelOfProfile(before.profile) !== levelOfProfile(proposed.scope.profile)) {
|
|
2237
1886
|
throw new PermissionsWouldChange();
|
|
2238
1887
|
}
|
|
@@ -2243,7 +1892,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2243
1892
|
const filedScope = store.getScope(taskId);
|
|
2244
1893
|
if (filedScope?.profileState === "resolved") {
|
|
2245
1894
|
const sealedUnderMode = store.sealScopeApproval(taskId, who.name, now, {}, { kind: "mode", modeDigest: coverage.digest });
|
|
2246
|
-
// The quarantine speaks at the caller (review finding 7).
|
|
2247
1895
|
if (!sealedUnderMode) {
|
|
2248
1896
|
return { ok: false, status: 200, message: "scope saved — coordinator-filed: mode coverage cannot admit it; sign the scope" };
|
|
2249
1897
|
}
|
|
@@ -2258,8 +1906,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2258
1906
|
saved = { ok: false, status: 409, message: "Not saved: this would change what the agent may do. Change permissions in Details, under edit the scope." };
|
|
2259
1907
|
}
|
|
2260
1908
|
if (!saved.ok) {
|
|
2261
|
-
// Refused because the plan moved on: the draft comes back with the version now on file, so saving it
|
|
2262
|
-
// again (having read the reason) can succeed instead of being refused the same way.
|
|
2263
1909
|
const draft = new URLSearchParams(body.sent);
|
|
2264
1910
|
if (saved.status === 409)
|
|
2265
1911
|
draft.set("sawDigest", store.getScope(taskId)?.digest ?? "");
|
|
@@ -2277,13 +1923,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2277
1923
|
: requestedReturn === null
|
|
2278
1924
|
? taskHref(taskId)
|
|
2279
1925
|
: safeChatReturn(requestedReturn);
|
|
2280
|
-
// The release sheet's Approve release (trusted-release-reports.md A7): the same door, its own page for words.
|
|
2281
1926
|
const sheet = body.get("sheet") === "release";
|
|
2282
|
-
// Each caller names its outcome (live-pages-and-home.md B2.3); none is inferred from the status.
|
|
2283
1927
|
const approvalProblem = (outcome, message, status) => {
|
|
2284
1928
|
if (sheet)
|
|
2285
1929
|
return releaseSheet.sheetScreen({ who, response, project: null }, taskId, message, status);
|
|
2286
|
-
// Asked in place: the same proofs ran, only the answer's shape differs.
|
|
2287
1930
|
if (answersInPlace(request))
|
|
2288
1931
|
return answerApprovalInPlace(response, outcome, message, status);
|
|
2289
1932
|
if (requestedReturn !== null && requestedReturn !== "next") {
|
|
@@ -2295,23 +1938,16 @@ export function createTasksHandlers(runtime) {
|
|
|
2295
1938
|
if (approvingRef?.plan === "requested") {
|
|
2296
1939
|
return approvalProblem("refused", "approval is blocked while planning is in progress — review the drafted plan first", 409);
|
|
2297
1940
|
}
|
|
2298
|
-
// Step-up: the session got you here; only the token agrees. The
|
|
2299
|
-
// digest names what was seen; the nonce proves this exact form was
|
|
2300
|
-
// rendered to this approver and is spent either way.
|
|
2301
1941
|
const digest = body.get("digest") ?? "";
|
|
2302
1942
|
const token = body.get("token") ?? "";
|
|
2303
1943
|
const nonce = body.get("nonce") ?? "";
|
|
2304
1944
|
if (!consumeApprovalNonce(nonce, who.name, taskId, digest)) {
|
|
2305
1945
|
return approvalProblem("refused", "that approval form is stale — read it again", 409);
|
|
2306
1946
|
}
|
|
2307
|
-
// An empty password stands for an explicit identity-provider re-check not yet spent, or (cockpit B2) a password
|
|
2308
|
-
// remembered on this session; approve() decides whether these terms may stand on a remembered one.
|
|
2309
|
-
// Easy-start C5: a laptop's local owner approves eligible work with no password (approve() proves it again).
|
|
2310
1947
|
if (token === "" && !passwordlessSessionFor(store, who.name) && !ssoNowAvailable(who.name) && withFreshness("approve-standard", () => freshnessFor(who.name)) === null
|
|
2311
1948
|
&& !(who.authority === "local-owner" && localApprovalEligible(store, who.name, taskId).ok)) {
|
|
2312
1949
|
return approvalProblem("refused", "approval requires your password, typed again", 400);
|
|
2313
1950
|
}
|
|
2314
|
-
// The sheet binds the release card's digest (the nonce was minted for it): the shared card wrapper decides.
|
|
2315
1951
|
if (sheet)
|
|
2316
1952
|
return releaseSheet.approveFromSheet({ who, response, project: null }, taskId, digest, token);
|
|
2317
1953
|
const scopeRow = store.getScope(taskId);
|
|
@@ -2322,21 +1958,14 @@ export function createTasksHandlers(runtime) {
|
|
|
2322
1958
|
if (digest !== expectedDigest) {
|
|
2323
1959
|
return approvalProblem("refused", "the scope or plan changed while this form was open — read the latest version and approve again", 409);
|
|
2324
1960
|
}
|
|
2325
|
-
// A revision approves ONLY against a brief that still verifies
|
|
2326
|
-
// (Codex M5-M8 audit, IV-3): the batch the screen restated must be
|
|
2327
|
-
// provably the batch on disk at the moment of the yes — a brief
|
|
2328
|
-
// deleted or corrupted between render and click blocks the
|
|
2329
|
-
// approval instead of silently approving comment-free work.
|
|
2330
1961
|
if (approvingRef !== null && approvingRef.revisionBriefArtifact !== null) {
|
|
2331
1962
|
const view = revisionViewOf(approvingRef);
|
|
2332
1963
|
if (view !== null && "problem" in view) {
|
|
2333
1964
|
return approvalProblem("refused", `approval is blocked: ${view.problem}`, 409);
|
|
2334
1965
|
}
|
|
2335
1966
|
}
|
|
2336
|
-
// A re-check is spent only if this yes is kept (sealed, or a protected-work vote recorded).
|
|
2337
1967
|
const approved = spendingOnlyOnSuccess(() => withFreshness("approve-standard", () => approveScope(store, taskId, who.name, now, scopeRow.digest, token)), result => !result.ok && !(result.reason === "second-approver" && !result.already));
|
|
2338
1968
|
if (!approved.ok) {
|
|
2339
|
-
// v102: a first yes on protected work is recorded, not refused — the page says who else is needed.
|
|
2340
1969
|
if (approved.reason === "second-approver")
|
|
2341
1970
|
return approvalProblem("vote", gateWords({ verdict: "vote", have: approved.have, need: 2, already: approved.already }), 200);
|
|
2342
1971
|
if (approved.reason === "policy")
|
|
@@ -2344,13 +1973,9 @@ export function createTasksHandlers(runtime) {
|
|
|
2344
1973
|
const status = approved.reason === "changed" || approved.reason === "unrouted" ? 409 : 403;
|
|
2345
1974
|
return approvalProblem("refused", approveRefusalWords(approved.reason), status);
|
|
2346
1975
|
}
|
|
2347
|
-
// Approve & build again (the plan was rewritten after a build): the same yes requeues, only for the build the
|
|
2348
|
-
// sheet named, and only while it is still the task's latest result, made to an earlier plan than this one.
|
|
2349
1976
|
const rebuildRaw = body.get("rebuild") ?? "";
|
|
2350
1977
|
if (rebuildRaw !== "") {
|
|
2351
1978
|
const named = /^[0-9]{1,15}$/.test(rebuildRaw) ? store.getRun(Number(rebuildRaw)) : null;
|
|
2352
|
-
// Built to an earlier plan than the one just approved (the scope this approval sealed, scopeRow.digest);
|
|
2353
|
-
// requeueTask re-proves, in its own transaction, that it is still the latest result and that scope approved.
|
|
2354
1979
|
const offered = named != null && named.taskRef === ref.id && named.role === "builder" && !!named.scopeDigest && named.scopeDigest !== scopeRow.digest;
|
|
2355
1980
|
const requeued = offered ? store.requeueTask(taskId, who.name, now, { run: named.id, scopeDigest: scopeRow.digest }) : null;
|
|
2356
1981
|
if (requeued === null || (!requeued.ok && requeued.reason === "moved"))
|
|
@@ -2364,13 +1989,9 @@ export function createTasksHandlers(runtime) {
|
|
|
2364
1989
|
}
|
|
2365
1990
|
case "accept-proof": {
|
|
2366
1991
|
const body = readForm(posted, CONSOLE_FORMS.taskAcceptProof);
|
|
2367
|
-
// Accepting is a person's act, like approving a scope (Priority
|
|
2368
|
-
// 2): a cookie session only, never a bearer credential.
|
|
2369
1992
|
if (who.via !== "cookie") {
|
|
2370
1993
|
return refuse(response, who, 403, "accepting a proof is a browser session's act");
|
|
2371
1994
|
}
|
|
2372
|
-
// v40 fix: a reviewer run is never the attempt whose proof is
|
|
2373
|
-
// being accepted.
|
|
2374
1995
|
const latest = store.runsFor(ref.id).find(runIsTaskResult);
|
|
2375
1996
|
if (latest === undefined) {
|
|
2376
1997
|
return taskScreen(response, who, taskId, "this task has no finished attempt to accept", 404);
|
|
@@ -2388,9 +2009,7 @@ export function createTasksHandlers(runtime) {
|
|
|
2388
2009
|
}
|
|
2389
2010
|
note = validated.note;
|
|
2390
2011
|
}
|
|
2391
|
-
// A failed task's result is accepted only anyway, on purpose: with a reason.
|
|
2392
2012
|
if (note === null && store.getTask(taskId)?.state === "failed") {
|
|
2393
|
-
// Posted from the result page: back there, where the reason field is, with the refusal said on it.
|
|
2394
2013
|
const back = body.get("return") === null ? null : safeReturn(body.get("return"));
|
|
2395
2014
|
if (back !== null && back.startsWith("/review?"))
|
|
2396
2015
|
return redirect(response, withRefusal(back, "reason"));
|
|
@@ -2401,7 +2020,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2401
2020
|
}
|
|
2402
2021
|
case "complete": {
|
|
2403
2022
|
const body = readForm(posted, CONSOLE_FORMS.taskComplete);
|
|
2404
|
-
// The row admits only an approver's browser session; the principal re-proves that session's standing.
|
|
2405
2023
|
const principal = who.via === "cookie" ? leadPrincipal(who) : null;
|
|
2406
2024
|
if (principal === null)
|
|
2407
2025
|
return refuse(response, who, 403, "Your access changed. Sign in again.");
|
|
@@ -2412,8 +2030,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2412
2030
|
return taskScreen(response, who, taskId, "This result changed. Open the current result before marking it complete.", 409);
|
|
2413
2031
|
}
|
|
2414
2032
|
if (body.get("accept") === "1") {
|
|
2415
|
-
// Accept and finish: the person's acceptance and the completion of what it accepted, in one request
|
|
2416
|
-
// and one transaction. The receipt named is the one read, before accepting.
|
|
2417
2033
|
const rawNote = (body.get("note") ?? "").trim();
|
|
2418
2034
|
let note = null;
|
|
2419
2035
|
if (rawNote !== "") {
|
|
@@ -2429,8 +2045,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2429
2045
|
return redirect(response, publish ? `${taskHref(familyOf(taskId)?.root.id ?? taskId)}#merge` : body.get("return") === null ? reviewHref(taskId, Number(namedRun)) : safeReturn(body.get("return")));
|
|
2430
2046
|
}
|
|
2431
2047
|
if (body.get("publish") === "1") {
|
|
2432
|
-
// "Complete and open a pull request": the same exact-receipt completion, plus the owed PR for this
|
|
2433
|
-
// exact commit in one transaction. The watch process pushes and opens it; the task shows its progress.
|
|
2434
2048
|
const opened = completeAndOpenPullRequest(store, { taskId, digest, runId: Number(namedRun), who: principal, root: evidenceRoot }, now);
|
|
2435
2049
|
if (!opened.ok)
|
|
2436
2050
|
return taskScreen(response, who, taskId, opened.message, 409);
|
|
@@ -2439,7 +2053,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2439
2053
|
const completed = checkAssignmentAsOperator(store, taskId, digest, principal, now, evidenceRoot);
|
|
2440
2054
|
if (!completed.ok)
|
|
2441
2055
|
return taskScreen(response, who, taskId, completed.message, 409);
|
|
2442
|
-
// Back where it was completed (the task page's Result tab, or the result page), as Accept and finish does.
|
|
2443
2056
|
return redirect(response, body.get("return") === null ? reviewHref(taskId, Number(namedRun)) : safeReturn(body.get("return")));
|
|
2444
2057
|
}
|
|
2445
2058
|
case "retry-review": {
|
|
@@ -2447,12 +2060,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2447
2060
|
}
|
|
2448
2061
|
case "stop": {
|
|
2449
2062
|
const body = readForm(posted, CONSOLE_FORMS.taskStop);
|
|
2450
|
-
// The exact-run stop (v52): a browser session's act, an approver's
|
|
2451
|
-
// act, naming ONE run. The store's transaction proves the run is
|
|
2452
|
-
// this task's current live attempt and records who asked before
|
|
2453
|
-
// any process is signalled; the answer is "stopping", never
|
|
2454
|
-
// "stopped". A repeated post is the same request; a stale one (a
|
|
2455
|
-
// finished run, a successor) is refused in words.
|
|
2456
2063
|
if (who.via !== "cookie")
|
|
2457
2064
|
return refuse(response, who, 403, "stopping a task is a browser session's act");
|
|
2458
2065
|
if (who.role !== "approver")
|
|
@@ -2474,7 +2081,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2474
2081
|
return taskScreen(response, who, taskId, words[asked.reason] ?? asked.detail, 409);
|
|
2475
2082
|
}
|
|
2476
2083
|
const back = body.get("return") ?? "";
|
|
2477
|
-
// From the Agents board: back to the same agent, saying what happens now.
|
|
2478
2084
|
if (back === "agents")
|
|
2479
2085
|
return redirect(response, `/agents?run=${Number(named)}&said=stopping`);
|
|
2480
2086
|
const stopFlow = returnedFlow(back);
|
|
@@ -2484,10 +2090,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2484
2090
|
}
|
|
2485
2091
|
case "pause": {
|
|
2486
2092
|
const body = readForm(posted, CONSOLE_FORMS.taskPause);
|
|
2487
|
-
// Pause, and Pause and steer (live steering): a browser session's act, an approver's act, naming the ONE run
|
|
2488
|
-
// the page showed under the page's own request id. It stops the running Claude build's turn and keeps the
|
|
2489
|
-
// build; a note that rides along is filed in the same transaction and sent right after. mode=resume continues a
|
|
2490
|
-
// paused build with no note. Never a stop.
|
|
2491
2093
|
if (who.via !== "cookie")
|
|
2492
2094
|
return refuse(response, who, 403, "pausing a build is a browser session's act");
|
|
2493
2095
|
if (who.role !== "approver")
|
|
@@ -2498,7 +2100,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2498
2100
|
if (!/^[0-9]{1,15}$/.test(named))
|
|
2499
2101
|
return taskScreen(response, who, taskId, "which build? a pause names one exact run", 400);
|
|
2500
2102
|
const note = (body.get("note") ?? "").trim();
|
|
2501
|
-
// Resume: the paused build goes on where it stopped; no note is filed.
|
|
2502
2103
|
const asked = body.get("mode") === "resume"
|
|
2503
2104
|
? store.requestResume({ taskId, runId: Number(named), by: verifiedAuthor(who.name), via: "web", requestId: body.get("request") ?? "" }, now)
|
|
2504
2105
|
: store.requestPause({ taskId, runId: Number(named), by: verifiedAuthor(who.name), via: "web", requestId: body.get("request") ?? "", ...(note === "" ? {} : { note }) }, now);
|
|
@@ -2514,14 +2115,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2514
2115
|
return taskScreen(response, who, taskId, words[asked.reason] ?? asked.detail, asked.reason === "invalid-note" ? 400 : 409);
|
|
2515
2116
|
}
|
|
2516
2117
|
const back = body.get("return") ?? "";
|
|
2517
|
-
// A note that rode along came from a composer's draft: its key comes back, so only that draft clears.
|
|
2518
2118
|
const keyRaw = body.get("key") ?? "";
|
|
2519
|
-
// Only a note this request actually stored clears its draft: a repeated request answers with the note it stored
|
|
2520
|
-
// the first time, and a draft edited since is not that note.
|
|
2521
2119
|
const storedId = "note" in asked && typeof asked.note === "number" ? asked.note : null;
|
|
2522
2120
|
const stored = storedId === null ? null : store.handle.prepare("SELECT note FROM task_steer WHERE id = ?").get(storedId)?.["note"];
|
|
2523
2121
|
const sent = note !== "" && /^[A-Za-z0-9-]{8,64}$/.test(keyRaw) && typeof stored === "string" && stored.trim() === note ? keyRaw : null;
|
|
2524
|
-
// A note that rode along but is not the one this request stored (a reused form): said plainly, the draft kept.
|
|
2525
2122
|
if (note !== "" && (typeof stored !== "string" || stored.trim() !== note)) {
|
|
2526
2123
|
if (back === "agents")
|
|
2527
2124
|
return redirect(response, `/agents?run=${Number(named)}&said=pause-note-stale`);
|
|
@@ -2542,11 +2139,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2542
2139
|
}
|
|
2543
2140
|
case "resume": {
|
|
2544
2141
|
const body = readForm(posted, CONSOLE_FORMS.taskResume);
|
|
2545
|
-
// The resume itself (v52): password typed again + the durable nonce
|
|
2546
|
-
// consumed INSIDE the store's resume transaction against the digest
|
|
2547
|
-
// re-derived from live state. A replay finds the nonce spent; a
|
|
2548
|
-
// changed approval finds the digest moved; a successor attempt finds
|
|
2549
|
-
// the run superseded — each refuses without starting work; a submitted nonce remains one-shot.
|
|
2550
2142
|
if (who.via !== "cookie")
|
|
2551
2143
|
return refuse(response, who, 403, "resuming a task is a browser session's act");
|
|
2552
2144
|
if (who.role !== "approver")
|
|
@@ -2594,10 +2186,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2594
2186
|
return refuse(response, who, 404, "That action isn't available here.", taskHref(taskId));
|
|
2595
2187
|
}
|
|
2596
2188
|
}
|
|
2597
|
-
/** The queue as a region: dispatch order per column, drag handles and
|
|
2598
|
-
* all — the /queue page's body, and the board's "order" view (the one
|
|
2599
|
-
* place dragging exists, because reordering and reserving are scheduling,
|
|
2600
|
-
* never authority). */
|
|
2601
2189
|
function queueRegionFor(project, csrf, revision, now) {
|
|
2602
2190
|
const tasks = store.queueScoped(project, now).map(one => ({
|
|
2603
2191
|
...one,
|
|
@@ -2620,23 +2208,12 @@ export function createTasksHandlers(runtime) {
|
|
|
2620
2208
|
}));
|
|
2621
2209
|
return queueBody(tasks, workers, revision, store.queueRevision());
|
|
2622
2210
|
}
|
|
2623
|
-
/** An OBSERVED CI failure on a completed row's PR — the open episode the
|
|
2624
|
-
* watcher recorded for exactly that repository and number; never a guess
|
|
2625
|
-
* from quiet. One indexed publication read per row that has a PR. */
|
|
2626
2211
|
function ciFailingFor(runId, prNumber) {
|
|
2627
2212
|
if (runId === null || prNumber === null)
|
|
2628
2213
|
return false;
|
|
2629
2214
|
const publication = store.publicationForRun(runId);
|
|
2630
2215
|
return publication !== null && publication.prNumber === prNumber && store.hasOpenCiEpisode(publication.githubRepo, prNumber);
|
|
2631
2216
|
}
|
|
2632
|
-
/**
|
|
2633
|
-
* One completed row by task id, for a `?result=` deep link the bounded
|
|
2634
|
-
* queue could not show — the done list's own predicate, re-proved per
|
|
2635
|
-
* read: the task is done, sits in this project (or in none), and its
|
|
2636
|
-
* repository passes the ceiling; the result run is the newest finished
|
|
2637
|
-
* built/no-change builder or scout attempt. Anything else is
|
|
2638
|
-
* null, and null reads exactly like a task that never existed.
|
|
2639
|
-
*/
|
|
2640
2217
|
function completedRowFor(taskId, project) {
|
|
2641
2218
|
const family = familyOf(taskId);
|
|
2642
2219
|
if (family === null)
|
|
@@ -2652,15 +2229,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2652
2229
|
(one.role === "builder" || one.role === "scout")) ?? null;
|
|
2653
2230
|
return resultRowOf(task, ref.repo, family.problem, run);
|
|
2654
2231
|
}
|
|
2655
|
-
/**
|
|
2656
|
-
* A build attempt that didn't deliver a result (failed, refused, stopped,
|
|
2657
|
-
* never finished) still has a result page: its changes, its checks and what
|
|
2658
|
-
* went wrong. The row for one: the run named by `runId` when it is an ended
|
|
2659
|
-
* builder or scout attempt of this task that isn't a delivered result, or a
|
|
2660
|
-
* failed task's latest attempt; with no run named, that latest attempt. The
|
|
2661
|
-
* same admission as a completed row: in this project (or none) and inside
|
|
2662
|
-
* the ceiling. Null otherwise, which reads like a task that never existed.
|
|
2663
|
-
*/
|
|
2664
2232
|
function attemptRowFor(taskId, runId, project) {
|
|
2665
2233
|
const family = familyOf(taskId);
|
|
2666
2234
|
const task = store.getTask(taskId);
|
|
@@ -2672,7 +2240,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2672
2240
|
const attempts = store.runsFor(ref.id).filter(one => (one.role === "builder" || one.role === "scout") && (one.finishedAt !== null || one.outcome !== null));
|
|
2673
2241
|
const latest = task.state === "failed" ? latestFinishedAttempt(attempts) : null;
|
|
2674
2242
|
const run = runId !== null ? attempts.find(one => one.id === runId) ?? null : latest;
|
|
2675
|
-
// A delivered result has its completed row; a failed task's latest attempt is what failed, whatever it ended as.
|
|
2676
2243
|
if (run === null || runIsLive(run) || ((run.outcome === "built" || run.outcome === "no-change") && run.id !== latest?.id))
|
|
2677
2244
|
return null;
|
|
2678
2245
|
return resultRowOf(task, ref.repo, family.problem, run);
|
|
@@ -2708,8 +2275,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2708
2275
|
function reviewCockpitViewOf(row, who, now) {
|
|
2709
2276
|
const ref = store.lookupRef(row.taskId);
|
|
2710
2277
|
const scope = store.getScope(row.taskId);
|
|
2711
|
-
// The result run, read once: the shared result detail below hangs off
|
|
2712
|
-
// this one record.
|
|
2713
2278
|
const run = row.runId === null ? null : store.getRun(row.runId);
|
|
2714
2279
|
const intent = scope === null
|
|
2715
2280
|
? null
|
|
@@ -2767,39 +2332,27 @@ export function createTasksHandlers(runtime) {
|
|
|
2767
2332
|
summary: detail.handoff?.conclusion ?? run.handoff,
|
|
2768
2333
|
},
|
|
2769
2334
|
detail,
|
|
2770
|
-
// How it ran: derived from the run's own records once it has finished, display only. A read ahead of the page's
|
|
2771
|
-
// link (x-toolroll-read: prefetch) derives it and saves nothing.
|
|
2772
2335
|
efficiency: (() => { try {
|
|
2773
2336
|
return runEfficiencyOf(store, evidenceRoot, run.id, now, requestContext.getStore()?.readPurpose !== "prefetch");
|
|
2774
2337
|
}
|
|
2775
2338
|
catch {
|
|
2776
2339
|
return null;
|
|
2777
2340
|
} })(),
|
|
2778
|
-
// What its network was and what its proxy saw (egress.ts), display only.
|
|
2779
2341
|
network: store.runNetwork(run.id),
|
|
2780
|
-
// Where the time went: its release check's parts and the task's deploys (latency-timeline.ts), display only.
|
|
2781
2342
|
timing: timingFor(store, run.id, row.taskId),
|
|
2782
|
-
// How far its checks reached (check-access.ts), display only.
|
|
2783
2343
|
checkAccess: store.runCheckAccess(run.id),
|
|
2784
|
-
// How its checks actually ran, by what was stamped at launch: said only for a result whose checks ran.
|
|
2785
2344
|
checkRan: store.artifactsFor(run.id).some(one => one.kind === "check-log") ? ranWords(runCheckStamp(store, run.id)) : null,
|
|
2786
2345
|
reviewRetry: store.reviewRetryStateOf(run.id),
|
|
2787
2346
|
review: reviewFactsFor(run.id),
|
|
2788
2347
|
notes: store.notesForRun(run.id),
|
|
2789
2348
|
};
|
|
2790
2349
|
}
|
|
2791
|
-
// ---- evidence ------------------------------------------------------------
|
|
2792
2350
|
function decisionEvidence(response, decisionId, artifactId) {
|
|
2793
|
-
// The ceiling applies to decision evidence exactly as to run evidence
|
|
2794
|
-
// (v2 review, finding 2): a decision whose task belongs to a repo this
|
|
2795
|
-
// server may not serve does not exist here, and neither do its bytes.
|
|
2796
2351
|
const decision = store.getDecision(decisionId);
|
|
2797
2352
|
const decisionRun = decision === null ? null : store.getRun(decision.run);
|
|
2798
2353
|
if (decisionRun !== null && !visible(taskRepoOf(decisionRun.taskRef))) {
|
|
2799
2354
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
2800
2355
|
}
|
|
2801
|
-
// Only through the decision's own relation — an artifact id from another
|
|
2802
|
-
// run simply is not in this list, whatever the URL claims.
|
|
2803
2356
|
const linked = store.evidenceFor(decisionId).find(one => one.id === artifactId);
|
|
2804
2357
|
if (linked === undefined) {
|
|
2805
2358
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
@@ -2811,8 +2364,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2811
2364
|
if (run === null || !runVisible(run)) {
|
|
2812
2365
|
return respond(response, 404, "text/plain; charset=utf-8", "no such run");
|
|
2813
2366
|
}
|
|
2814
|
-
// Membership is the lookup's own predicate — there is no way to check
|
|
2815
|
-
// the run and fetch the artifact as two separate acts here.
|
|
2816
2367
|
const linked = store.artifactForRun(runId, artifactId);
|
|
2817
2368
|
if (linked === null) {
|
|
2818
2369
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
@@ -2824,9 +2375,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2824
2375
|
if (!read.ok) {
|
|
2825
2376
|
return respond(response, 410, "text/plain; charset=utf-8", "the evidence no longer matches its record");
|
|
2826
2377
|
}
|
|
2827
|
-
// A validated screenshot is the one evidence kind meant to render
|
|
2828
|
-
// inline (thumbnails, full-image links) — every other kind stays a
|
|
2829
|
-
// downloaded text record, exactly as before.
|
|
2830
2378
|
if (linked.kind === "screenshot") {
|
|
2831
2379
|
const imageType = linked.key.endsWith(".png") ? "image/png" : linked.key.endsWith(".jpg") ? "image/jpeg" : null;
|
|
2832
2380
|
if (imageType !== null) {
|
|
@@ -2842,7 +2390,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2842
2390
|
});
|
|
2843
2391
|
response.end(read.content);
|
|
2844
2392
|
}
|
|
2845
|
-
/** The full guard list (v3 §4) — run on every request, hit or miss. */
|
|
2846
2393
|
function peekGuards(runId) {
|
|
2847
2394
|
if (options.localRunner === undefined || options.poolRoot === undefined) {
|
|
2848
2395
|
return { ok: false, message: "live peek is off — start serve with --runner <name> naming this machine's runner", final: true };
|
|
@@ -2852,17 +2399,11 @@ export function createTasksHandlers(runtime) {
|
|
|
2852
2399
|
return { ok: false, message: "no such build", final: true };
|
|
2853
2400
|
if (run.outcome !== null)
|
|
2854
2401
|
return { ok: false, message: "this build has finished — the final diff below is the record", final: true };
|
|
2855
|
-
// The reviewer role (v29): artifact-only, honestly — there is no
|
|
2856
|
-
// checkout anywhere to watch, and there never was.
|
|
2857
2402
|
if (run.worktree === null) {
|
|
2858
2403
|
return { ok: false, message: "this run reviewed the sealed diff — no workspace existed to watch", final: true };
|
|
2859
2404
|
}
|
|
2860
2405
|
if (run.baseRevision === null)
|
|
2861
2406
|
return { ok: false, message: "the build has not settled its starting point yet" };
|
|
2862
|
-
// The run's lease must be the task's CURRENT live lease — max generation,
|
|
2863
|
-
// unreleased, strictly unexpired. liveClaimByLease proves only that the
|
|
2864
|
-
// lease exists; a superseded lease would still pass it (round-4
|
|
2865
|
-
// finding 15), and superseded is forever, so the poller may stop.
|
|
2866
2407
|
if (store.currentLiveLease(run.taskRef, clock()) !== run.leaseId) {
|
|
2867
2408
|
return { ok: false, message: "the build is not actively running right now", final: true };
|
|
2868
2409
|
}
|
|
@@ -2872,8 +2413,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2872
2413
|
if (row.runner !== options.localRunner) {
|
|
2873
2414
|
return { ok: false, message: "this build runs on another machine — open the console there to watch it", final: true };
|
|
2874
2415
|
}
|
|
2875
|
-
// Adoption-path rows can carry no epoch (round-3 finding 37): no fence,
|
|
2876
|
-
// no peek — never a guess.
|
|
2877
2416
|
if (row.leaseEpoch === null || row.leaseEpoch === undefined) {
|
|
2878
2417
|
return { ok: false, message: "this checkout was set up before live watching existed — the next fresh build can be watched", final: true };
|
|
2879
2418
|
}
|
|
@@ -2887,8 +2426,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2887
2426
|
catch {
|
|
2888
2427
|
return { ok: false, message: "the checkout could not be found on this machine" };
|
|
2889
2428
|
}
|
|
2890
|
-
// The snapshot: exactly one successful, untruncated base-tree artifact
|
|
2891
|
-
// whose envelope binds THIS run and THIS base (round-3 finding 42).
|
|
2892
2429
|
const artifact = store.artifactsFor(runId).find(one => one.kind === "base-tree");
|
|
2893
2430
|
if (artifact === undefined)
|
|
2894
2431
|
return { ok: false, message: "no base snapshot was captured for this build" };
|
|
@@ -2904,7 +2441,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2904
2441
|
}
|
|
2905
2442
|
return { ok: true, admit: { run, worktree: run.worktree, epoch: row.leaseEpoch, entries: snapshot } };
|
|
2906
2443
|
}
|
|
2907
|
-
/** The live subset of a bounded run page \u2014 one indexed lookup per row. */
|
|
2908
2444
|
function liveRunIds(rows) {
|
|
2909
2445
|
const live = new Set();
|
|
2910
2446
|
for (const run of rows)
|
|
@@ -2914,7 +2450,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2914
2450
|
}
|
|
2915
2451
|
const tidyHandlers = createTidyHandlers(runtime);
|
|
2916
2452
|
const releaseSheet = createReleaseSheetHandlers(runtime);
|
|
2917
|
-
/** The question page, with a refusal in its box when an answer was refused (the box keeps the choice to make). */
|
|
2918
2453
|
function decisionScreen(ctx, id, back, refusal, code, now, draft) {
|
|
2919
2454
|
const { who, response, project } = ctx;
|
|
2920
2455
|
const decision = store.getDecision(id);
|
|
@@ -2941,13 +2476,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2941
2476
|
"code.changes-read": showCode("changes", true),
|
|
2942
2477
|
"code.ship-preview": showCode("ship", true),
|
|
2943
2478
|
"code.other": showCode("unknown"),
|
|
2944
|
-
// Retired into Tasks and the task page (src/design/KIT.md): each old address still answers, as a redirect.
|
|
2945
|
-
// Retired pages (docs/plans/plain-toolroll.md P1.4): permanent redirects, no page handler of their own.
|
|
2946
2479
|
"inbox": async (ctx) => retiredRedirect("inbox", ctx.url, ctx.response),
|
|
2947
2480
|
"work": async (ctx) => retiredRedirect("work", ctx.url, ctx.response),
|
|
2948
2481
|
"next": async (ctx) => retiredRedirect("next", ctx.url, ctx.response),
|
|
2949
2482
|
"board": async (ctx) => retiredRedirect("board", ctx.url, ctx.response),
|
|
2950
|
-
// A result keeps its own page; the bare list moved to Tasks' Ready view.
|
|
2951
2483
|
"review": async (ctx) => ctx.url.searchParams.has("result") ? showReview(ctx) : retiredRedirect("review", ctx.url, ctx.response),
|
|
2952
2484
|
"done": async (ctx) => retiredRedirect("done", ctx.url, ctx.response),
|
|
2953
2485
|
"tasks": showTasks,
|
|
@@ -3018,33 +2550,26 @@ export function createTasksHandlers(runtime) {
|
|
|
3018
2550
|
"session.editor-links": sessionEditorLinks,
|
|
3019
2551
|
"incident.resolve": resolveIncident,
|
|
3020
2552
|
});
|
|
3021
|
-
/** The add page, once more: blank, from a shipped template (`?template=`, as the old task list did), or with a refused
|
|
3022
|
-
* filing's own words and status (the draft keeps the project revision it was written against). */
|
|
3023
2553
|
function newTaskScreen(ctx, status, problem, draft, text = null) {
|
|
3024
2554
|
const { who, response, project } = ctx;
|
|
3025
2555
|
const chainable = store
|
|
3026
2556
|
.listTasksScoped(project, undefined, 100, null)
|
|
3027
2557
|
.filter(one => one.state !== "done" && one.state !== "cancelled" && visible(one.repo))
|
|
3028
2558
|
.map(one => ({ id: one.id, title: one.title }));
|
|
3029
|
-
// A refused draft keeps the task it was to start after, even if the refreshed list no longer carries it.
|
|
3030
2559
|
const after = draft?.values?.get("after") ?? "";
|
|
3031
2560
|
if (after !== "" && !chainable.some(one => one.id === after))
|
|
3032
2561
|
chainable.unshift({ id: after, title: "(as submitted)" });
|
|
3033
2562
|
const chrome = chromeFor(project, "tasks");
|
|
3034
2563
|
const revision = draft?.values !== undefined ? undefined : who.via === "cookie" ? who.session.projectRevision : 0;
|
|
3035
|
-
// Ideas for the project the box starts on: what the first run found there (issues, TODOs), else the safe generic
|
|
3036
|
-
// ones while the first run is open; none once someone has filed work and nothing was found.
|
|
3037
2564
|
const startsOn = draft?.values?.get("repo") ?? project ?? chrome.projects?.[0]?.path ?? null;
|
|
3038
2565
|
const found = startsOn === null ? null : runtime.firstTasks.get(startsOn)?.found ?? null;
|
|
3039
2566
|
const ideas = found ?? (runtime.firstRunStepsNow(ctx.now) !== null && !store.hasAnyWork() ? firstTaskSuggestions({ issues: [], todos: [] }) : []);
|
|
3040
2567
|
return sendScreen(response, status, newTaskPage(chrome, project, revision, problem, chainable, store.permissionDefault().mode, store.qualityDefault().mode, chrome.projects ?? [], draft, text, ideas, ctx.url.searchParams.get("from")?.slice(0, 300) ?? null));
|
|
3041
2568
|
}
|
|
3042
|
-
/** What the password rule reads for this request (approval-password.ts), the same facts the approve forms read. */
|
|
3043
2569
|
function fastPasswordFacts(who) {
|
|
3044
2570
|
return { passwordless: passwordlessSessionFor(store, who.name), localOwner: who.via === "cookie" && who.authority === "local-owner",
|
|
3045
2571
|
freshAt: withFreshness("approve-standard", () => freshnessFor(who.name, Date.now(), true))?.at ?? null, returnTo: "/tasks/new" };
|
|
3046
2572
|
}
|
|
3047
|
-
/** Build: the fast start's one write. Every check is made again inside fastStartBuild's transaction. */
|
|
3048
2573
|
async function buildNow(ctx) {
|
|
3049
2574
|
const { who, response, now, posted } = ctx;
|
|
3050
2575
|
const body = readForm(posted, CONSOLE_FORMS.tasksFast);
|
|
@@ -3064,7 +2589,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3064
2589
|
actionContext.createdTask = built.taskId;
|
|
3065
2590
|
return redirect(response, taskHref(built.taskId));
|
|
3066
2591
|
}
|
|
3067
|
-
/** "Approve it to keep it": a fast start that grew gets a plan for its exact commit, on the ordinary approval. It seals nothing. */
|
|
3068
2592
|
async function keepGrown(ctx) {
|
|
3069
2593
|
const { url, who, response, now, posted } = ctx;
|
|
3070
2594
|
readForm(posted, CONSOLE_FORMS.keepGrown);
|
|
@@ -3076,8 +2600,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3076
2600
|
return taskScreen(response, who, act.taskId, kept.message, 409);
|
|
3077
2601
|
return redirect(response, taskHref(act.taskId));
|
|
3078
2602
|
}
|
|
3079
|
-
/** Findings, a failed check's repair and evidence (render-follow-through.ts). Nothing here is an approval: a repair is a
|
|
3080
|
-
* draft, and its task page asks for the plan's approval as any other. */
|
|
3081
2603
|
async function followThroughAct(ctx) {
|
|
3082
2604
|
const { url, who, response, now, posted } = ctx;
|
|
3083
2605
|
const body = readForm(posted, CONSOLE_FORMS.followThrough);
|
|
@@ -3085,13 +2607,11 @@ export function createTasksHandlers(runtime) {
|
|
|
3085
2607
|
if (act === null)
|
|
3086
2608
|
return noPage(who, response);
|
|
3087
2609
|
const { taskId } = act;
|
|
3088
|
-
// Chat's gate, here too (findings.ts familyInReach): every project in this task's family, not only this page's.
|
|
3089
2610
|
if (familyInWebReach(store, who, taskId, visible) === null)
|
|
3090
2611
|
return refuse(response, who, 403, "That task is outside your access.", "/tasks");
|
|
3091
2612
|
const number = (name) => Number(body.get(name) ?? "");
|
|
3092
2613
|
const back = () => redirect(response, `${taskHref(taskId)}#findings`);
|
|
3093
2614
|
const refused = (message) => taskScreen(response, who, taskId, message, 409);
|
|
3094
|
-
/** A finding or a run named by a form must belong to this task's family: this page's project was the one admitted. */
|
|
3095
2615
|
const ownFinding = () => { const found = getFinding(store, number("finding")); return found !== null && found.familyRoot === familyRootOf(store, taskId) ? found : null; };
|
|
3096
2616
|
const ownRun = () => runOnTask(store, number("run"), taskId);
|
|
3097
2617
|
switch (body.get("act")) {
|
|
@@ -3149,9 +2669,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3149
2669
|
}
|
|
3150
2670
|
return { registrations, runListPane, peekFragment, taskMutation, queueRegionFor, ciFailingFor, completedRowFor, attemptRowFor, resultRowOf, reviewCockpitViewOf, decisionEvidence, runEvidence, sendArtifact, peekGuards, liveRunIds };
|
|
3151
2671
|
}
|
|
3152
|
-
/** Put away and Restore one task, and Put away old tasks (docs/plans/task-tidy.md): the preview reads only (GET-quiet);
|
|
3153
|
-
* putting away many is an approver's step-up bound to the digest of exactly what the preview showed. Each write
|
|
3154
|
-
* re-proves the person's standing inside its own transaction. */
|
|
3155
2672
|
export function createTidyHandlers(runtime) {
|
|
3156
2673
|
const { store, sendScreen, chromeFor, authenticateApprover, workAccess, bustBadge } = runtime;
|
|
3157
2674
|
async function showPutAway(ctx) {
|
|
@@ -3198,19 +2715,11 @@ export function createTidyHandlers(runtime) {
|
|
|
3198
2715
|
return { "tasks.archive": showPutAway, "work.put-away": async (ctx) => retiredRedirect("work.put-away", ctx.url, ctx.response),
|
|
3199
2716
|
"work.put-away.apply": applyPutAway, "task.act.archive": oneTask("archive"), "task.act.restore": oneTask("restore") };
|
|
3200
2717
|
}
|
|
3201
|
-
/** A retired page's GET alias: a plain 302 (the shared 303 helper belongs to POST landings), as pages.ts morningAlias. */
|
|
3202
2718
|
function redirectGet(response, to) {
|
|
3203
2719
|
response.writeHead(302, { ...SAFETY, Location: to });
|
|
3204
2720
|
response.end();
|
|
3205
2721
|
}
|
|
3206
|
-
/** How many cards a Board column shows; the column's count covers them all and its "View all" opens the list. */
|
|
3207
2722
|
export const BOARD_COLUMN_LIMIT = 40;
|
|
3208
|
-
/**
|
|
3209
|
-
* Easy-start C1 (N1): the two writes a page load used to make, as keyed POSTs the shell sends (wave 1c wires the
|
|
3210
|
-
* browser). `agents.seen`: a finished result this person opened leaves their unread Done. `agents.watch`: hold (on each
|
|
3211
|
-
* keep-alive) or release (on unload) the short lease that quiets chat pings while this person's page shows the agent.
|
|
3212
|
-
* Each re-proves the run is in the person's projects; a reply carries nothing else.
|
|
3213
|
-
*/
|
|
3214
2723
|
export function createAgentSignalHandlers(runtime) {
|
|
3215
2724
|
const { store, runVisible } = runtime;
|
|
3216
2725
|
const answer = (response, status, ok) => respond(response, status, "application/json", JSON.stringify({ ok }));
|
|
@@ -3225,7 +2734,6 @@ export function createAgentSignalHandlers(runtime) {
|
|
|
3225
2734
|
const run = visibleRun(who, readForm(posted, CONSOLE_FORMS.agentSeen).get("run"));
|
|
3226
2735
|
if (run === null)
|
|
3227
2736
|
return answer(response, 404, false);
|
|
3228
|
-
// Only once it finished: a page shown while it ran saw no finished version (cockpit §3).
|
|
3229
2737
|
if (run.finishedAt === null)
|
|
3230
2738
|
return answer(response, 409, false);
|
|
3231
2739
|
markAgentSeen(store, who.name, run.id, now);
|
|
@@ -3249,17 +2757,9 @@ export function createAgentSignalHandlers(runtime) {
|
|
|
3249
2757
|
}
|
|
3250
2758
|
return { "agents.seen": agentSeen, "agents.watch": agentWatch };
|
|
3251
2759
|
}
|
|
3252
|
-
/**
|
|
3253
|
-
* One-tap release approval (docs/plans/trusted-release-reports.md, slice A): the sheet (`/t/<id>/release`), the push's
|
|
3254
|
-
* opaque locator (`/approve/<task ref>`, a GET that only redirects to the sheet) and the sheet's approval, which the
|
|
3255
|
-
* task approval POST hands here once its shared checks (cookie session, CSRF and the browser key at admission, the
|
|
3256
|
-
* single-use nonce, a password or a standing proof) passed. The approval itself is the shared card wrapper around the
|
|
3257
|
-
* unchanged approve() (release-approval.ts approveReleaseCard).
|
|
3258
|
-
*/
|
|
3259
2760
|
export function createReleaseSheetHandlers(runtime) {
|
|
3260
2761
|
const { store, sendScreen, chromeFor, visible, mintApprovalNonce, clock, authenticateApprover } = runtime;
|
|
3261
2762
|
const missing = (who, response) => refuse(response, who, 404, "There's no release waiting for approval at this address.", "/work");
|
|
3262
|
-
/** The sheet, with a problem said where it happened. */
|
|
3263
2763
|
function sheetScreen(ctx, taskId, problem, status) {
|
|
3264
2764
|
const { who, response, project } = ctx;
|
|
3265
2765
|
const ref = store.lookupRef(taskId);
|
|
@@ -3270,7 +2770,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3270
2770
|
return missing(who, response);
|
|
3271
2771
|
const card = built.card;
|
|
3272
2772
|
const open = card.approved === null && card.refusal === null;
|
|
3273
|
-
// This computer's local owner can't approve a release: the full sign-in comes first (scope.ts localApprovalEligible).
|
|
3274
2773
|
const local = who.via === "cookie" && who.authority === "local-owner" ? localOwnerRefusal(store.accountOf(who.name)?.passwordSet === true, releaseSheetHref(taskId)) : null;
|
|
3275
2774
|
const nonce = open && local === null && who.via === "cookie" && who.role === "approver" ? mintApprovalNonce(who.name, taskId, card.digest) : "";
|
|
3276
2775
|
const remembered = (() => {
|
|
@@ -3290,7 +2789,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3290
2789
|
return missing(ctx.who, ctx.response);
|
|
3291
2790
|
return sheetScreen(ctx, task.taskId, null, 200);
|
|
3292
2791
|
}
|
|
3293
|
-
/** The push's locator: proved a release in the person's projects from the plane's own state, then only redirected. */
|
|
3294
2792
|
async function locate(ctx) {
|
|
3295
2793
|
const { who, response, url } = ctx;
|
|
3296
2794
|
const raw = /^\/approve\/([1-9][0-9]{0,14})$/.exec(url.pathname)?.[1];
|
|
@@ -3299,7 +2797,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3299
2797
|
return missing(who, response);
|
|
3300
2798
|
return redirect(response, releaseSheetHref(ref.externalId));
|
|
3301
2799
|
}
|
|
3302
|
-
/** The sheet's Approve release, after the approval POST's shared checks. */
|
|
3303
2800
|
function approveFromSheet(ctx, taskId, cardDigest, token) {
|
|
3304
2801
|
const { who, response } = ctx;
|
|
3305
2802
|
const now = clock();
|
|
@@ -3315,7 +2812,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3315
2812
|
return sheetScreen(ctx, taskId, refused.message, 403);
|
|
3316
2813
|
return sheetScreen(ctx, taskId, approveRefusalWords(refused.reason), refused.reason === "changed" || refused.reason === "unrouted" ? 409 : 403);
|
|
3317
2814
|
}
|
|
3318
|
-
/** A held automatic release goes on: a person only, proved now. The watch then resumes it (release-next.ts). */
|
|
3319
2815
|
async function goOn(ctx) {
|
|
3320
2816
|
const { who, url, posted, now, response } = ctx;
|
|
3321
2817
|
const body = readForm(posted, CONSOLE_FORMS.releaseGoOn);
|
|
@@ -3334,8 +2830,18 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3334
2830
|
}
|
|
3335
2831
|
return { routes: { "task.release": showSheet, "task.release.go-on": goOn, "release.locate": locate }, sheetScreen, approveFromSheet };
|
|
3336
2832
|
}
|
|
3337
|
-
/** The answer to an approval asked in place: its named outcome and the same words the page would show, as JSON. Written
|
|
3338
|
-
* only after the approve route's proofs, by the caller that knows the outcome. */
|
|
3339
2833
|
export function answerApprovalInPlace(response, outcome, words, status) {
|
|
3340
2834
|
respond(response, status, "application/json; charset=utf-8", JSON.stringify({ outcome, words }));
|
|
3341
2835
|
}
|
|
2836
|
+
export function localOwnerPlan(store, taskId, source, now) {
|
|
2837
|
+
if (typeof source !== "string" || !/^[a-f0-9]{64}$/.test(source))
|
|
2838
|
+
return { ok: false, status: 409, message: LOCAL_TASK_CHANGED };
|
|
2839
|
+
const done = requestPlanAsLocalOwner(store, taskId, source, now);
|
|
2840
|
+
return done.ok ? { ok: true } : { ok: false, status: done.reason === "local-owner" || done.reason === "refused" ? 403 : 409, message: done.message };
|
|
2841
|
+
}
|
|
2842
|
+
export function localOwnerRetry(store, taskId, run, digest, now) {
|
|
2843
|
+
if (typeof run !== "string" || !/^[1-9][0-9]{0,14}$/.test(run) || typeof digest !== "string" || !/^[a-f0-9]{32}$/.test(digest))
|
|
2844
|
+
return { ok: false, status: 409, message: LOCAL_TASK_CHANGED };
|
|
2845
|
+
const done = retryAsLocalOwner(store, taskId, { run: Number(run), digest }, now);
|
|
2846
|
+
return done.ok ? { ok: true, replayed: done.replayed } : { ok: false, status: done.reason === "local-owner" || done.reason === "refused" || done.reason === "limit" ? 403 : 409, message: done.message };
|
|
2847
|
+
}
|