toolroll 0.9.104 → 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 +62 -5
- package/README.md +18 -20
- 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 +17 -139
- 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 +1 -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 +0 -17
- 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 +0 -53
- package/dist/local-owner.js +2 -93
- 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 +0 -17
- package/dist/operate-remote.js +0 -33
- package/dist/operate.js +227 -2326
- 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 +0 -20
- 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 +0 -34
- package/dist/public-check.js +0 -16
- package/dist/publish.js +1 -150
- package/dist/pull-request-flow.js +0 -77
- 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 +0 -100
- 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 +0 -25
- 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 +4 -567
- 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 +21 -555
- 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 +1 -88
- 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 +13 -493
- 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 +6 -135
- 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 +9 -227
- package/dist/server/tasks.js +5 -539
- 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 +0 -75
- 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 +17 -28
- 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 +16 -36
- package/dist/tui.js +1 -1
- 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 +4 -3
- 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 -350
- 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 -1985
- 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 -540
- 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 -43
- 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-acts.d.ts +0 -83
- package/dist/local-owner.d.ts +0 -135
- 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 -61
- 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 -170
- 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 -39
- 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 -1098
- 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 -81
- 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 -60
- 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 -758
- package/dist/server/render-settings.d.ts +0 -93
- package/dist/server/render-tasks.d.ts +0 -783
- 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 -343
- 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 -108
- 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 -48
- 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 -202
- 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";
|
|
@@ -94,12 +93,9 @@ import { approvalFactsNow } from "./kit.js";
|
|
|
94
93
|
import { localOwnerRefusal } from "../local-owner.js";
|
|
95
94
|
export function createTasksHandlers(runtime) {
|
|
96
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;
|
|
97
|
-
/** A row admitted the address but its path parameter does not parse: the console's unknown page. */
|
|
98
96
|
function noPage(who, response) {
|
|
99
97
|
return refuse(response, who, 404, "There's no page at this address.", "/chat");
|
|
100
98
|
}
|
|
101
|
-
// `posted`: the session page's own POST (form token). A GET of changes or the shipping preview runs no git in the
|
|
102
|
-
// agent's checkout: changes go back to the session page, the preview asks for one click.
|
|
103
99
|
const showCode = (part, posted = false) => async (ctx) => {
|
|
104
100
|
const { url, who, response, project } = ctx;
|
|
105
101
|
if (who.via !== 'cookie' || !codingActorAllowed({ name: who.name, generation: who.session.generation }))
|
|
@@ -155,14 +151,7 @@ export function createTasksHandlers(runtime) {
|
|
|
155
151
|
};
|
|
156
152
|
async function showWork(ctx) {
|
|
157
153
|
const { url, who, response, now, project } = ctx;
|
|
158
|
-
// The Work destination (workspace package 1): every task in view as
|
|
159
|
-
// one row wearing the shared status projection, with All, Needs you,
|
|
160
|
-
// Running, and Completed as shortcuts over the same rows — never a
|
|
161
|
-
// persisted state. With no project open in scoped mode this rolls
|
|
162
|
-
// up like the inbox: admission binds the query and every row's repo
|
|
163
|
-
// is re-proved here.
|
|
164
154
|
const view = parseWorkView(url.searchParams.get("view"));
|
|
165
|
-
// The stored-state filter the old task list had (`?state=`): an unknown state is refused, as it was there.
|
|
166
155
|
const wantedState = url.searchParams.get("state");
|
|
167
156
|
if (wantedState !== null && !TASK_STATES.includes(wantedState))
|
|
168
157
|
return refuse(response, who, 400, "no such state", "/tasks");
|
|
@@ -172,10 +161,7 @@ export function createTasksHandlers(runtime) {
|
|
|
172
161
|
try {
|
|
173
162
|
work = workIndexPage(store, now, workAccess(), { view, limit: 40, cursor: url.searchParams.get('cursor'), project, root: evidenceRoot, ...(state === null ? {} : { state }) });
|
|
174
163
|
const facts = requestContext.getStore();
|
|
175
|
-
// A filtered page never stands in for the counts or the Crew: those read the unfiltered work.
|
|
176
164
|
if (facts !== undefined && state === null) {
|
|
177
|
-
// These counts cover the exact admitted project lens, including
|
|
178
|
-
// unplaced tasks where permitted. Crew excludes unplaced rows.
|
|
179
165
|
if (project === null)
|
|
180
166
|
facts.workCounts = work.projects;
|
|
181
167
|
const admitted = workAccess().repos;
|
|
@@ -189,10 +175,6 @@ export function createTasksHandlers(runtime) {
|
|
|
189
175
|
return refuse(response, who, 400, 'This task page has expired. Open the first page.', '/tasks');
|
|
190
176
|
throw error;
|
|
191
177
|
}
|
|
192
|
-
// A failed row says what its latest attempt missed, as its task page does (a stop reason already reads so), from
|
|
193
|
-
// 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
|
|
194
|
-
// stuck on, from that live attempt's own progress only, never a stopped attempt's; the step's words come from its
|
|
195
|
-
// current plan (one saved file, for live rows only), and without it the row names the step by number.
|
|
196
178
|
const enrich = (page) => ({ ...page, items: page.items.map((item) => {
|
|
197
179
|
if (item.liveRunId !== null) {
|
|
198
180
|
const ref = store.lookupRef(item.activeTaskId);
|
|
@@ -214,7 +196,6 @@ export function createTasksHandlers(runtime) {
|
|
|
214
196
|
return failure.kind === "reason" ? item : { ...item, status: { ...item.status, detail: failure.line } };
|
|
215
197
|
}) });
|
|
216
198
|
work = enrich(work);
|
|
217
|
-
// The Board view: the same index as four columns (needs you, queued, running, finished), never a second classifier.
|
|
218
199
|
const board = url.searchParams.get("layout") !== "board" ? null : (() => {
|
|
219
200
|
const column = (view) => enrich(workIndexPage(store, now, workAccess(), { view, limit: BOARD_COLUMN_LIMIT, project, root: evidenceRoot, ...(state === null ? {} : { state }) }));
|
|
220
201
|
return { needs: column("needs-you"), queued: column("queued"), running: column("running"), finished: column("completed") };
|
|
@@ -231,69 +212,50 @@ export function createTasksHandlers(runtime) {
|
|
|
231
212
|
now,
|
|
232
213
|
state,
|
|
233
214
|
canPutAway: who.via === "cookie" && who.role === "approver",
|
|
234
|
-
|
|
235
|
-
limits: store.isInstanceOperator(who.name)
|
|
215
|
+
limits: store.isInstanceOperator(who.name) && advancedShownNow()
|
|
236
216
|
? limitsView(store.providerLimits(), store.budgets().length === 0 ? [] : store.monthSpendCached(now).budgets, { project: projectName, subagent: id => subagentNamesOf(store.handle).get(id) ?? `Subagent ${id}` }, now)
|
|
237
217
|
: null,
|
|
238
218
|
});
|
|
239
|
-
// One project's Tasks dock that project's own conversation (v77).
|
|
240
219
|
const projectThread = url.searchParams.has('project') && project !== null && managedRepos().includes(project) ? project : null;
|
|
241
220
|
const docked = projectThread === null ? null : dockedConversation(who, null, projectThread, now, `/tasks?project=${encodeURIComponent(projectThread)}`);
|
|
242
221
|
if (docked !== null)
|
|
243
222
|
page.workspace = { ...page.workspace, conversation: docked, pageHtml: page.body };
|
|
244
|
-
// Without a docked chat the list reads itself: 10 s while any of its tasks is building, else 30 s.
|
|
245
223
|
page.refreshSeconds = work.totals.running > 0 ? 10 : 30;
|
|
246
224
|
return sendScreen(response, 200, page);
|
|
247
225
|
}
|
|
248
|
-
/** A completed (or attempted) row as the review list ranks it: its proof reasons, CI standing, and the assignment
|
|
249
|
-
* when that assignment's receipt is this very row. */
|
|
250
226
|
function reviewRowOf(row, now) {
|
|
251
227
|
const assignment = assignmentOf(store, row.taskId, now, workAccess(), evidenceRoot);
|
|
252
228
|
return { ...row, proofReasons: row.runId === null ? [] : store.proofVerdictFor(row.runId)?.reasons ?? [], ciFailing: ciFailingFor(row.runId, row.prNumber),
|
|
253
229
|
assignment: assignment?.activeTaskId === row.taskId && (assignment.receipt?.runId ?? null) === row.runId ? assignment : null };
|
|
254
230
|
}
|
|
255
|
-
/** The result a link names (the task's own result, or the exact run `namedRun` of it): its completed row when the
|
|
256
|
-
* task is done (`inQueue` when the review list already holds it), else that attempt's own result (a failed or stopped
|
|
257
|
-
* build has a result page too), with what went wrong and Retry / Accept anyway as the review page offers them.
|
|
258
|
-
* Shared by /review and the task page's Result tab (docs/plans/one-page-task-and-agent.md). */
|
|
259
231
|
function selectResultFor(wantedId, namedRun, project, who, now, inQueue = null) {
|
|
260
232
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
261
233
|
const beyond = inQueue !== null ? null : completedRowFor(wantedId, project);
|
|
262
234
|
const beyondRow = beyond === null ? null : reviewRowOf(beyond, now);
|
|
263
235
|
const completedChoice = inQueue ?? (beyondRow === null ? null : { ...beyondRow, priority: reviewPriorityOf(beyondRow) });
|
|
264
|
-
// A build that failed (or stopped) has its own result page too: the run named, or a failed task's latest attempt.
|
|
265
236
|
const attempt = (completedChoice !== null && (namedRun === null || completedChoice.runId === namedRun)) ? null : attemptRowFor(wantedId, namedRun, project);
|
|
266
237
|
const attemptRow = attempt === null ? null : reviewRowOf(attempt, now);
|
|
267
238
|
const chosen = attemptRow !== null ? { ...attemptRow, priority: reviewPriorityOf(attemptRow) } : completedChoice;
|
|
268
239
|
const selected = chosen === null ? null : reviewCockpitViewOf(chosen, who, now);
|
|
269
|
-
// A build that delivered nothing reads Failed here, and so does a failed task's delivered result: what went wrong
|
|
270
|
-
// is the card and Retry the ink act. That result may still be accepted, but only in outline, as Accept anyway, with
|
|
271
|
-
// a reason.
|
|
272
240
|
const delivered = selected?.run?.outcome === "built" || selected?.run?.outcome === "no-change";
|
|
273
241
|
const failedTask = selected === null ? null : store.getTask(selected.taskId);
|
|
274
242
|
if (selected !== null && attemptRow !== null && selected.run !== null && (!delivered || failedTask?.state === "failed")) {
|
|
275
243
|
const attemptRun = store.getRun(selected.run.id);
|
|
276
244
|
const runs = attemptRun === null ? [] : store.runsFor(attemptRun.taskRef);
|
|
277
245
|
const latest = latestFinishedAttempt(runs);
|
|
278
|
-
// Retry from here only when the task failed, nothing holds it, and this is its latest attempt or a result it delivered.
|
|
279
246
|
const retry = failedTask?.state === "failed" && (latest?.id === selected.run.id || delivered) && csrf !== "" && who.role === "approver" && store.currentLiveLease(attemptRun.taskRef, now) === null
|
|
280
247
|
? { action: `${taskHref(selected.taskId)}/requeue`, pins: retryPinsOf(store, selected.taskId) } : null;
|
|
281
|
-
// Accept anyway: the same acceptance this task's latest result takes, never for an older one or one already accepted.
|
|
282
248
|
const family = delivered ? familyOf(selected.taskId) : null;
|
|
283
249
|
const acceptAnyway = delivered && csrf !== "" && who.role === "approver" && family?.current.id === selected.taskId && family.problem === null &&
|
|
284
250
|
runs.find(runIsTaskResult)?.id === selected.run.id && store.proofAcceptance(selected.run.id) === null
|
|
285
251
|
? { action: `${taskHref(selected.taskId)}/accept-proof`, run: selected.run.id } : null;
|
|
286
252
|
if (attemptRun !== null) {
|
|
287
|
-
// A delivered result didn't fail itself: the task's failure is its latest attempt's.
|
|
288
253
|
const failure = delivered ? failureOf(runs, null) : explainAttempt(attemptRun, null);
|
|
289
254
|
selected.failure = { ...failure, retry: retry === null ? null : { ...retry, note: retryNoteOf(failure.suggestion) }, ...(acceptAnyway === null ? {} : { acceptAnyway }) };
|
|
290
255
|
}
|
|
291
256
|
}
|
|
292
257
|
return { chosen, attemptRow, beyond, selected };
|
|
293
258
|
}
|
|
294
|
-
/** Whether `run` is a result selectResultFor shows for version `taskId`: a finished attempt that didn't deliver (failed,
|
|
295
|
-
* stopped, refused…), or the delivered one that is the version's own result — its completed row's, or, for a failed
|
|
296
|
-
* version, its latest finished attempt. An older delivered build is not (its version's result is the newer one). */
|
|
297
259
|
function resultRunAdmissible(taskId, run, project) {
|
|
298
260
|
if ((run.role !== "builder" && run.role !== "scout") || (run.finishedAt === null && run.outcome === null) || runIsLive(run))
|
|
299
261
|
return false;
|
|
@@ -304,21 +266,12 @@ export function createTasksHandlers(runtime) {
|
|
|
304
266
|
return latestFinishedAttempt(store.runsFor(run.taskRef).filter(one => (one.role === "builder" || one.role === "scout") && (one.finishedAt !== null || one.outcome !== null)))?.id === run.id;
|
|
305
267
|
return completedRowFor(taskId, project)?.runId === run.id;
|
|
306
268
|
}
|
|
307
|
-
/** A run's own task and its family's root: the task pages a result form may return to. */
|
|
308
269
|
function runTasks(taskRef) {
|
|
309
270
|
const task = store.externalIdFor(taskRef);
|
|
310
271
|
return task === null ? [] : [task, familyOf(task)?.root.id ?? task];
|
|
311
272
|
}
|
|
312
273
|
async function showReview(ctx) {
|
|
313
274
|
const { url, who, response, now, project, chosenProject } = ctx;
|
|
314
|
-
// The review cockpit (Priority 5): every visible COMPLETED task,
|
|
315
|
-
// ranked by review priority, with one selected result projected
|
|
316
|
-
// from the records the task, run, and done pages already read —
|
|
317
|
-
// scope, plan, run, artifacts, verdict, publication. The
|
|
318
|
-
// ranking is a labeled presentation aid: it never rewrites the
|
|
319
|
-
// stored verdict, and the sealed patch downloads exactly as stored.
|
|
320
|
-
// Admission binds BEFORE the SQL limit (the done page's own rule),
|
|
321
|
-
// and every row is re-proved against the ceiling before ranking.
|
|
322
275
|
const resultRow = (row) => reviewRowOf(row, now);
|
|
323
276
|
const rows = familiesInView(project, { states: ["done"], limit: REVIEW_QUEUE_CAP }).flatMap(family => {
|
|
324
277
|
const row = completedRowFor(family.current.id, project);
|
|
@@ -328,34 +281,23 @@ export function createTasksHandlers(runtime) {
|
|
|
328
281
|
const wanted = url.searchParams.get("result");
|
|
329
282
|
const wantedId = wanted === null || wanted.length === 0 || wanted.length > 64 || hasForbiddenControls(wanted) ? null : wanted;
|
|
330
283
|
const inQueue = wantedId === null ? null : ranked.find(one => one.taskId === wantedId) ?? null;
|
|
331
|
-
// A stable deep link outlives the queue window (v2 review, comment
|
|
332
|
-
// 1): a completion older than the newest REVIEW_QUEUE_CAP resolves
|
|
333
|
-
// directly — re-proved as done, in this project, and inside the
|
|
334
|
-
// ceiling — so an old receipt never reads as unfinished or foreign.
|
|
335
|
-
// The ranked queue itself stays bounded and says so.
|
|
336
284
|
const expectedRun = url.searchParams.get("run");
|
|
337
285
|
const namedRun = expectedRun !== null && /^[1-9]\d*$/.test(expectedRun) ? Number(expectedRun) : null;
|
|
338
286
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
339
287
|
const picked = wantedId === null ? null : selectResultFor(wantedId, namedRun, project, who, now, inQueue);
|
|
340
288
|
const chosen = picked?.chosen ?? null, attemptRow = picked?.attemptRow ?? null, beyond = picked?.beyond ?? null;
|
|
341
289
|
const selectedRow = wantedId === null ? ranked[0] ?? null : chosen;
|
|
342
|
-
// An exact link to a result this person can't see (or that never existed) reads the same either way.
|
|
343
290
|
if (expectedRun !== null && wantedId !== null && chosen === null)
|
|
344
291
|
return refuse(response, who, 404, "No such result in your projects.", "/tasks");
|
|
345
292
|
if (expectedRun !== null && (!/^[1-9]\d*$/.test(expectedRun) || selectedRow?.runId !== Number(expectedRun))) {
|
|
346
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") }));
|
|
347
294
|
}
|
|
348
295
|
const selected = picked !== null ? picked.selected : selectedRow === null ? null : reviewCockpitViewOf(selectedRow, who, now);
|
|
349
|
-
// Opening a run's own result page is viewing it: the shell says so with a keyed POST /agents/seen (easy-start N1:
|
|
350
|
-
// a page load never writes), which leaves this person's unread Done once the run has finished.
|
|
351
296
|
const reviewPage = reviewCockpitPage(chromeFor(wantedId === null ? project : chosenProject, "runs"), {
|
|
352
297
|
queue: ranked,
|
|
353
298
|
queueCap: REVIEW_QUEUE_CAP,
|
|
354
299
|
selected,
|
|
355
300
|
beyondQueue: beyond !== null && attemptRow === null,
|
|
356
|
-
// A deep link to a result this console cannot show — not done,
|
|
357
|
-
// not admitted, or never existed — says so in one sentence and
|
|
358
|
-
// shows the top of the queue; the three cases read identically.
|
|
359
301
|
missing: wantedId !== null && chosen === null ? wantedId : null,
|
|
360
302
|
csrf,
|
|
361
303
|
canRetryReview: who.via === "cookie" && who.role === "approver",
|
|
@@ -365,8 +307,6 @@ export function createTasksHandlers(runtime) {
|
|
|
365
307
|
user: who.name,
|
|
366
308
|
now,
|
|
367
309
|
});
|
|
368
|
-
// The result's task conversation, docked beside it (v77); messages
|
|
369
|
-
// sent here carry the result being viewed.
|
|
370
310
|
const reviewFocus = selected === null ? null : taskChatFocus(selected.taskId, now, who, { mintNonce: false });
|
|
371
311
|
const reviewDocked = reviewFocus === null || selected === null ? null
|
|
372
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);
|
|
@@ -374,11 +314,6 @@ export function createTasksHandlers(runtime) {
|
|
|
374
314
|
reviewPage.workspace = { ...reviewPage.workspace, conversation: reviewDocked, pageHtml: reviewPage.body };
|
|
375
315
|
return sendScreen(response, 200, reviewPage);
|
|
376
316
|
}
|
|
377
|
-
/** The old task list, retired into /work (docs/plans/reui-polish.md slice 7): its address keeps answering, as a
|
|
378
|
-
* redirect, so links and bookmarks still land. `state` carries over (an unknown one is still refused); `template`
|
|
379
|
-
* goes to the add page, which now pre-fills it. Anything else is dropped. */
|
|
380
|
-
/** Tasks (docs/plans/plain-toolroll.md P1.4): the one list, with List, Board, Ready, Archived and an every-project
|
|
381
|
-
* scope (`scope=all`). `view=board` is the Board, `view=order` the queue's order, `view=done` Finished. */
|
|
382
317
|
async function showTasks(ctx) {
|
|
383
318
|
const { url } = ctx;
|
|
384
319
|
const template = url.searchParams.get("template");
|
|
@@ -387,7 +322,6 @@ export function createTasksHandlers(runtime) {
|
|
|
387
322
|
const view = url.searchParams.get("view");
|
|
388
323
|
if (view === "order")
|
|
389
324
|
return showOrder(ctx);
|
|
390
|
-
// The list reads its own keys: Board is its layout, every project its roll-up, Finished its completed view.
|
|
391
325
|
const read = new URL(url.href);
|
|
392
326
|
if (view === "board") {
|
|
393
327
|
read.searchParams.delete("view");
|
|
@@ -401,7 +335,6 @@ export function createTasksHandlers(runtime) {
|
|
|
401
335
|
}
|
|
402
336
|
return showWork({ ...ctx, url: read });
|
|
403
337
|
}
|
|
404
|
-
/** The queue's order view, under Tasks: dispatch order with drag handles (scheduling, never authority). */
|
|
405
338
|
async function showOrder(ctx) {
|
|
406
339
|
const { url, who, response, project } = ctx;
|
|
407
340
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
@@ -416,8 +349,6 @@ export function createTasksHandlers(runtime) {
|
|
|
416
349
|
html `<p class="meta" id="queue-region-stamp"></p>`,
|
|
417
350
|
], "\n"), { chrome: chromeFor(project, "work"), functional: { script: queueScript(), fetches: true } }));
|
|
418
351
|
}
|
|
419
|
-
/** /n/<number>: a push's task link, by the task's stored number, never its title. It opens the task's page only
|
|
420
|
-
* inside the viewer's own projects; anything else is the same not-found as an unknown number. */
|
|
421
352
|
async function showNumberedTask(ctx) {
|
|
422
353
|
const { url, who, response } = ctx;
|
|
423
354
|
const number = Number(url.pathname.slice("/n/".length));
|
|
@@ -433,7 +364,6 @@ export function createTasksHandlers(runtime) {
|
|
|
433
364
|
const prefill = picked !== null && picked.kind === "task"
|
|
434
365
|
? { title: picked.title, goal: picked.goal, not: picked.outOfScope ?? "", touches: picked.touches.join(", "), acceptance: acceptanceToLines(picked.acceptance).join("\n") }
|
|
435
366
|
: null;
|
|
436
|
-
// An idea's link (or any ?text=) puts words in the box: bounded to what the box takes, nothing filed.
|
|
437
367
|
const text = ctx.url.searchParams.get("text");
|
|
438
368
|
return newTaskScreen(ctx, 200, null, prefill, text === null ? null : text.slice(0, 200));
|
|
439
369
|
}
|
|
@@ -448,24 +378,17 @@ export function createTasksHandlers(runtime) {
|
|
|
448
378
|
const version = url.searchParams.get("version");
|
|
449
379
|
if (version !== null && !family.versions.some(one => one.id === version))
|
|
450
380
|
return refuse(response, who, 404, "That version is not available for this task.", taskHref(family.root.id));
|
|
451
|
-
// A version's own address lands on its family's page, still asking for the plan editor when it did (Chat's Edit plan).
|
|
452
381
|
if (task.taskId !== family.root.id) {
|
|
453
|
-
// Everything else the address asked for (its tab, result run and view, a form's feedback) rides along.
|
|
454
382
|
const kept = new URLSearchParams(url.searchParams);
|
|
455
383
|
kept.delete("version");
|
|
456
384
|
return redirect(response, `${taskHref(family.root.id)}?version=${encodeURIComponent(task.taskId)}${kept.size === 0 ? "" : `&${kept.toString()}`}`);
|
|
457
385
|
}
|
|
458
|
-
// One page per task (docs/plans/one-page-task-and-agent.md): the tab named, and the Result tab's result — the shown
|
|
459
|
-
// version's own, or the exact run `run=` names, which must be a result of that very version.
|
|
460
386
|
const tabWord = url.searchParams.get("tab");
|
|
461
|
-
// The first tab (Plan, or Result once there is one) unless the address names Activity or Attempts.
|
|
462
387
|
const tab = tabWord === "result" || tabWord === "activity" || tabWord === "attempts" ? tabWord : "plan";
|
|
463
388
|
const runWord = url.searchParams.get("run");
|
|
464
389
|
const named = runWord === null ? null : /^[1-9][0-9]{0,14}$/.test(runWord) ? Number(runWord) : -1;
|
|
465
390
|
if (named === -1)
|
|
466
391
|
return refuse(response, who, 404, "No such result for this task.", taskHref(family.root.id));
|
|
467
|
-
// A run named without a version is shown with the version it belongs to: a saved link to a result outlives a newer
|
|
468
|
-
// revision becoming current. A run of no version of this family is no result of it.
|
|
469
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; })();
|
|
470
393
|
const shown = version ?? owner ?? family.current.id;
|
|
471
394
|
const picked = selectResultFor(shown, named, ctx.project, who, ctx.now);
|
|
@@ -475,19 +398,15 @@ export function createTasksHandlers(runtime) {
|
|
|
475
398
|
const csrf = who.via === "cookie" ? who.session.csrf : "";
|
|
476
399
|
const result = picked.selected === null ? null : (() => {
|
|
477
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 });
|
|
478
|
-
// Current: the result the task itself would show (its latest), however the address named it — the header then
|
|
479
|
-
// owns its status and ceremonies, so no form is ever on the page twice.
|
|
480
401
|
const latest = named === null ? picked.chosen?.runId ?? null : selectResultFor(shown, null, ctx.project, who, ctx.now).chosen?.runId ?? null;
|
|
481
402
|
return { html: parts.html, selected: parts.selected, current: shown === family.current.id && latest !== null && latest === picked.chosen?.runId };
|
|
482
403
|
})();
|
|
483
|
-
// The attempts the picker offers: exactly the runs this page would show for their version (the same rule as above).
|
|
484
404
|
const admissible = new Set(family.versions.flatMap(one => {
|
|
485
405
|
const ref = store.lookupRef(one.id);
|
|
486
406
|
return ref === null ? [] : store.runsFor(ref.id).filter(run => resultRunAdmissible(one.id, run, ctx.project)).map(run => run.id);
|
|
487
407
|
}));
|
|
488
408
|
return taskScreen(response, who, shown, null, 200, undefined, undefined, url.searchParams.get("edit") === "plan", { tab, result, admissible });
|
|
489
409
|
}
|
|
490
|
-
// v103: a task's evidence pack, as a printable page or JSON (the whole family, sealed ledger entries included).
|
|
491
410
|
async function showTaskEvidence(ctx) {
|
|
492
411
|
const { url, who, response, now } = ctx;
|
|
493
412
|
const evidence = matchTaskPath(url.pathname, "/evidence$");
|
|
@@ -509,8 +428,6 @@ export function createTasksHandlers(runtime) {
|
|
|
509
428
|
}
|
|
510
429
|
return sendScreen(response, 200, evidenceRecordPage(chromeFor(family.root.repo, "tasks"), pack));
|
|
511
430
|
}
|
|
512
|
-
/** Build history lives on Agents now ("Finished in the last …"), and each task keeps its own attempts: the old address
|
|
513
|
-
* keeps answering, as a GET alias. */
|
|
514
431
|
async function showRuns(ctx) {
|
|
515
432
|
return redirectGet(ctx.response, "/agents");
|
|
516
433
|
}
|
|
@@ -530,14 +447,9 @@ export function createTasksHandlers(runtime) {
|
|
|
530
447
|
return respond(response, 200, "text/html; charset=utf-8", checkProgressHtml(store.checkProgress(found.id)));
|
|
531
448
|
}
|
|
532
449
|
if (url.searchParams.get("fragment") === "facts") {
|
|
533
|
-
// The facts region alone — same auth and ceiling as the page; a
|
|
534
|
-
// finished or no-longer-live run says so rather than growing forms
|
|
535
|
-
// (finding 5; round-4 finding 15).
|
|
536
450
|
return respond(response, 200, "text/html; charset=utf-8", runFactsFragment(found, taskId, running, store.runRoute(found.id)));
|
|
537
451
|
}
|
|
538
452
|
if (url.searchParams.get("fragment") === "peek") {
|
|
539
|
-
// The live peek: cookie sessions only (v2 §3), never stored, never
|
|
540
|
-
// cached by anything downstream.
|
|
541
453
|
if (who.via !== "cookie")
|
|
542
454
|
return respond(response, 403, "text/plain; charset=utf-8", "the live peek is a browser session's view");
|
|
543
455
|
const peeked = await peekFragment(found.id, who.session.csrf, options.editorLinks !== undefined && found.runner === options.localRunner && who.session.editorLinks === true);
|
|
@@ -547,18 +459,10 @@ export function createTasksHandlers(runtime) {
|
|
|
547
459
|
return respond(response, peeked.status, "text/html; charset=utf-8", peeked.body);
|
|
548
460
|
}
|
|
549
461
|
if (url.searchParams.get("fragment") === "transcript") {
|
|
550
|
-
// The live conversation's window (arc 1; live-conversation.md §3–4):
|
|
551
|
-
// JSON over sanitized text or records — the sinks are textContent and
|
|
552
|
-
// React text, never innerHTML. Guards, enumerated: cookie session; run
|
|
553
|
-
// visible (proved above); this machine's runner asserted AND owning
|
|
554
|
-
// the run; byte offsets validated; the file read through its own
|
|
555
|
-
// descriptor with the exact numeric-id name, and its generation
|
|
556
|
-
// matched. Display state, not evidence — and never cached.
|
|
557
462
|
response.setHeader("cache-control", "no-store");
|
|
558
463
|
if (who.via !== "cookie")
|
|
559
464
|
return respond(response, 403, "application/json", JSON.stringify({ error: "session" }));
|
|
560
465
|
const records = url.searchParams.get("shape") === "records";
|
|
561
|
-
// Notes come from the store, not the file: they show even where the transcript cannot be read.
|
|
562
466
|
const notesOf = () => (records ? runNotes(store, found, who.name, now) : {});
|
|
563
467
|
if (options.localRunner === undefined || found.runner !== options.localRunner) {
|
|
564
468
|
return respond(response, 200, "application/json", JSON.stringify({ error: "off", ...notesOf() }));
|
|
@@ -570,27 +474,19 @@ export function createTasksHandlers(runtime) {
|
|
|
570
474
|
}
|
|
571
475
|
const sawGen = url.searchParams.get("gen");
|
|
572
476
|
const live = runIsLive(found);
|
|
573
|
-
// The final drain: a finished run's tail — including a torn last
|
|
574
|
-
// line — may be read until the sweep removes the file.
|
|
575
477
|
const window = readLiveWindow(evidenceRoot, found.id, from, !live);
|
|
576
478
|
if (!window.ok) {
|
|
577
479
|
if (window.reason === "replaced") {
|
|
578
480
|
return respond(response, 409, "application/json", JSON.stringify({ error: "replaced" }));
|
|
579
481
|
}
|
|
580
|
-
// Missing or unreadable: nothing to show. Final only when the
|
|
581
|
-
// run can never write again.
|
|
582
|
-
// Nothing was read, so the key state the cursor carried is handed straight back.
|
|
583
482
|
const inKey = url.searchParams.get("inkey") === "1";
|
|
584
483
|
const keyTail = validKeyTail(url.searchParams.get("ktail") ?? "") ? url.searchParams.get("ktail") ?? "" : "";
|
|
585
484
|
const empty = records ? { records: [], nextOffset: from, gen: sawGen, inKey, keyTail, final: !live } : { text: "", nextOffset: from, inKey, keyTail, final: !live };
|
|
586
485
|
return respond(response, 200, "application/json", JSON.stringify({ ...empty, ...notesOf() }));
|
|
587
486
|
}
|
|
588
|
-
// An offset belongs to the file it was read from: another file starts over, visibly.
|
|
589
487
|
if (sawGen !== null && sawGen !== "" && sawGen !== window.gen) {
|
|
590
488
|
return respond(response, 409, "application/json", JSON.stringify({ error: "replaced" }));
|
|
591
489
|
}
|
|
592
|
-
// Re-proof after the read (peek discipline): the run row still says
|
|
593
|
-
// what admission said — visible, and still this machine's — or nothing is shown.
|
|
594
490
|
const again = store.getRun(found.id);
|
|
595
491
|
if (again === null || !runVisible(again) || again.runner !== options.localRunner) {
|
|
596
492
|
const inKey = url.searchParams.get("inkey") === "1";
|
|
@@ -598,35 +494,25 @@ export function createTasksHandlers(runtime) {
|
|
|
598
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 }));
|
|
599
495
|
}
|
|
600
496
|
const final = !live && window.eof;
|
|
601
|
-
// A key block split across reads stays hidden: the cursor carries whether the last read ended inside one.
|
|
602
497
|
const tailRaw = url.searchParams.get("ktail") ?? "";
|
|
603
498
|
const keys = { inKey: url.searchParams.get("inkey") === "1", tail: validKeyTail(tailRaw) ? tailRaw : "" };
|
|
604
499
|
if (records) {
|
|
605
|
-
// Command text and output only under this run's own captured answer, never the file's `open` record (v136).
|
|
606
500
|
const commands = runLiveCommands(store, found.id);
|
|
607
501
|
const shown = liveWindowRecords(window, commands, keys);
|
|
608
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() }));
|
|
609
503
|
}
|
|
610
|
-
// The plain words, whatever the file's format; the offset moves by the bytes read even when nothing shows.
|
|
611
504
|
const lines = liveWindowLines(window, runLiveCommands(store, found.id), keys);
|
|
612
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 }));
|
|
613
506
|
}
|
|
614
|
-
// One result page (2026-10-02): a builder's finished result opens on
|
|
615
|
-
// its task's result page, titled with the task. The raw run record
|
|
616
|
-
// waits there under Details, and here with ?record=1.
|
|
617
507
|
if (url.searchParams.get("record") === null && !running && found.role === "builder" && (found.outcome === "built" || found.outcome === "no-change") &&
|
|
618
508
|
completedRowFor(taskId, null)?.runId === found.id) {
|
|
619
509
|
const tab = parseResultTab(url.searchParams.get("tab"));
|
|
620
510
|
return redirect(response, `${reviewHref(taskId, found.id)}${tab === "summary" ? "" : `&tab=${tab}`}`);
|
|
621
511
|
}
|
|
622
|
-
// A build that failed or stopped opens on its own result page too: its changes, its checks and what went wrong.
|
|
623
512
|
if (url.searchParams.get("record") === null && !running && (found.role === "builder" || found.role === "scout") && attemptRowFor(taskId, found.id, null) !== null) {
|
|
624
513
|
const tab = parseResultTab(url.searchParams.get("tab"));
|
|
625
514
|
return redirect(response, `${reviewHref(taskId, found.id)}${tab === "summary" ? "" : `&tab=${tab}`}`);
|
|
626
515
|
}
|
|
627
|
-
// Pollers exist only for a LIVE run — an orphaned null-outcome run
|
|
628
|
-
// would otherwise be refetched forever (finding 15). The nonce is
|
|
629
|
-
// sendScreen's business now.
|
|
630
516
|
const artifacts = store.artifactsFor(found.id);
|
|
631
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), (() => {
|
|
632
518
|
const publication = store.publicationForRun(found.id);
|
|
@@ -637,18 +523,12 @@ export function createTasksHandlers(runtime) {
|
|
|
637
523
|
? undefined
|
|
638
524
|
: regionScript("run-facts", "facts") +
|
|
639
525
|
(options.localRunner === undefined ? "" : regionScript("run-peek", "peek")) +
|
|
640
|
-
(options.localRunner === undefined ? "" : transcriptScript()), options.localRunner !== undefined, running,
|
|
641
|
-
// Editor links (arc 6): three statements align or nothing renders —
|
|
642
|
-
// the deployment capability, THIS machine's runner owning the run,
|
|
643
|
-
// and the session's own device-side yes.
|
|
644
|
-
options.editorLinks !== undefined &&
|
|
526
|
+
(options.localRunner === undefined ? "" : transcriptScript()), options.localRunner !== undefined, running, options.editorLinks !== undefined &&
|
|
645
527
|
options.localRunner !== undefined &&
|
|
646
528
|
found.runner === options.localRunner &&
|
|
647
529
|
who.via === "cookie" &&
|
|
648
530
|
who.session.editorLinks === true &&
|
|
649
|
-
// A reviewer run (v29) never had a checkout — no files to open.
|
|
650
531
|
found.worktree !== null &&
|
|
651
|
-
// Idle cleanup removes the folder and a later run makes it again: no link to a folder that isn't there.
|
|
652
532
|
existsSync(found.worktree)
|
|
653
533
|
? { worktree: found.worktree }
|
|
654
534
|
: null, options.editorLinks !== undefined &&
|
|
@@ -656,9 +536,7 @@ export function createTasksHandlers(runtime) {
|
|
|
656
536
|
found.runner === options.localRunner &&
|
|
657
537
|
who.via === "cookie"
|
|
658
538
|
? { on: who.session.editorLinks === true }
|
|
659
|
-
: 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),
|
|
660
|
-
// The shared result presentation (package 3) for a finished result.
|
|
661
|
-
!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")
|
|
662
540
|
? { detail: resultDetailOf(found, who, now), tab: parseResultTab(url.searchParams.get("tab")), user: who.name, requestToken: randomBytes(16).toString("hex") }
|
|
663
541
|
: null, store.getScope(taskId)?.digest ?? null));
|
|
664
542
|
}
|
|
@@ -669,7 +547,6 @@ export function createTasksHandlers(runtime) {
|
|
|
669
547
|
return noPage(who, response);
|
|
670
548
|
return runEvidence(response, Number(runArtifact[1]), Number(runArtifact[2]));
|
|
671
549
|
}
|
|
672
|
-
// v115: routines became scheduled flows; an old link to the list or to one routine lands on the flows page.
|
|
673
550
|
async function showRoutines(ctx) {
|
|
674
551
|
return redirect(ctx.response, "/flows");
|
|
675
552
|
}
|
|
@@ -708,8 +585,6 @@ export function createTasksHandlers(runtime) {
|
|
|
708
585
|
const permitted = (repo) => visible(repo) && codingProjectAllowed(repo);
|
|
709
586
|
const starting = verb === 'start';
|
|
710
587
|
const sessionId = starting || verb === 'unknown' ? null : /^\/code\/([a-f0-9]{32})/.exec(url.pathname)[1];
|
|
711
|
-
// Sprint 8: a coding session is Codex taking turns: the organisation policy decides whether it may (provider,
|
|
712
|
-
// model, and a ceiling Codex can't run under), when it starts and on every action that makes it take another turn.
|
|
713
588
|
const turnAction = ['send', 'resume', 'recover', 'continue', 'answer'].includes(verb);
|
|
714
589
|
if (starting || turnAction) {
|
|
715
590
|
const stopped = store.sessionPolicyRefusal('codex', starting ? body.get('model')?.trim() || null : null, 'coding sessions');
|
|
@@ -762,7 +637,6 @@ export function createTasksHandlers(runtime) {
|
|
|
762
637
|
runtime.coding.answer(id, actor, token, decision, answers);
|
|
763
638
|
}
|
|
764
639
|
}
|
|
765
|
-
// Authorization is checked again after asynchronous startup/transport work.
|
|
766
640
|
if (!codingActorAllowed(actor))
|
|
767
641
|
return fail(403, 'Your access changed. Sign in again.', 'unknown', id);
|
|
768
642
|
return wantsJson ? respond(response, 200, 'application/json', JSON.stringify({ ok: true, id })) : redirect(response, `/code/${id}`);
|
|
@@ -788,8 +662,6 @@ export function createTasksHandlers(runtime) {
|
|
|
788
662
|
if (project === undefined) {
|
|
789
663
|
return refuse(response, who, 403, "that project is outside what this server was configured to show");
|
|
790
664
|
}
|
|
791
|
-
// Stale-tab guard: a form rendered under one open project must not
|
|
792
|
-
// create into a different one switched-to since (finding 6).
|
|
793
665
|
if (who.via === "cookie") {
|
|
794
666
|
const seen = body.get("projectRevision");
|
|
795
667
|
if (seen !== null && seen !== String(who.session.projectRevision)) {
|
|
@@ -797,38 +669,21 @@ export function createTasksHandlers(runtime) {
|
|
|
797
669
|
}
|
|
798
670
|
}
|
|
799
671
|
const id = (body.get("id") ?? "").trim();
|
|
800
|
-
// 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
|
|
801
|
-
// filing. A direct POST longer than that is cut at a whole word, with an ellipsis (task-text.ts titleWithin), as a
|
|
802
|
-
// belt; a refusal keeps the person's own words (the draft below).
|
|
803
672
|
const typed = body.get("title") ?? "";
|
|
804
673
|
const title = titleWithin(typed);
|
|
805
|
-
// The EFFECTIVE placement (repo onboarding, findings 15/35): the
|
|
806
|
-
// trimmed, nonempty posted repo, else the open project — an empty
|
|
807
|
-
// input falls through correctly. In root mode the effective path is
|
|
808
|
-
// proved by authorizedProject EXACTLY as typed-then-canonicalized,
|
|
809
|
-
// and [canonical] is the admitted list — a fresh clone under a root
|
|
810
|
-
// must be able to receive its first task without waiting to appear
|
|
811
|
-
// in any table.
|
|
812
674
|
const repoGiven = (body.get("repo") ?? "").trim();
|
|
813
675
|
const effective = repoGiven !== "" ? repoGiven : (project ?? "");
|
|
814
676
|
if (restricted() && !visible(effective === "" ? null : effective))
|
|
815
677
|
return refuse(response, who, 403, "That project is outside your access.", "/projects");
|
|
816
|
-
// A scoped console refuses an EMPTY placement server-side (verification
|
|
817
|
-
// finding 1): the form's `required` is a courtesy, not the guard — a
|
|
818
|
-
// direct POST with no project open must not mint an unplaced task
|
|
819
|
-
// under a ceiling. Unscoped mode keeps its historic unplaced filings.
|
|
820
|
-
// A refusal from here on is the add page again with the person's own words (the old task list kept them too).
|
|
821
678
|
const draft = { title: typed, goal: body.get("goal") ?? "", not: body.get("not") ?? "", touches: body.get("touches") ?? "", acceptance: body.get("acceptance") ?? "", values: body.sent };
|
|
822
679
|
if (!unscopedMode && effective === "") {
|
|
823
680
|
return newTaskScreen(ctx, 400, "name a repository — no project is open, so the task must say where it belongs", draft);
|
|
824
681
|
}
|
|
825
682
|
let repo = effective;
|
|
826
683
|
let admitted = unscopedMode ? null : admissionList() ?? [];
|
|
827
|
-
// What this filing is decided on: re-checked inside the write below, after every await (project-identity.ts).
|
|
828
684
|
const decidedOn = identities.generation();
|
|
829
685
|
const rootMode = !unscopedMode && ceiling.roots.length > 0;
|
|
830
686
|
if (rootMode && effective !== "") {
|
|
831
|
-
// Resolved off the console's thread (project-identity.ts), then proved against the ceiling as that identity.
|
|
832
687
|
const resolved = await identities.resolveNow(effective);
|
|
833
688
|
if (resolved === "no-answer")
|
|
834
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);
|
|
@@ -854,9 +709,7 @@ export function createTasksHandlers(runtime) {
|
|
|
854
709
|
if (qualityMode !== null && !isQualityMode(qualityMode)) {
|
|
855
710
|
return refuse(response, who, 400, "quality must be Default or Strict / release", "/tasks/new");
|
|
856
711
|
}
|
|
857
|
-
// One filing door for every surface (Codex adoption review, finding 7).
|
|
858
712
|
const after = (body.get("after") ?? "").trim();
|
|
859
|
-
// From an issue or pull request (github-import.ts): read and quoted first; filing is the second press, on what was read.
|
|
860
713
|
const fromLink = (body.get("from") ?? "").trim();
|
|
861
714
|
if (fromLink !== "") {
|
|
862
715
|
if (who.via !== "cookie" || repo === "")
|
|
@@ -872,8 +725,6 @@ export function createTasksHandlers(runtime) {
|
|
|
872
725
|
return newTaskScreen(ctx, filed.reason === "head-moved" ? 409 : 400, filed.message, draft);
|
|
873
726
|
return redirect(response, taskHref(filed.taskId));
|
|
874
727
|
}
|
|
875
|
-
// Small work a person starts themselves: their words become the exact terms, and Build is their yes (fast-start.ts).
|
|
876
|
-
// Anything else, or any doubt, is the ordinary filing below. `plain` is "Plan it first" from that form.
|
|
877
728
|
if (who.via === "cookie" && body.get("plain") !== "1" && repo !== "" && goal === "" && notThis === "" && touchesGiven.length === 0 && !scout && id === "" && after === ""
|
|
878
729
|
&& (qualityMode === null || qualityMode === "default") && (permissionMode === null || permissionMode === "auto")) {
|
|
879
730
|
const fast = await prepareFastStart(store, { actor: who.name, repo, title: typed.trim(), via: "console", ...(permissionMode === null ? {} : { permissionMode }), password: fastPasswordFacts(who) }, now);
|
|
@@ -882,8 +733,6 @@ export function createTasksHandlers(runtime) {
|
|
|
882
733
|
}
|
|
883
734
|
let chainProblem = null;
|
|
884
735
|
const made = store.transact(() => {
|
|
885
|
-
// A project folder's identity changed while this request waited (a root or link now leads elsewhere): what was
|
|
886
|
-
// proved above may no longer hold, so nothing is filed on it.
|
|
887
736
|
if (identities.generation() !== decidedOn || (rootMode && repo !== "" && !visible(repo)))
|
|
888
737
|
return null;
|
|
889
738
|
const filed = fileTaskProposal(store, {
|
|
@@ -911,8 +760,6 @@ export function createTasksHandlers(runtime) {
|
|
|
911
760
|
if (!chained.ok)
|
|
912
761
|
chainProblem = chained.reason;
|
|
913
762
|
}
|
|
914
|
-
// Missing dependencies leave a reviewable, inert task. They must
|
|
915
|
-
// never be silently dropped before automatic approval starts work.
|
|
916
763
|
if (filed.ok && chainProblem === null && who.via === "cookie")
|
|
917
764
|
applyModeToNewFiling(store, filed.id, who.name, now);
|
|
918
765
|
return filed;
|
|
@@ -925,8 +772,6 @@ export function createTasksHandlers(runtime) {
|
|
|
925
772
|
const actionContext = requestContext.getStore();
|
|
926
773
|
if (actionContext !== undefined)
|
|
927
774
|
actionContext.createdTask = made.id;
|
|
928
|
-
// A proved root-mode placement joins the project table (finding 15):
|
|
929
|
-
// the new task's home is openable and admissible from now on.
|
|
930
775
|
if (rootMode && repo !== "")
|
|
931
776
|
store.upsertProject(repo, projectName(repo), now);
|
|
932
777
|
if (chainProblem !== null)
|
|
@@ -940,9 +785,6 @@ export function createTasksHandlers(runtime) {
|
|
|
940
785
|
if (project === undefined) {
|
|
941
786
|
return refuse(response, who, 403, "that project is outside what this server was configured to show");
|
|
942
787
|
}
|
|
943
|
-
// The note is a global runner label, not project-scoped work: the
|
|
944
|
-
// fleet screen (project-less) posts it too, so the null-project gate
|
|
945
|
-
// applies only to moves, which their task-level check re-proves.
|
|
946
788
|
const worker = (body.get("runner") ?? "").trim();
|
|
947
789
|
const note = (body.get("note") ?? "").trim();
|
|
948
790
|
if (note.length > 200 || hasForbiddenControls(note)) {
|
|
@@ -966,8 +808,6 @@ export function createTasksHandlers(runtime) {
|
|
|
966
808
|
return refuse(response, who, 409, "the open project changed since this form was rendered — reload and try again", QUEUE_VIEW);
|
|
967
809
|
}
|
|
968
810
|
}
|
|
969
|
-
// A drag posts in place (fetch) when it can; the page re-renders its
|
|
970
|
-
// own fragment on success. A plain form still works with no script.
|
|
971
811
|
const inPlace = body.get("respond") === "fragment";
|
|
972
812
|
const fromFleet = who.via === "cookie" && body.get("projectRevision") === null;
|
|
973
813
|
const respondMove = (status, message) => {
|
|
@@ -989,8 +829,6 @@ export function createTasksHandlers(runtime) {
|
|
|
989
829
|
const toRunner = columnGiven === "" || columnGiven === "anyone" ? null : columnGiven;
|
|
990
830
|
const beforeGiven = (body.get("before") ?? "").trim();
|
|
991
831
|
const revisionGiven = Number(body.get("queueRevision") ?? "");
|
|
992
|
-
// The queue's own screen enforces the open project; the fleet screen
|
|
993
|
-
// is cross-project, so the ceiling is the only wall it needs.
|
|
994
832
|
const belongs = (id) => {
|
|
995
833
|
const ref = store.lookupRef(id);
|
|
996
834
|
return ref !== null && visible(ref.repo) && (fromFleet || project === null || ref.repo === null || ref.repo === project);
|
|
@@ -998,12 +836,6 @@ export function createTasksHandlers(runtime) {
|
|
|
998
836
|
if (!belongs(taskId) || (beforeGiven !== "" && beforeGiven !== QUEUE_FRONT && !belongs(beforeGiven))) {
|
|
999
837
|
return respondMove(404, "that task is not in this queue");
|
|
1000
838
|
}
|
|
1001
|
-
// The no-script "move to the front" button cannot name the front: the
|
|
1002
|
-
// front of a task's partition is decided by the store's exact repo AND
|
|
1003
|
-
// assignment, and the page's snapshot is bounded — so the sentinel is
|
|
1004
|
-
// resolved HERE, against a fresh snapshot, into a real task id (slice
|
|
1005
|
-
// 1b, fix 1). It is honored only within the task's own column; a
|
|
1006
|
-
// cross-column front is not provable from a bounded snapshot.
|
|
1007
839
|
let beforeTaskId = beforeGiven === "" ? null : beforeGiven;
|
|
1008
840
|
if (beforeGiven === QUEUE_FRONT) {
|
|
1009
841
|
const ref = store.lookupRef(taskId);
|
|
@@ -1015,11 +847,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1015
847
|
const now = clock();
|
|
1016
848
|
const snapshot = store.queueScoped(ref.repo, now);
|
|
1017
849
|
const self = snapshot.find(one => one.id === taskId);
|
|
1018
|
-
// A claim can land after the form rendered WITHOUT
|
|
1019
|
-
// bumping queueRevision, so the snapshot — not the form — decides
|
|
1020
|
-
// whether the card is still free. A taken or vanished card is the
|
|
1021
|
-
// typed refusal, never a silent no-op that would skip moveTask()'s
|
|
1022
|
-
// own claimed recheck.
|
|
1023
850
|
if (self === undefined)
|
|
1024
851
|
return respondMove(409, moveReason("unknown-task"));
|
|
1025
852
|
if (self.taken)
|
|
@@ -1029,9 +856,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1029
856
|
if (front === undefined)
|
|
1030
857
|
return respondMove(409, moveReason("unknown-task"));
|
|
1031
858
|
if (front.id === taskId) {
|
|
1032
|
-
// Already the front: a no-op, but only against the revision the
|
|
1033
|
-
// form was rendered with — this branch never reaches moveTask()'s
|
|
1034
|
-
// CAS, so the check is made here.
|
|
1035
859
|
if (!Number.isSafeInteger(revisionGiven) || revisionGiven !== store.queueRevision()) {
|
|
1036
860
|
return respondMove(409, moveReason("stale"));
|
|
1037
861
|
}
|
|
@@ -1072,10 +896,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1072
896
|
}
|
|
1073
897
|
const choice = body.get("choice") ?? "";
|
|
1074
898
|
const chosen = decision.options.find(option => option.id === choice);
|
|
1075
|
-
// Irreversible options never ride one accidental tap: the form arms
|
|
1076
|
-
// them behind an explicit confirmation field, and the server checks —
|
|
1077
|
-
// the client rendering is convenience, this is the rule.
|
|
1078
|
-
// The question page's own form hears a refusal in its box, with nothing changed; /next keeps its refusal page.
|
|
1079
899
|
const inPlace = requestedReturn !== "next";
|
|
1080
900
|
const pageBack = requestedReturn === null ? null : decisionBack;
|
|
1081
901
|
if (chosen !== undefined && !chosen.reversible && body.get("confirm") !== "yes") {
|
|
@@ -1108,8 +928,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1108
928
|
if (act === null)
|
|
1109
929
|
return noPage(who, response);
|
|
1110
930
|
const body = readForm(posted, CONSOLE_FORMS.recheckStopped);
|
|
1111
|
-
// Check again: Toolroll looks at this computer's processes for the build once more (stop-proof.ts) and settles it
|
|
1112
|
-
// when none of them is the build's. Nobody vouches that a build stopped, so there is nothing to confirm here.
|
|
1113
931
|
const back = taskHref(act.taskId);
|
|
1114
932
|
const ref = store.lookupRef(act.taskId);
|
|
1115
933
|
if (ref === null || !visible(ref.repo))
|
|
@@ -1142,8 +960,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1142
960
|
if (act === null)
|
|
1143
961
|
return noPage(who, response);
|
|
1144
962
|
const body = readForm(posted, CONSOLE_FORMS.merge);
|
|
1145
|
-
// Merging is a person's act behind their password, typed again: a browser session, an approver, the exact
|
|
1146
|
-
// result's pull request. The flow re-reads GitHub before merging and records who merged in the ledger.
|
|
1147
963
|
if (store.isDemo())
|
|
1148
964
|
return taskScreen(response, who, act.taskId, "The demo merges nothing.", 403);
|
|
1149
965
|
const ref = store.lookupRef(act.taskId);
|
|
@@ -1160,7 +976,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1160
976
|
return taskScreen(response, who, act.taskId, merged.message, merged.reason === "password" ? 403 : 409);
|
|
1161
977
|
return redirect(response, `${taskHref(act.taskId)}#merge`);
|
|
1162
978
|
}
|
|
1163
|
-
/** A task act bound to its verb: taskMutation owns each verb's checks. */
|
|
1164
979
|
const taskAct = (verb) => async (ctx) => {
|
|
1165
980
|
const { url, who, response, now, posted } = ctx;
|
|
1166
981
|
const act = matchTaskPath(url.pathname, `/${verb}$`);
|
|
@@ -1168,8 +983,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1168
983
|
return noPage(who, response);
|
|
1169
984
|
return taskMutation(response, who, act.taskId, verb, posted, now, ctx.request);
|
|
1170
985
|
};
|
|
1171
|
-
// Cockpit E: Show in Finder — the checkout proved again right now (live, this machine's runner, inside the pool),
|
|
1172
|
-
// then Finder asked to reveal it with a fixed argv. Nothing runs in it; a Mac only.
|
|
1173
986
|
async function runReveal(ctx) {
|
|
1174
987
|
const { url, who, response, now, posted } = ctx;
|
|
1175
988
|
const asked = /^\/r\/([0-9]{1,15})\/reveal$/.exec(url.pathname);
|
|
@@ -1196,10 +1009,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1196
1009
|
if (noted === null)
|
|
1197
1010
|
return noPage(who, response);
|
|
1198
1011
|
const body = readForm(posted, CONSOLE_FORMS.runNote);
|
|
1199
|
-
// An operator's verdict beside the machine's record (M6): immutable,
|
|
1200
|
-
// bounded by the same validator as decision notes, ceiling-checked
|
|
1201
|
-
// like every run resource. Ordinary authenticated mutation — no
|
|
1202
|
-
// nonce, because nothing here approves anything.
|
|
1203
1012
|
const id = Number(noted[1]);
|
|
1204
1013
|
const found = store.getRun(id);
|
|
1205
1014
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1217,31 +1026,17 @@ export function createTasksHandlers(runtime) {
|
|
|
1217
1026
|
if (diffComment === null)
|
|
1218
1027
|
return noPage(who, response);
|
|
1219
1028
|
const body = readForm(posted, CONSOLE_FORMS.diffComment);
|
|
1220
|
-
// A review comment on the IMMUTABLE terminal diff (M6.8): bound to
|
|
1221
|
-
// the exact artifact and its hash. Ordinary authenticated mutation —
|
|
1222
|
-
// the nonce belongs to the approval screen that later restates the
|
|
1223
|
-
// batch, never to the comment box.
|
|
1224
1029
|
const id = Number(diffComment[1]);
|
|
1225
1030
|
const found = store.getRun(id);
|
|
1226
1031
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
1227
1032
|
return refuse(response, who, 404, "no such run");
|
|
1228
1033
|
}
|
|
1229
|
-
// Where the reader came from (package 3): the cockpit's deep link,
|
|
1230
|
-
// the chat's result view, or the run page — validated to those exact
|
|
1231
|
-
// shapes. A refusal sends them back THERE, where the browser has kept
|
|
1232
|
-
// their draft, so a failed submission is recoverable in place.
|
|
1233
1034
|
const returnTo = resultReturnTarget(body.get("return"), id, runTasks(found.taskRef));
|
|
1234
1035
|
const selectedTab = parseResultTab(body.get("tab"));
|
|
1235
|
-
// A task page's Result tab keeps the result's own view in `section=` (its `tab` is the task's).
|
|
1236
1036
|
const viewParam = returnTo.startsWith("/t/") ? "section" : "tab";
|
|
1237
1037
|
const back = selectedTab === "summary" ? returnTo
|
|
1238
1038
|
: `${returnTo.replace(/§ion=(?:summary|changes|checks)$/, "")}${returnTo.includes("?") ? "&" : "?"}${viewParam}=${selectedTab}`;
|
|
1239
1039
|
if (body.get("intent") === "drop-image") {
|
|
1240
|
-
// A saved note whose screenshot is gone or changed would block every revision that seals it. Its words stay:
|
|
1241
|
-
// the note is superseded by an exact imageless copy, and the original remains in history.
|
|
1242
|
-
// Who: a signed-in browser approver admitted to this run's project (checked above) — the same authority that
|
|
1243
|
-
// seals any saved note into a revision. What: only a screenshot that is unusable right now, re-proved inside
|
|
1244
|
-
// dropFeedbackImage's transaction, and recorded in the ledger under this person.
|
|
1245
1040
|
if (who.via !== "cookie" || who.role !== "approver")
|
|
1246
1041
|
return refuse(response, who, 403, "Only a signed-in approver can change saved feedback.", back);
|
|
1247
1042
|
const comment = Number(body.get("comment") ?? "");
|
|
@@ -1262,14 +1057,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1262
1057
|
const result = requestResultChanges(store, evidenceRoot, {
|
|
1263
1058
|
run: id, batch: body.get("batch"), source: body.get("source"), actor: who.name,
|
|
1264
1059
|
repos: admissionList(), includeUnplaced: visible(null), allowMode: who.via === "cookie",
|
|
1265
|
-
// A browser session is a person's proof; a bearer credential is a machine's.
|
|
1266
1060
|
origin: who.via === "cookie" ? "person" : "machine",
|
|
1267
1061
|
note: body.get("note") ?? "", path: body.get("path") ?? "", line: body.get("line") ?? "", request: body.get("request"), image,
|
|
1268
1062
|
}, now);
|
|
1269
1063
|
if (!result.ok) {
|
|
1270
1064
|
const request = body.get("request") ?? "";
|
|
1271
|
-
// The queue's link can stop resolving when a newer attempt finishes. The exact
|
|
1272
|
-
// run record still hosts this account/run's recoverable feedback draft.
|
|
1273
1065
|
const retryBase = image === null ? back : `/r/${id}?record=1`;
|
|
1274
1066
|
const retryBack = /^[a-f0-9]{32}$/.test(request) ? `${retryBase}${retryBase.includes("?") ? "&" : "?"}conflict=${request}#request-changes` : retryBase;
|
|
1275
1067
|
return refuse(response, who, result.status, result.message, retryBack);
|
|
@@ -1280,9 +1072,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1280
1072
|
if (terminal === undefined) {
|
|
1281
1073
|
return refuse(response, who, 400, "this run has no terminal diff to comment on", back);
|
|
1282
1074
|
}
|
|
1283
|
-
// The bytes must VERIFY before words attach to them (audit IV-10):
|
|
1284
|
-
// "a comment on the exact reviewed bytes" is a lie if the bytes are
|
|
1285
|
-
// gone or no longer hash to their record.
|
|
1286
1075
|
const proven = readVerifiedArtifact(evidenceRoot, terminal);
|
|
1287
1076
|
if (!proven.ok) {
|
|
1288
1077
|
return refuse(response, who, 409, `the terminal diff no longer verifies (${proven.problem}) — nothing to comment on`, back);
|
|
@@ -1299,15 +1088,9 @@ export function createTasksHandlers(runtime) {
|
|
|
1299
1088
|
if (line !== null && (!Number.isInteger(line) || line < 1 || line > 1_000_000)) {
|
|
1300
1089
|
return refuse(response, who, 400, "Enter a whole line number from 1 to 1,000,000, or leave it blank.", back);
|
|
1301
1090
|
}
|
|
1302
|
-
// The form's own request token (package 3) is the dedupe key: a
|
|
1303
|
-
// replayed or double submission finds its note already recorded and
|
|
1304
|
-
// lands on the same receipt instead of a second note. The token is
|
|
1305
|
-
// bound to the account, so nobody else's replay can consume it.
|
|
1306
1091
|
const request = body.get("request");
|
|
1307
1092
|
const sourceKey = commentSourceKey(who.name, request);
|
|
1308
1093
|
const path = rawPath === "" ? null : rawPath;
|
|
1309
|
-
// Freshness, custody and the insert in one write transaction: a newer attempt finishing in between can't leave a
|
|
1310
|
-
// stale screenshot attached (check and write together).
|
|
1311
1094
|
const saved = store.transact(() => {
|
|
1312
1095
|
const imageProblem = feedbackImageProblem(store, evidenceRoot, id, image);
|
|
1313
1096
|
if (imageProblem !== null)
|
|
@@ -1318,13 +1101,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1318
1101
|
return refuse(response, who, 409, saved.problem, `/r/${id}?record=1#request-changes`);
|
|
1319
1102
|
const inserted = saved.inserted;
|
|
1320
1103
|
if (inserted === null && sourceKey !== undefined) {
|
|
1321
|
-
// The token was used before (repair 2026-09-14, finding 1). A
|
|
1322
|
-
// request identity is IMMUTABLE: it names exactly one note on
|
|
1323
|
-
// exactly one result. The unchanged retry — same run, same file,
|
|
1324
|
-
// line and words — lands on its original receipt; any other reuse
|
|
1325
|
-
// is refused, and the refusal's way back carries `conflict=<token>`
|
|
1326
|
-
// so the browser mints a fresh identity for the words it still
|
|
1327
|
-
// holds. Nothing typed is lost either way.
|
|
1328
1104
|
const earlier = store.diffCommentBySourceKey(sourceKey);
|
|
1329
1105
|
const conflictBack = `${back}${back.includes("?") ? "&" : "?"}conflict=${request}#request-changes`;
|
|
1330
1106
|
if (earlier === null || earlier.run !== id) {
|
|
@@ -1334,21 +1110,12 @@ export function createTasksHandlers(runtime) {
|
|
|
1334
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);
|
|
1335
1111
|
}
|
|
1336
1112
|
}
|
|
1337
|
-
// Land back AT the request-changes form with the note field ready —
|
|
1338
|
-
// writing five notes in a row must cost five keystrokes of
|
|
1339
|
-
// navigation, not five scrolls (arc 6, finding 5/6). The receipt
|
|
1340
|
-
// names the request token, so the browser clears exactly the draft
|
|
1341
|
-
// that landed and no other.
|
|
1342
1113
|
const receipt = sourceKey === undefined ? "1" : request;
|
|
1343
1114
|
return redirect(response, `${back}${back.includes("?") ? "&" : "?"}noted=${receipt}#request-changes`);
|
|
1344
1115
|
}
|
|
1345
1116
|
async function sessionEditorLinks(ctx) {
|
|
1346
1117
|
const { who, response, posted } = ctx;
|
|
1347
1118
|
const body = readForm(posted, CONSOLE_FORMS.editorLinks);
|
|
1348
|
-
// The session half of the editor-link activation (arc 6, finding 1):
|
|
1349
|
-
// only the person at the browser can say "this device holds the
|
|
1350
|
-
// worktrees". Per-session, dies with the session, grants nothing —
|
|
1351
|
-
// it only lets already-authorized pages RENDER vscode links.
|
|
1352
1119
|
if (who.via !== "cookie")
|
|
1353
1120
|
return refuse(response, who, 403, "editor links are a browser session's choice");
|
|
1354
1121
|
if (options.editorLinks === undefined)
|
|
@@ -1363,10 +1130,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1363
1130
|
if (revise === null)
|
|
1364
1131
|
return noPage(who, response);
|
|
1365
1132
|
const body = readForm(posted, CONSOLE_FORMS.revise);
|
|
1366
|
-
// Seal the live comment batch into ONE unapproved revision task with
|
|
1367
|
-
// an immutable brief (M6.8). Deterministic — no model reads anything
|
|
1368
|
-
// here — and every revision takes its own approval: comments can
|
|
1369
|
-
// semantically widen work, and no path check can prove they did not.
|
|
1370
1133
|
const id = Number(revise[1]);
|
|
1371
1134
|
const found = store.getRun(id);
|
|
1372
1135
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1382,8 +1145,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1382
1145
|
return refuse(response, who, result.status, result.message, back);
|
|
1383
1146
|
return redirect(response, revisionDestination(result.id, back));
|
|
1384
1147
|
}
|
|
1385
|
-
// Follow-ups on a result: Run checks on its exact commit (a worker runs the
|
|
1386
|
-
// approved command once and seals the log), or file a task to add tests.
|
|
1387
1148
|
const runFollowUp = (op) => async (ctx) => {
|
|
1388
1149
|
const { url, who, response, now, posted } = ctx;
|
|
1389
1150
|
const followUp = /^\/r\/([0-9]{1,15})\//.exec(url.pathname);
|
|
@@ -1394,7 +1155,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1394
1155
|
const found = store.getRun(id);
|
|
1395
1156
|
if (found === null || !visible(taskRepoOf(found.taskRef)))
|
|
1396
1157
|
return refuse(response, who, 404, "no such run");
|
|
1397
|
-
// The task page that offered Run checks in place is a return target too: this run's own task, or its family's root.
|
|
1398
1158
|
const back = resultReturnTarget(body.get("return"), id, runTasks(found.taskRef));
|
|
1399
1159
|
if (who.via !== "cookie")
|
|
1400
1160
|
return refuse(response, who, 403, "Sign in with a browser session to do this.", back);
|
|
@@ -1407,7 +1167,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1407
1167
|
const asked = requestFollowUpChecks(store, { runId: id, level, actor: who.name }, now);
|
|
1408
1168
|
if (!asked.ok)
|
|
1409
1169
|
return refuse(response, who, 409, asked.message, back);
|
|
1410
|
-
// Back where it was asked: the task page's status row says the checks are running; a result page shows them under #follow-ups.
|
|
1411
1170
|
return redirect(response, back.startsWith("/t/") ? back : `${back.split("#")[0]}#follow-ups`);
|
|
1412
1171
|
}
|
|
1413
1172
|
const filed = fileAddTestsTask(store, evidenceRoot, { runId: id, actor: who.name, filedVia: "console", ...(admissionList() === null ? {} : { admittedRepos: admissionList() }) }, now);
|
|
@@ -1420,10 +1179,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1420
1179
|
const draftRepair = /^\/r\/([0-9]{1,15})\/draft-repair$/.exec(url.pathname);
|
|
1421
1180
|
if (draftRepair === null)
|
|
1422
1181
|
return noPage(who, response);
|
|
1423
|
-
// CI repair, suggestion-first (M8.18): a red episode never spawns an
|
|
1424
|
-
// agent by itself — it EARNS a button, and the button creates one
|
|
1425
|
-
// unapproved task through the same revision machinery as review
|
|
1426
|
-
// comments. One draft per task/PR, ever: the merge blocker records it.
|
|
1427
1182
|
const id = Number(draftRepair[1]);
|
|
1428
1183
|
const found = store.getRun(id);
|
|
1429
1184
|
if (found === null || !visible(taskRepoOf(found.taskRef))) {
|
|
@@ -1438,9 +1193,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1438
1193
|
}
|
|
1439
1194
|
const sourceTaskId = store.externalIdFor(found.taskRef) ?? "?";
|
|
1440
1195
|
const sourceScope = store.getScope(sourceTaskId);
|
|
1441
|
-
// The observed episode, not the click: the brief binds the head the
|
|
1442
|
-
// failure was SEEN on and when (audit C-2) — a PR that advanced since
|
|
1443
|
-
// is a different failure, and the click time is not an observation.
|
|
1444
1196
|
const episode = store.latestOpenCiEpisode(publication.githubRepo, publication.prNumber);
|
|
1445
1197
|
const brief = {
|
|
1446
1198
|
schema: 1,
|
|
@@ -1458,11 +1210,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1458
1210
|
const briefBytes = Buffer.from(JSON.stringify(brief, null, 2), "utf8");
|
|
1459
1211
|
const briefName = `ci-repair-brief-${randomBytes(6).toString("hex")}.json`;
|
|
1460
1212
|
const key = writeEvidenceFile(evidenceRoot, id, briefName, briefBytes);
|
|
1461
|
-
// The SAME revision boundary the annotation road and the criterion
|
|
1462
|
-
// repair use (contract handoff task 2): the inherited terms come from
|
|
1463
|
-
// the source rows inside the seal; the scope read above only names
|
|
1464
|
-
// the digest this draft was composed against.
|
|
1465
|
-
// One draft per task/PR, ever: the PR's merge blocker names it, lifted or not, and is written in the seal's transaction.
|
|
1466
1213
|
const sealed = store.transact(() => {
|
|
1467
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);
|
|
1468
1215
|
if (prior !== undefined)
|
|
@@ -1478,9 +1225,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1478
1225
|
commentIds: null,
|
|
1479
1226
|
requestedBy: who.name,
|
|
1480
1227
|
}, now);
|
|
1481
|
-
// The merge blocker rides the SAME breath as the draft (merge grant,
|
|
1482
|
-
// findings 3/12/13): while this repair exists, the source PR merges
|
|
1483
|
-
// NOTHING — sticky until the operator's unblock act or the PR closes.
|
|
1484
1228
|
if (result.ok)
|
|
1485
1229
|
store.createMergeBlocker(publication.id, result.id, now);
|
|
1486
1230
|
return result;
|
|
@@ -1497,11 +1241,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1497
1241
|
return noPage(who, response);
|
|
1498
1242
|
const body = readForm(posted, CONSOLE_FORMS.resolveIncident);
|
|
1499
1243
|
const id = Number(resolve[1]);
|
|
1500
|
-
// The ceiling applies to incident mutation exactly as to every other
|
|
1501
|
-
// resource (v3 review, finding 3): resolve incident → run → task, and
|
|
1502
|
-
// an incident outside this server's scope does not exist here. The
|
|
1503
|
-
// task id is captured BEFORE resolving — afterwards the incident is
|
|
1504
|
-
// no longer open and could not be found again.
|
|
1505
1244
|
const openRow = store.openIncidents().find(one => one.id === id);
|
|
1506
1245
|
const incidentRun = openRow === undefined ? null : store.getRun(openRow.run);
|
|
1507
1246
|
if (openRow !== undefined && incidentRun !== null && !visible(taskRepoOf(incidentRun.taskRef))) {
|
|
@@ -1513,7 +1252,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1513
1252
|
const back = body.get("return") === "inbox" ? "/" : openRow === undefined ? "/" : taskHref(openRow.taskId);
|
|
1514
1253
|
return redirect(response, back);
|
|
1515
1254
|
}
|
|
1516
|
-
/** The compact recent-runs list for the master pane. */
|
|
1517
1255
|
function runListPane(project, currentId) {
|
|
1518
1256
|
const rows = store.listRunsBefore(null, 50, project);
|
|
1519
1257
|
const live = liveRunIds(rows);
|
|
@@ -1522,15 +1260,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1522
1260
|
return html `<h2>Builds</h2>\n${rows.length === 0 ? html `<p class="meta">None yet</p>` : items}`;
|
|
1523
1261
|
}
|
|
1524
1262
|
async function peekFragment(runId, sessionKey, editorMode = false) {
|
|
1525
|
-
// The cache and the in-flight coalescer hold the fragment's bytes (runtime's types); they are markup this made.
|
|
1526
1263
|
const said = (message, final) => peekSay(message, final);
|
|
1527
1264
|
const guarded = peekGuards(runId);
|
|
1528
1265
|
if (!guarded.ok)
|
|
1529
1266
|
return { status: 200, body: said(guarded.message, guarded.final === true) };
|
|
1530
1267
|
const { run, worktree, epoch, entries } = guarded.admit;
|
|
1531
|
-
// The cache and the in-flight coalescer both vary by LINK MODE (arc 6,
|
|
1532
|
-
// finding 3): a linked fragment rendered for one session must never be
|
|
1533
|
-
// served to a session that has not activated links on its device.
|
|
1534
1268
|
const key = `${runId}:${run.baseRevision}:${epoch}:${editorMode ? "links" : "plain"}`;
|
|
1535
1269
|
const cached = peekCache.get(key);
|
|
1536
1270
|
if (cached !== undefined && Date.now() - cached.at <= PEEK_CACHE_TTL_MS) {
|
|
@@ -1540,7 +1274,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1540
1274
|
peekCache.delete(key);
|
|
1541
1275
|
runtime.peekCacheBytes -= cached.bytes;
|
|
1542
1276
|
}
|
|
1543
|
-
// Coalesce per run; bound per session and globally (finding 10).
|
|
1544
1277
|
const flightKey = `${runId}:${editorMode ? "links" : "plain"}`;
|
|
1545
1278
|
const inFlight = peekInFlight.get(flightKey);
|
|
1546
1279
|
if (inFlight !== undefined)
|
|
@@ -1553,9 +1286,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1553
1286
|
peekBySession.set(sessionKey, (peekBySession.get(sessionKey) ?? 0) + 1);
|
|
1554
1287
|
const work = (async () => {
|
|
1555
1288
|
const seen = await observeWorktree(worktree, entries.entries, PEEK_LIMITS);
|
|
1556
|
-
// The fence, proved AGAIN after the walk (findings 16/28): the same
|
|
1557
|
-
// run still open, the same claim, the SAME epoch — or the whole
|
|
1558
|
-
// observation is discarded, never rendered, never cached.
|
|
1559
1289
|
const after = peekGuards(runId);
|
|
1560
1290
|
if (!after.ok || after.admit.epoch !== epoch) {
|
|
1561
1291
|
return peekSay("the checkout changed hands mid-look — nothing is shown");
|
|
@@ -1573,9 +1303,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1573
1303
|
if (changed.length === 0 && deleted.length === 0 && fresh.total === 0) {
|
|
1574
1304
|
parts.push(html `<p class="row">nothing has changed against the starting point yet</p>`);
|
|
1575
1305
|
}
|
|
1576
|
-
// A name is linked ONLY when sanitize provably changed nothing (arc 6,
|
|
1577
|
-
// finding 3): a masked or normalized label must never carry an href
|
|
1578
|
-
// that discloses what the mask hid. Collapsed labels never link.
|
|
1579
1306
|
const shownName = (path) => peekName(path);
|
|
1580
1307
|
const linkedName = (path) => {
|
|
1581
1308
|
const shown = shownName(path);
|
|
@@ -1609,8 +1336,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1609
1336
|
parts.push(html `<p class="meta">${seen.partial}</p>`);
|
|
1610
1337
|
let fragment = joinHtml(parts, "\n");
|
|
1611
1338
|
if (Buffer.byteLength(htmlString(fragment)) > PEEK_FRAGMENT_BYTES) {
|
|
1612
|
-
// The byte cap is enforced AFTER escaping (finding 32): an oversize
|
|
1613
|
-
// rendering is replaced whole by its exact counts.
|
|
1614
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>`;
|
|
1615
1340
|
}
|
|
1616
1341
|
const bytes = Buffer.byteLength(htmlString(fragment));
|
|
@@ -1632,10 +1357,7 @@ export function createTasksHandlers(runtime) {
|
|
|
1632
1357
|
peekBySession.set(sessionKey, left);
|
|
1633
1358
|
}
|
|
1634
1359
|
}
|
|
1635
|
-
|
|
1636
|
-
function taskMutation(response, who, taskId, verb, posted, now,
|
|
1637
|
-
/** Read only to shape an answer in place (answersInPlace), after the act's proofs. */
|
|
1638
|
-
request = null) {
|
|
1360
|
+
function taskMutation(response, who, taskId, verb, posted, now, request = null) {
|
|
1639
1361
|
const ref = store.lookupRef(taskId);
|
|
1640
1362
|
if (ref === null || store.getTask(taskId) === null) {
|
|
1641
1363
|
return refuse(response, who, 404, "no such task", "/tasks");
|
|
@@ -1646,21 +1368,13 @@ export function createTasksHandlers(runtime) {
|
|
|
1646
1368
|
switch (verb) {
|
|
1647
1369
|
case "steer": {
|
|
1648
1370
|
const body = readForm(posted, CONSOLE_FORMS.taskSteer);
|
|
1649
|
-
// Steering is a browser session's act, explicitly (arc 1 v2 §3):
|
|
1650
|
-
// identify() accepts bearer credentials generically, and those are
|
|
1651
|
-
// for machines — a person watching steers, cookie + CSRF only.
|
|
1652
1371
|
if (who.via !== "cookie") {
|
|
1653
1372
|
return refuse(response, who, 403, "steering is a browser session's act");
|
|
1654
1373
|
}
|
|
1655
|
-
// The same gates as a pause or a stop (the route's act scope already refuses a viewer; this says why).
|
|
1656
1374
|
if (who.role !== "approver")
|
|
1657
1375
|
return taskScreen(response, who, taskId, "your login can watch — sending an agent a note is an approver's act", 403);
|
|
1658
1376
|
if (store.isDemo())
|
|
1659
1377
|
return taskScreen(response, who, taskId, "the demo authorizes nothing", 403);
|
|
1660
|
-
// From the Agents view, the note is for the exact run on screen (live-conversation.md §6): filed only while that
|
|
1661
|
-
// run is still the task's live build, once per draft key. Nothing is filed on a refusal; the view keeps the draft.
|
|
1662
|
-
// An unsent note from an attempt that ended, sent on to the task's next attempt from that agent's page: filed
|
|
1663
|
-
// task-level, back to the same agent with its draft key so only a confirmed send clears the draft.
|
|
1664
1378
|
if (body.has("after")) {
|
|
1665
1379
|
const afterRaw = body.get("after") ?? "";
|
|
1666
1380
|
const keyRaw = body.get("key") ?? "";
|
|
@@ -1670,9 +1384,7 @@ export function createTasksHandlers(runtime) {
|
|
|
1670
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)) {
|
|
1671
1385
|
return taskScreen(response, who, taskId, "that note did not say which agent it came from, so nothing was sent", 400);
|
|
1672
1386
|
}
|
|
1673
|
-
// The same receipt as a send to that run: a draft already filed while it ran comes back as sent, not twice.
|
|
1674
1387
|
const filed = store.fileSteerNoteForRun(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now, { run: ended.id, key: keyRaw, onward: true });
|
|
1675
|
-
// From the task page or a flow card: back there with the draft's key (only that draft clears), or the refusal in words.
|
|
1676
1388
|
if (afterBack !== null) {
|
|
1677
1389
|
if (filed.ok)
|
|
1678
1390
|
return redirect(response, afterFlow !== null ? `/flows/${afterFlow.flow}?card=${afterFlow.card}&sent=${keyRaw}` : `${taskHref(taskId)}?sent=${keyRaw}#steering`);
|
|
@@ -1682,7 +1394,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1682
1394
|
return redirect(response, `/agents?run=${ended.id}&said=steered-next&sent=${keyRaw}`);
|
|
1683
1395
|
return redirect(response, `/agents?run=${ended.id}&said=${filed.reason === "task-finished" ? "steer-next-finished" : filed.reason === "key-reused" ? "steer-stale" : "steer-invalid"}`);
|
|
1684
1396
|
}
|
|
1685
|
-
// A form that asks for a run but names none properly is refused — never quietly filed unbound.
|
|
1686
1397
|
if (body.get("return") === "agents" || body.get("return") === "task" || returnedFlow(body.get("return")) !== null || body.has("run") || body.has("key")) {
|
|
1687
1398
|
const runRaw = body.get("run") ?? "";
|
|
1688
1399
|
const keyRaw = body.get("key") ?? "";
|
|
@@ -1694,22 +1405,17 @@ export function createTasksHandlers(runtime) {
|
|
|
1694
1405
|
const shown = store.getRun(Number(runRaw));
|
|
1695
1406
|
if (shown === null || shown.taskRef !== ref.id)
|
|
1696
1407
|
return taskScreen(response, who, taskId, "that run is not part of this task", 404);
|
|
1697
|
-
// An attempt that takes no notes (a planner, a scout, a reviewer, one repairing its handoff) is never filed one:
|
|
1698
|
-
// it would never read it (cockpit §4).
|
|
1699
1408
|
const capability = steerCapabilityOf(store, shown.id, now);
|
|
1700
1409
|
if (capability !== null && capability.send === null) {
|
|
1701
1410
|
return from === "agents" ? redirect(response, `/agents?run=${shown.id}&said=steer-no-notes`) : taskScreen(response, who, taskId, capability.words, 409);
|
|
1702
1411
|
}
|
|
1703
1412
|
const bound = store.fileSteerNoteForRun(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now, { run: shown.id, key: keyRaw });
|
|
1704
|
-
// From the task page: back to its steering card, or the refusal in words (the page keeps nothing to restore).
|
|
1705
1413
|
if (from === "task") {
|
|
1706
|
-
// Back where it was written (the task page, or a flow card's task), with its draft's key: only that draft clears.
|
|
1707
1414
|
if (bound.ok)
|
|
1708
1415
|
return redirect(response, flowBack !== null ? `/flows/${flowBack.flow}?card=${flowBack.card}&sent=${keyRaw}` : `${taskHref(taskId)}?sent=${keyRaw}#steering`);
|
|
1709
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"
|
|
1710
1417
|
: bound.reason === "invalid-note" ? "that note will not store" : "that form was already used — reload and send it again", 409);
|
|
1711
1418
|
}
|
|
1712
|
-
// The draft's own key comes back: only that draft is cleared from the box.
|
|
1713
1419
|
if (bound.ok)
|
|
1714
1420
|
return redirect(response, `/agents?run=${shown.id}&said=steered&sent=${keyRaw}`);
|
|
1715
1421
|
if (bound.reason === "attempt-ended" || bound.reason === "task-finished")
|
|
@@ -1718,7 +1424,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1718
1424
|
return redirect(response, `/agents?run=${shown.id}&said=steer-invalid`);
|
|
1719
1425
|
return redirect(response, `/agents?run=${shown.id}&said=steer-stale`);
|
|
1720
1426
|
}
|
|
1721
|
-
// The session IS the verified principal here — cookie + CSRF proved it.
|
|
1722
1427
|
const filed = store.fileSteerNote(taskId, verifiedAuthor(who.name), body.get("note") ?? "", now);
|
|
1723
1428
|
if (!filed.ok) {
|
|
1724
1429
|
const said = filed.reason === "task-finished"
|
|
@@ -1732,10 +1437,8 @@ export function createTasksHandlers(runtime) {
|
|
|
1732
1437
|
}
|
|
1733
1438
|
case "reply": {
|
|
1734
1439
|
const body = readForm(posted, CONSOLE_FORMS.taskReply);
|
|
1735
|
-
// A reply is steering, so it is a browser session's act too.
|
|
1736
1440
|
if (who.via !== "cookie")
|
|
1737
1441
|
return refuse(response, who, 403, "replying to an agent is a browser session's act");
|
|
1738
|
-
// The same gates as a pause: the route's act scope already refuses a viewer; these say why, and the demo answers nothing.
|
|
1739
1442
|
if (who.role !== "approver")
|
|
1740
1443
|
return taskScreen(response, who, taskId, "your login can watch — replying to an agent is an approver's act", 403);
|
|
1741
1444
|
if (store.isDemo())
|
|
@@ -1755,19 +1458,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1755
1458
|
if (reason.length > 200 || hasForbiddenControls(reason)) {
|
|
1756
1459
|
return taskScreen(response, who, taskId, "that reason will not render, so it will not store", 400);
|
|
1757
1460
|
}
|
|
1758
|
-
// Operator-owned only, always: the form supplies a reason, never an
|
|
1759
|
-
// owner. Decision, incident, and backoff holds are not reachable
|
|
1760
|
-
// from here, whatever a request claims.
|
|
1761
1461
|
store.hold(ref.id, reason, null, now);
|
|
1762
1462
|
return redirect(response, taskHref(taskId));
|
|
1763
1463
|
}
|
|
1764
1464
|
case "block": {
|
|
1765
1465
|
const body = readForm(posted, CONSOLE_FORMS.taskBlock);
|
|
1766
|
-
// Chains are scheduling, not authority (chains-and-next review,
|
|
1767
|
-
// finding 2): the edge decides WHEN the ready set admits the task;
|
|
1768
|
-
// approval still decides WHAT may build. Both ends are re-proved
|
|
1769
|
-
// here — existence and ceiling — and the
|
|
1770
|
-
// cycle refusal comes from the store's own closure check.
|
|
1771
1466
|
const on = (body.get("on") ?? "").trim();
|
|
1772
1467
|
const blocker = on === "" ? null : store.getTask(on);
|
|
1773
1468
|
const blockerRef = on === "" ? null : store.lookupRef(on);
|
|
@@ -1851,8 +1546,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1851
1546
|
}
|
|
1852
1547
|
case "reopen": {
|
|
1853
1548
|
const body = readForm(posted, CONSOLE_FORMS.taskReopen);
|
|
1854
|
-
// Authenticated like every approving act: the session alone may
|
|
1855
|
-
// read; resuming external work takes the password, typed again.
|
|
1856
1549
|
const token = (body.get("token") ?? "").trim();
|
|
1857
1550
|
const authenticated = token !== "" ? authenticateApprover(who, token) : null;
|
|
1858
1551
|
if (authenticated === null || !authenticated.ok) {
|
|
@@ -1879,7 +1572,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1879
1572
|
return redirect(response, taskHref(taskId));
|
|
1880
1573
|
}
|
|
1881
1574
|
case "stop-carrying": {
|
|
1882
|
-
// One click, any active approver (release-once.md): later commits of this release ask again. Only ever stricter.
|
|
1883
1575
|
const found = releaseAuthorityOfTask(store, taskId);
|
|
1884
1576
|
if (found === null)
|
|
1885
1577
|
return taskScreen(response, who, taskId, "This task isn't part of a release.", 409);
|
|
@@ -1890,14 +1582,11 @@ export function createTasksHandlers(runtime) {
|
|
|
1890
1582
|
}
|
|
1891
1583
|
case "requeue": {
|
|
1892
1584
|
const body = readForm(posted, CONSOLE_FORMS.taskRequeue);
|
|
1893
|
-
// Retry may carry a note for the next attempt: the same steering note, checked before anything changes.
|
|
1894
1585
|
const note = (body.get("note") ?? "").trim();
|
|
1895
1586
|
if (note !== "" && who.via !== "cookie")
|
|
1896
1587
|
return refuse(response, who, 403, "steering is a browser session's act");
|
|
1897
1588
|
if (note !== "" && !validateNote(note).ok)
|
|
1898
1589
|
return taskScreen(response, who, taskId, "that note will not store, so nothing was retried", 400);
|
|
1899
|
-
// Local-owner slice 3: the laptop's local owner retries its own approved build on its own road, bound to the
|
|
1900
|
-
// build and plan the page read. The same request again files no second note.
|
|
1901
1590
|
let replayed = false;
|
|
1902
1591
|
if (who.via === "cookie" && who.authority === "local-owner") {
|
|
1903
1592
|
const retried = localOwnerRetry(store, taskId, body.get("run"), body.get("digest"), now);
|
|
@@ -1916,14 +1605,10 @@ export function createTasksHandlers(runtime) {
|
|
|
1916
1605
|
if (!filed.ok)
|
|
1917
1606
|
return taskScreen(response, who, taskId, "Retried. The note wasn't saved; add it under Steering.", 409);
|
|
1918
1607
|
}
|
|
1919
|
-
// Allow-listed return only — never an arbitrary URL from the form.
|
|
1920
1608
|
return redirect(response, body.get("return") === "inbox" || body.get("return") === "next" ? "/" : taskHref(taskId));
|
|
1921
1609
|
}
|
|
1922
1610
|
case "follow-up": {
|
|
1923
1611
|
const body = readForm(posted, CONSOLE_FORMS.taskFollowUp);
|
|
1924
|
-
// A scout's proposed follow-up, filed by the operator's tap (mate
|
|
1925
|
-
// arc §10): the ONE filing door, this task's repository, the scope
|
|
1926
|
-
// text stamped as the scout's — mode coverage never seals it.
|
|
1927
1612
|
const indexRaw = body.get("index") ?? "";
|
|
1928
1613
|
if (!/^[0-9]{1,2}$/.test(indexRaw))
|
|
1929
1614
|
return taskScreen(response, who, taskId, "which follow-up?", 400);
|
|
@@ -1937,10 +1622,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1937
1622
|
return taskScreen(response, who, taskId, "this task has no repository — file the follow-up by hand", 409);
|
|
1938
1623
|
if (!visible(ref.repo))
|
|
1939
1624
|
return taskScreen(response, who, taskId, "that repository is outside what this server shows", 403);
|
|
1940
|
-
// Idempotent by construction (v4 review, finding 10): the filing's
|
|
1941
|
-
// id is derived from the source task, the report's run, and the
|
|
1942
|
-
// follow-up's place — a retried POST lands on the task the first
|
|
1943
|
-
// one filed instead of minting a twin.
|
|
1944
1625
|
const followUpId = `${taskId.slice(0, 40)}-r${view.run}-f${Number(indexRaw) + 1}`;
|
|
1945
1626
|
if (store.getTask(followUpId) !== null)
|
|
1946
1627
|
return redirect(response, taskHref(followUpId));
|
|
@@ -1949,10 +1630,6 @@ export function createTasksHandlers(runtime) {
|
|
|
1949
1630
|
title: followUp.title,
|
|
1950
1631
|
repo: ref.repo,
|
|
1951
1632
|
goal: followUp.goal,
|
|
1952
|
-
// v39: the scout's report format does not yet draft a rubric
|
|
1953
|
-
// per follow-up — a placeholder names the operator's own
|
|
1954
|
-
// review as the outstanding work, the same posture a
|
|
1955
|
-
// coordinator's bare intent takes.
|
|
1956
1633
|
acceptance: PLACEHOLDER_RUBRIC,
|
|
1957
1634
|
filedVia: "console", filedBy: { name: who.name, kind: "person" },
|
|
1958
1635
|
proposedVia: "scout",
|
|
@@ -1966,19 +1643,14 @@ export function createTasksHandlers(runtime) {
|
|
|
1966
1643
|
return redirect(response, taskHref(filed.id));
|
|
1967
1644
|
}
|
|
1968
1645
|
case "plan": {
|
|
1969
|
-
// Local-owner slice 2: the laptop's local owner asks on its own road, bound to the planning source it read.
|
|
1970
1646
|
if (who.via === "cookie" && who.authority === "local-owner") {
|
|
1971
1647
|
const asked = localOwnerPlan(store, taskId, readForm(posted, CONSOLE_FORMS.taskPlan).get("source"), now);
|
|
1972
1648
|
return asked.ok ? redirect(response, taskHref(taskId)) : taskScreen(response, who, taskId, asked.message, asked.status);
|
|
1973
1649
|
}
|
|
1974
|
-
// The operator's explicit ask, refused transactionally when the
|
|
1975
|
-
// moment has passed — approved scope, live claim, or a plan
|
|
1976
|
-
// already under way (Codex planning review's requestPlan guard).
|
|
1977
1650
|
const asked = store.requestPlan(ref.id, now);
|
|
1978
1651
|
if (!asked.ok) {
|
|
1979
1652
|
return taskScreen(response, who, taskId, `not planned: ${asked.reason}`, 409);
|
|
1980
1653
|
}
|
|
1981
|
-
// Only a full session: a local owner never pre-authorizes (plan-auto.ts refuses it there too).
|
|
1982
1654
|
if (who.via === "cookie" && who.authority === "full")
|
|
1983
1655
|
authorizePlanUnderMode(store, taskId, who.name, now);
|
|
1984
1656
|
return redirect(response, taskHref(taskId));
|
|
@@ -2043,10 +1715,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2043
1715
|
case "accept-revision":
|
|
2044
1716
|
case "reject-revision": {
|
|
2045
1717
|
const body = readForm(posted, CONSOLE_FORMS.taskRevision);
|
|
2046
|
-
// Adaptive execution plans (v44): resolving a revision the builder
|
|
2047
|
-
// filed while its authority snapshot no longer matched the run it
|
|
2048
|
-
// started under — the ONLY road a 'blocked' plan_revision reaches,
|
|
2049
|
-
// since a plan-only proposal auto-applies without ever pausing here.
|
|
2050
1718
|
if (who.via !== "cookie") {
|
|
2051
1719
|
return refuse(response, who, 403, "resolving a plan revision is a browser session's act");
|
|
2052
1720
|
}
|
|
@@ -2057,9 +1725,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2057
1725
|
}
|
|
2058
1726
|
const outcome = verb === "accept-revision" ? "applied" : "rejected";
|
|
2059
1727
|
if (outcome === "applied") {
|
|
2060
|
-
// Accepting a revision that changed signed scope or publication
|
|
2061
|
-
// authority takes the password ceremony again — the same act
|
|
2062
|
-
// that would be required to approve that authority from scratch.
|
|
2063
1728
|
const token = (body.get("token") ?? "").trim();
|
|
2064
1729
|
if (!authenticateApprover(who, token).ok) {
|
|
2065
1730
|
return taskScreen(response, who, taskId, "accepting this revision takes your password, typed again", 403);
|
|
@@ -2088,23 +1753,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2088
1753
|
}
|
|
2089
1754
|
case "route": {
|
|
2090
1755
|
const body = readForm(posted, CONSOLE_FORMS.taskRoute);
|
|
2091
|
-
// THE AGENTS EDIT (v47): an approver's session sets the size,
|
|
2092
|
-
// overrides one role to an exact agent, or clears an override — ONE
|
|
2093
|
-
// authenticated transaction in the store that CAS-checks the scope
|
|
2094
|
-
// digest the form rendered (empty = "I saw no scope"), records the
|
|
2095
|
-
// change under this name, reconciles the planner pin, re-files the
|
|
2096
|
-
// scope so a sealed route goes visibly stale, and re-requests a
|
|
2097
|
-
// drafted plan when the planner changed. The viewer gate above
|
|
2098
|
-
// already refused a watcher; a live claim refuses
|
|
2099
|
-
// inside the transaction.
|
|
2100
1756
|
const sizeGiven = body.get("size");
|
|
2101
1757
|
const riskyGiven = body.getAll("risky");
|
|
2102
1758
|
const phaseGiven = body.get("phase");
|
|
2103
1759
|
const clearGiven = body.get("clear-phase");
|
|
2104
|
-
// The agent arrives as the form's `provider|model` choice (v48) or,
|
|
2105
|
-
// for older clients, as separate fields — either way it must be one
|
|
2106
|
-
// of the CONFIGURED, role-valid choices right now: the form offers
|
|
2107
|
-
// nothing else, and the server believes nothing else.
|
|
2108
1760
|
const agentGiven = (body.get("agent") ?? "").trim();
|
|
2109
1761
|
const providerGiven = agentGiven === "" ? body.get("provider") : agentGiven.slice(0, agentGiven.indexOf("|") === -1 ? agentGiven.length : agentGiven.indexOf("|"));
|
|
2110
1762
|
const modelGiven = agentGiven === "" ? (body.get("model") ?? "").trim() : agentGiven.indexOf("|") === -1 ? "" : agentGiven.slice(agentGiven.indexOf("|") + 1).trim();
|
|
@@ -2116,7 +1768,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2116
1768
|
return taskScreen(response, who, taskId, "size is small, medium, or large", 400);
|
|
2117
1769
|
if (riskyGiven.some(one => one !== "yes" && one !== "no"))
|
|
2118
1770
|
return taskScreen(response, who, taskId, "risky is yes or no", 400);
|
|
2119
|
-
// A size keeps the task's risky flag unless the form says otherwise; marking risky keeps the size.
|
|
2120
1771
|
const sizeEdit = sizeGiven === null && riskyGiven.length === 0 ? undefined : {
|
|
2121
1772
|
size: sizeGiven !== null && isTaskSize(sizeGiven) ? sizeGiven : ref.sizing?.size ?? "medium",
|
|
2122
1773
|
risky: riskyGiven.includes("yes") ? true : riskyGiven.includes("no") ? false : ref.sizing?.risky ?? false,
|
|
@@ -2136,17 +1787,12 @@ export function createTasksHandlers(runtime) {
|
|
|
2136
1787
|
if ((phaseGiven === "plan" || phaseGiven === "review") && isAcpProvider(providerGiven))
|
|
2137
1788
|
return taskScreen(response, who, taskId, `${ACP_AGENTS[providerGiven].name} builds and repairs only — choose another agent to ${phaseGiven}`, 400);
|
|
2138
1789
|
}
|
|
2139
|
-
// The configured-choice proof lives INSIDE the edit transaction
|
|
2140
|
-
// (`configured`): the pair is held to the role's choices under the
|
|
2141
|
-
// configuration standing at that instant, and a stale choice
|
|
2142
|
-
// mutates nothing.
|
|
2143
1790
|
const edited = store.editTaskRoute(ref.id, {
|
|
2144
1791
|
by: who.name,
|
|
2145
1792
|
authenticate: () => {
|
|
2146
1793
|
const account = store.accountOf(who.name);
|
|
2147
1794
|
return account !== null && account.revokedAt === null && account.role === "approver" ? { ok: true } : { ok: false, reason: "your login is no longer an approver" };
|
|
2148
1795
|
},
|
|
2149
|
-
// A person's size replaces the classifier's; the risky flag rides with it.
|
|
2150
1796
|
...(sizeEdit === undefined ? {} : { size: sizeEdit }),
|
|
2151
1797
|
...(phase === null
|
|
2152
1798
|
? {}
|
|
@@ -2157,7 +1803,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2157
1803
|
if (!edited.ok) {
|
|
2158
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);
|
|
2159
1805
|
}
|
|
2160
|
-
// v102: changing how a task runs is authoring it — the requester rule then refuses this person too.
|
|
2161
1806
|
const routed = store.getScope(taskId);
|
|
2162
1807
|
if (routed !== null)
|
|
2163
1808
|
store.recordScopeAuthor(taskId, routed.digest, who.name, now);
|
|
@@ -2191,14 +1836,11 @@ export function createTasksHandlers(runtime) {
|
|
|
2191
1836
|
: qualityGiven === "default"
|
|
2192
1837
|
? "default"
|
|
2193
1838
|
: ref.qualityMode ?? store.qualityDefault().mode;
|
|
2194
|
-
// The optional per-attempt dollar cap (v15) rides the same form.
|
|
2195
1839
|
const budgetGiven = (body.get("budget-usd") ?? "").trim();
|
|
2196
1840
|
const budgetUsd = budgetGiven === "" ? null : Number(budgetGiven);
|
|
2197
1841
|
if (budgetUsd !== null && (!Number.isFinite(budgetUsd) || budgetUsd <= 0)) {
|
|
2198
1842
|
return taskScreen(response, who, taskId, "the dollar cap is a positive amount", 400);
|
|
2199
1843
|
}
|
|
2200
|
-
// The approval sheet's in-place editor carries the cap it was shown
|
|
2201
|
-
// exactly, in millionths, and "none" for no limit (never a default).
|
|
2202
1844
|
const exactBudgetGiven = body.get("budget-microusd");
|
|
2203
1845
|
const exactBudget = exactBudgetGiven === null ? undefined : exactBudgetGiven === "none" ? null : /^[1-9][0-9]{0,14}$/.test(exactBudgetGiven) ? Number(exactBudgetGiven) : NaN;
|
|
2204
1846
|
if (Number.isNaN(exactBudget))
|
|
@@ -2207,13 +1849,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2207
1849
|
let saved;
|
|
2208
1850
|
try {
|
|
2209
1851
|
saved = store.transact(() => {
|
|
2210
|
-
// C1/M3: the signer's own credentialed filing auto-approves —
|
|
2211
|
-
// coverage is asked INSIDE this transaction, the escalated
|
|
2212
|
-
// default and budget ride the filing, and the seal commits
|
|
2213
|
-
// atomically with it.
|
|
2214
|
-
// COOKIE ONLY (C1's channel table; surfaces round 1, finding 1):
|
|
2215
|
-
// bearer credentials are for machines, and a machine road must
|
|
2216
|
-
// never spend the signer's mode.
|
|
2217
1852
|
const coverage = who.via === "cookie"
|
|
2218
1853
|
? modeFilingCoverage(store, ref.repo, who.name, now)
|
|
2219
1854
|
: null;
|
|
@@ -2223,7 +1858,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2223
1858
|
goal: body.has("goal-brief") ? `${(body.get("goal") ?? "").trim()}${body.get("goal-brief")}` : body.get("goal") ?? "",
|
|
2224
1859
|
outOfScope: body.get("not") ?? null,
|
|
2225
1860
|
touches: (body.get("touches") ?? "").split(/[\n,]/),
|
|
2226
|
-
// The approval sheet's in-place editor sends Done when line by line.
|
|
2227
1861
|
acceptance: inPlace
|
|
2228
1862
|
? requirementsFromEditor(body, before?.acceptance ?? [])
|
|
2229
1863
|
: acceptanceLinesToInput((body.get("acceptance") ?? "").split("\n")),
|
|
@@ -2248,9 +1882,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2248
1882
|
message: proposed.message ?? (proposed.reason === "acceptance-required" ? "Not saved: add at least one requirement under Done when." : `scope not saved: ${proposed.reason}`),
|
|
2249
1883
|
};
|
|
2250
1884
|
}
|
|
2251
|
-
// Editing the plan in place never changes what the agent may do:
|
|
2252
|
-
// a save that would (a legacy setting, a newer policy or mode)
|
|
2253
|
-
// rolls back whole.
|
|
2254
1885
|
if (inPlace && before?.profile != null && proposed.scope.profile != null && levelOfProfile(before.profile) !== levelOfProfile(proposed.scope.profile)) {
|
|
2255
1886
|
throw new PermissionsWouldChange();
|
|
2256
1887
|
}
|
|
@@ -2261,7 +1892,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2261
1892
|
const filedScope = store.getScope(taskId);
|
|
2262
1893
|
if (filedScope?.profileState === "resolved") {
|
|
2263
1894
|
const sealedUnderMode = store.sealScopeApproval(taskId, who.name, now, {}, { kind: "mode", modeDigest: coverage.digest });
|
|
2264
|
-
// The quarantine speaks at the caller (review finding 7).
|
|
2265
1895
|
if (!sealedUnderMode) {
|
|
2266
1896
|
return { ok: false, status: 200, message: "scope saved — coordinator-filed: mode coverage cannot admit it; sign the scope" };
|
|
2267
1897
|
}
|
|
@@ -2276,8 +1906,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2276
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." };
|
|
2277
1907
|
}
|
|
2278
1908
|
if (!saved.ok) {
|
|
2279
|
-
// Refused because the plan moved on: the draft comes back with the version now on file, so saving it
|
|
2280
|
-
// again (having read the reason) can succeed instead of being refused the same way.
|
|
2281
1909
|
const draft = new URLSearchParams(body.sent);
|
|
2282
1910
|
if (saved.status === 409)
|
|
2283
1911
|
draft.set("sawDigest", store.getScope(taskId)?.digest ?? "");
|
|
@@ -2295,13 +1923,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2295
1923
|
: requestedReturn === null
|
|
2296
1924
|
? taskHref(taskId)
|
|
2297
1925
|
: safeChatReturn(requestedReturn);
|
|
2298
|
-
// The release sheet's Approve release (trusted-release-reports.md A7): the same door, its own page for words.
|
|
2299
1926
|
const sheet = body.get("sheet") === "release";
|
|
2300
|
-
// Each caller names its outcome (live-pages-and-home.md B2.3); none is inferred from the status.
|
|
2301
1927
|
const approvalProblem = (outcome, message, status) => {
|
|
2302
1928
|
if (sheet)
|
|
2303
1929
|
return releaseSheet.sheetScreen({ who, response, project: null }, taskId, message, status);
|
|
2304
|
-
// Asked in place: the same proofs ran, only the answer's shape differs.
|
|
2305
1930
|
if (answersInPlace(request))
|
|
2306
1931
|
return answerApprovalInPlace(response, outcome, message, status);
|
|
2307
1932
|
if (requestedReturn !== null && requestedReturn !== "next") {
|
|
@@ -2313,23 +1938,16 @@ export function createTasksHandlers(runtime) {
|
|
|
2313
1938
|
if (approvingRef?.plan === "requested") {
|
|
2314
1939
|
return approvalProblem("refused", "approval is blocked while planning is in progress — review the drafted plan first", 409);
|
|
2315
1940
|
}
|
|
2316
|
-
// Step-up: the session got you here; only the token agrees. The
|
|
2317
|
-
// digest names what was seen; the nonce proves this exact form was
|
|
2318
|
-
// rendered to this approver and is spent either way.
|
|
2319
1941
|
const digest = body.get("digest") ?? "";
|
|
2320
1942
|
const token = body.get("token") ?? "";
|
|
2321
1943
|
const nonce = body.get("nonce") ?? "";
|
|
2322
1944
|
if (!consumeApprovalNonce(nonce, who.name, taskId, digest)) {
|
|
2323
1945
|
return approvalProblem("refused", "that approval form is stale — read it again", 409);
|
|
2324
1946
|
}
|
|
2325
|
-
// An empty password stands for an explicit identity-provider re-check not yet spent, or (cockpit B2) a password
|
|
2326
|
-
// remembered on this session; approve() decides whether these terms may stand on a remembered one.
|
|
2327
|
-
// Easy-start C5: a laptop's local owner approves eligible work with no password (approve() proves it again).
|
|
2328
1947
|
if (token === "" && !passwordlessSessionFor(store, who.name) && !ssoNowAvailable(who.name) && withFreshness("approve-standard", () => freshnessFor(who.name)) === null
|
|
2329
1948
|
&& !(who.authority === "local-owner" && localApprovalEligible(store, who.name, taskId).ok)) {
|
|
2330
1949
|
return approvalProblem("refused", "approval requires your password, typed again", 400);
|
|
2331
1950
|
}
|
|
2332
|
-
// The sheet binds the release card's digest (the nonce was minted for it): the shared card wrapper decides.
|
|
2333
1951
|
if (sheet)
|
|
2334
1952
|
return releaseSheet.approveFromSheet({ who, response, project: null }, taskId, digest, token);
|
|
2335
1953
|
const scopeRow = store.getScope(taskId);
|
|
@@ -2340,21 +1958,14 @@ export function createTasksHandlers(runtime) {
|
|
|
2340
1958
|
if (digest !== expectedDigest) {
|
|
2341
1959
|
return approvalProblem("refused", "the scope or plan changed while this form was open — read the latest version and approve again", 409);
|
|
2342
1960
|
}
|
|
2343
|
-
// A revision approves ONLY against a brief that still verifies
|
|
2344
|
-
// (Codex M5-M8 audit, IV-3): the batch the screen restated must be
|
|
2345
|
-
// provably the batch on disk at the moment of the yes — a brief
|
|
2346
|
-
// deleted or corrupted between render and click blocks the
|
|
2347
|
-
// approval instead of silently approving comment-free work.
|
|
2348
1961
|
if (approvingRef !== null && approvingRef.revisionBriefArtifact !== null) {
|
|
2349
1962
|
const view = revisionViewOf(approvingRef);
|
|
2350
1963
|
if (view !== null && "problem" in view) {
|
|
2351
1964
|
return approvalProblem("refused", `approval is blocked: ${view.problem}`, 409);
|
|
2352
1965
|
}
|
|
2353
1966
|
}
|
|
2354
|
-
// A re-check is spent only if this yes is kept (sealed, or a protected-work vote recorded).
|
|
2355
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));
|
|
2356
1968
|
if (!approved.ok) {
|
|
2357
|
-
// v102: a first yes on protected work is recorded, not refused — the page says who else is needed.
|
|
2358
1969
|
if (approved.reason === "second-approver")
|
|
2359
1970
|
return approvalProblem("vote", gateWords({ verdict: "vote", have: approved.have, need: 2, already: approved.already }), 200);
|
|
2360
1971
|
if (approved.reason === "policy")
|
|
@@ -2362,13 +1973,9 @@ export function createTasksHandlers(runtime) {
|
|
|
2362
1973
|
const status = approved.reason === "changed" || approved.reason === "unrouted" ? 409 : 403;
|
|
2363
1974
|
return approvalProblem("refused", approveRefusalWords(approved.reason), status);
|
|
2364
1975
|
}
|
|
2365
|
-
// Approve & build again (the plan was rewritten after a build): the same yes requeues, only for the build the
|
|
2366
|
-
// sheet named, and only while it is still the task's latest result, made to an earlier plan than this one.
|
|
2367
1976
|
const rebuildRaw = body.get("rebuild") ?? "";
|
|
2368
1977
|
if (rebuildRaw !== "") {
|
|
2369
1978
|
const named = /^[0-9]{1,15}$/.test(rebuildRaw) ? store.getRun(Number(rebuildRaw)) : null;
|
|
2370
|
-
// Built to an earlier plan than the one just approved (the scope this approval sealed, scopeRow.digest);
|
|
2371
|
-
// requeueTask re-proves, in its own transaction, that it is still the latest result and that scope approved.
|
|
2372
1979
|
const offered = named != null && named.taskRef === ref.id && named.role === "builder" && !!named.scopeDigest && named.scopeDigest !== scopeRow.digest;
|
|
2373
1980
|
const requeued = offered ? store.requeueTask(taskId, who.name, now, { run: named.id, scopeDigest: scopeRow.digest }) : null;
|
|
2374
1981
|
if (requeued === null || (!requeued.ok && requeued.reason === "moved"))
|
|
@@ -2382,13 +1989,9 @@ export function createTasksHandlers(runtime) {
|
|
|
2382
1989
|
}
|
|
2383
1990
|
case "accept-proof": {
|
|
2384
1991
|
const body = readForm(posted, CONSOLE_FORMS.taskAcceptProof);
|
|
2385
|
-
// Accepting is a person's act, like approving a scope (Priority
|
|
2386
|
-
// 2): a cookie session only, never a bearer credential.
|
|
2387
1992
|
if (who.via !== "cookie") {
|
|
2388
1993
|
return refuse(response, who, 403, "accepting a proof is a browser session's act");
|
|
2389
1994
|
}
|
|
2390
|
-
// v40 fix: a reviewer run is never the attempt whose proof is
|
|
2391
|
-
// being accepted.
|
|
2392
1995
|
const latest = store.runsFor(ref.id).find(runIsTaskResult);
|
|
2393
1996
|
if (latest === undefined) {
|
|
2394
1997
|
return taskScreen(response, who, taskId, "this task has no finished attempt to accept", 404);
|
|
@@ -2406,9 +2009,7 @@ export function createTasksHandlers(runtime) {
|
|
|
2406
2009
|
}
|
|
2407
2010
|
note = validated.note;
|
|
2408
2011
|
}
|
|
2409
|
-
// A failed task's result is accepted only anyway, on purpose: with a reason.
|
|
2410
2012
|
if (note === null && store.getTask(taskId)?.state === "failed") {
|
|
2411
|
-
// Posted from the result page: back there, where the reason field is, with the refusal said on it.
|
|
2412
2013
|
const back = body.get("return") === null ? null : safeReturn(body.get("return"));
|
|
2413
2014
|
if (back !== null && back.startsWith("/review?"))
|
|
2414
2015
|
return redirect(response, withRefusal(back, "reason"));
|
|
@@ -2419,7 +2020,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2419
2020
|
}
|
|
2420
2021
|
case "complete": {
|
|
2421
2022
|
const body = readForm(posted, CONSOLE_FORMS.taskComplete);
|
|
2422
|
-
// The row admits only an approver's browser session; the principal re-proves that session's standing.
|
|
2423
2023
|
const principal = who.via === "cookie" ? leadPrincipal(who) : null;
|
|
2424
2024
|
if (principal === null)
|
|
2425
2025
|
return refuse(response, who, 403, "Your access changed. Sign in again.");
|
|
@@ -2430,8 +2030,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2430
2030
|
return taskScreen(response, who, taskId, "This result changed. Open the current result before marking it complete.", 409);
|
|
2431
2031
|
}
|
|
2432
2032
|
if (body.get("accept") === "1") {
|
|
2433
|
-
// Accept and finish: the person's acceptance and the completion of what it accepted, in one request
|
|
2434
|
-
// and one transaction. The receipt named is the one read, before accepting.
|
|
2435
2033
|
const rawNote = (body.get("note") ?? "").trim();
|
|
2436
2034
|
let note = null;
|
|
2437
2035
|
if (rawNote !== "") {
|
|
@@ -2447,8 +2045,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2447
2045
|
return redirect(response, publish ? `${taskHref(familyOf(taskId)?.root.id ?? taskId)}#merge` : body.get("return") === null ? reviewHref(taskId, Number(namedRun)) : safeReturn(body.get("return")));
|
|
2448
2046
|
}
|
|
2449
2047
|
if (body.get("publish") === "1") {
|
|
2450
|
-
// "Complete and open a pull request": the same exact-receipt completion, plus the owed PR for this
|
|
2451
|
-
// exact commit in one transaction. The watch process pushes and opens it; the task shows its progress.
|
|
2452
2048
|
const opened = completeAndOpenPullRequest(store, { taskId, digest, runId: Number(namedRun), who: principal, root: evidenceRoot }, now);
|
|
2453
2049
|
if (!opened.ok)
|
|
2454
2050
|
return taskScreen(response, who, taskId, opened.message, 409);
|
|
@@ -2457,7 +2053,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2457
2053
|
const completed = checkAssignmentAsOperator(store, taskId, digest, principal, now, evidenceRoot);
|
|
2458
2054
|
if (!completed.ok)
|
|
2459
2055
|
return taskScreen(response, who, taskId, completed.message, 409);
|
|
2460
|
-
// Back where it was completed (the task page's Result tab, or the result page), as Accept and finish does.
|
|
2461
2056
|
return redirect(response, body.get("return") === null ? reviewHref(taskId, Number(namedRun)) : safeReturn(body.get("return")));
|
|
2462
2057
|
}
|
|
2463
2058
|
case "retry-review": {
|
|
@@ -2465,12 +2060,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2465
2060
|
}
|
|
2466
2061
|
case "stop": {
|
|
2467
2062
|
const body = readForm(posted, CONSOLE_FORMS.taskStop);
|
|
2468
|
-
// The exact-run stop (v52): a browser session's act, an approver's
|
|
2469
|
-
// act, naming ONE run. The store's transaction proves the run is
|
|
2470
|
-
// this task's current live attempt and records who asked before
|
|
2471
|
-
// any process is signalled; the answer is "stopping", never
|
|
2472
|
-
// "stopped". A repeated post is the same request; a stale one (a
|
|
2473
|
-
// finished run, a successor) is refused in words.
|
|
2474
2063
|
if (who.via !== "cookie")
|
|
2475
2064
|
return refuse(response, who, 403, "stopping a task is a browser session's act");
|
|
2476
2065
|
if (who.role !== "approver")
|
|
@@ -2492,7 +2081,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2492
2081
|
return taskScreen(response, who, taskId, words[asked.reason] ?? asked.detail, 409);
|
|
2493
2082
|
}
|
|
2494
2083
|
const back = body.get("return") ?? "";
|
|
2495
|
-
// From the Agents board: back to the same agent, saying what happens now.
|
|
2496
2084
|
if (back === "agents")
|
|
2497
2085
|
return redirect(response, `/agents?run=${Number(named)}&said=stopping`);
|
|
2498
2086
|
const stopFlow = returnedFlow(back);
|
|
@@ -2502,10 +2090,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2502
2090
|
}
|
|
2503
2091
|
case "pause": {
|
|
2504
2092
|
const body = readForm(posted, CONSOLE_FORMS.taskPause);
|
|
2505
|
-
// Pause, and Pause and steer (live steering): a browser session's act, an approver's act, naming the ONE run
|
|
2506
|
-
// the page showed under the page's own request id. It stops the running Claude build's turn and keeps the
|
|
2507
|
-
// build; a note that rides along is filed in the same transaction and sent right after. mode=resume continues a
|
|
2508
|
-
// paused build with no note. Never a stop.
|
|
2509
2093
|
if (who.via !== "cookie")
|
|
2510
2094
|
return refuse(response, who, 403, "pausing a build is a browser session's act");
|
|
2511
2095
|
if (who.role !== "approver")
|
|
@@ -2516,7 +2100,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2516
2100
|
if (!/^[0-9]{1,15}$/.test(named))
|
|
2517
2101
|
return taskScreen(response, who, taskId, "which build? a pause names one exact run", 400);
|
|
2518
2102
|
const note = (body.get("note") ?? "").trim();
|
|
2519
|
-
// Resume: the paused build goes on where it stopped; no note is filed.
|
|
2520
2103
|
const asked = body.get("mode") === "resume"
|
|
2521
2104
|
? store.requestResume({ taskId, runId: Number(named), by: verifiedAuthor(who.name), via: "web", requestId: body.get("request") ?? "" }, now)
|
|
2522
2105
|
: store.requestPause({ taskId, runId: Number(named), by: verifiedAuthor(who.name), via: "web", requestId: body.get("request") ?? "", ...(note === "" ? {} : { note }) }, now);
|
|
@@ -2532,14 +2115,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2532
2115
|
return taskScreen(response, who, taskId, words[asked.reason] ?? asked.detail, asked.reason === "invalid-note" ? 400 : 409);
|
|
2533
2116
|
}
|
|
2534
2117
|
const back = body.get("return") ?? "";
|
|
2535
|
-
// A note that rode along came from a composer's draft: its key comes back, so only that draft clears.
|
|
2536
2118
|
const keyRaw = body.get("key") ?? "";
|
|
2537
|
-
// Only a note this request actually stored clears its draft: a repeated request answers with the note it stored
|
|
2538
|
-
// the first time, and a draft edited since is not that note.
|
|
2539
2119
|
const storedId = "note" in asked && typeof asked.note === "number" ? asked.note : null;
|
|
2540
2120
|
const stored = storedId === null ? null : store.handle.prepare("SELECT note FROM task_steer WHERE id = ?").get(storedId)?.["note"];
|
|
2541
2121
|
const sent = note !== "" && /^[A-Za-z0-9-]{8,64}$/.test(keyRaw) && typeof stored === "string" && stored.trim() === note ? keyRaw : null;
|
|
2542
|
-
// A note that rode along but is not the one this request stored (a reused form): said plainly, the draft kept.
|
|
2543
2122
|
if (note !== "" && (typeof stored !== "string" || stored.trim() !== note)) {
|
|
2544
2123
|
if (back === "agents")
|
|
2545
2124
|
return redirect(response, `/agents?run=${Number(named)}&said=pause-note-stale`);
|
|
@@ -2560,11 +2139,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2560
2139
|
}
|
|
2561
2140
|
case "resume": {
|
|
2562
2141
|
const body = readForm(posted, CONSOLE_FORMS.taskResume);
|
|
2563
|
-
// The resume itself (v52): password typed again + the durable nonce
|
|
2564
|
-
// consumed INSIDE the store's resume transaction against the digest
|
|
2565
|
-
// re-derived from live state. A replay finds the nonce spent; a
|
|
2566
|
-
// changed approval finds the digest moved; a successor attempt finds
|
|
2567
|
-
// the run superseded — each refuses without starting work; a submitted nonce remains one-shot.
|
|
2568
2142
|
if (who.via !== "cookie")
|
|
2569
2143
|
return refuse(response, who, 403, "resuming a task is a browser session's act");
|
|
2570
2144
|
if (who.role !== "approver")
|
|
@@ -2612,10 +2186,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2612
2186
|
return refuse(response, who, 404, "That action isn't available here.", taskHref(taskId));
|
|
2613
2187
|
}
|
|
2614
2188
|
}
|
|
2615
|
-
/** The queue as a region: dispatch order per column, drag handles and
|
|
2616
|
-
* all — the /queue page's body, and the board's "order" view (the one
|
|
2617
|
-
* place dragging exists, because reordering and reserving are scheduling,
|
|
2618
|
-
* never authority). */
|
|
2619
2189
|
function queueRegionFor(project, csrf, revision, now) {
|
|
2620
2190
|
const tasks = store.queueScoped(project, now).map(one => ({
|
|
2621
2191
|
...one,
|
|
@@ -2638,23 +2208,12 @@ export function createTasksHandlers(runtime) {
|
|
|
2638
2208
|
}));
|
|
2639
2209
|
return queueBody(tasks, workers, revision, store.queueRevision());
|
|
2640
2210
|
}
|
|
2641
|
-
/** An OBSERVED CI failure on a completed row's PR — the open episode the
|
|
2642
|
-
* watcher recorded for exactly that repository and number; never a guess
|
|
2643
|
-
* from quiet. One indexed publication read per row that has a PR. */
|
|
2644
2211
|
function ciFailingFor(runId, prNumber) {
|
|
2645
2212
|
if (runId === null || prNumber === null)
|
|
2646
2213
|
return false;
|
|
2647
2214
|
const publication = store.publicationForRun(runId);
|
|
2648
2215
|
return publication !== null && publication.prNumber === prNumber && store.hasOpenCiEpisode(publication.githubRepo, prNumber);
|
|
2649
2216
|
}
|
|
2650
|
-
/**
|
|
2651
|
-
* One completed row by task id, for a `?result=` deep link the bounded
|
|
2652
|
-
* queue could not show — the done list's own predicate, re-proved per
|
|
2653
|
-
* read: the task is done, sits in this project (or in none), and its
|
|
2654
|
-
* repository passes the ceiling; the result run is the newest finished
|
|
2655
|
-
* built/no-change builder or scout attempt. Anything else is
|
|
2656
|
-
* null, and null reads exactly like a task that never existed.
|
|
2657
|
-
*/
|
|
2658
2217
|
function completedRowFor(taskId, project) {
|
|
2659
2218
|
const family = familyOf(taskId);
|
|
2660
2219
|
if (family === null)
|
|
@@ -2670,15 +2229,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2670
2229
|
(one.role === "builder" || one.role === "scout")) ?? null;
|
|
2671
2230
|
return resultRowOf(task, ref.repo, family.problem, run);
|
|
2672
2231
|
}
|
|
2673
|
-
/**
|
|
2674
|
-
* A build attempt that didn't deliver a result (failed, refused, stopped,
|
|
2675
|
-
* never finished) still has a result page: its changes, its checks and what
|
|
2676
|
-
* went wrong. The row for one: the run named by `runId` when it is an ended
|
|
2677
|
-
* builder or scout attempt of this task that isn't a delivered result, or a
|
|
2678
|
-
* failed task's latest attempt; with no run named, that latest attempt. The
|
|
2679
|
-
* same admission as a completed row: in this project (or none) and inside
|
|
2680
|
-
* the ceiling. Null otherwise, which reads like a task that never existed.
|
|
2681
|
-
*/
|
|
2682
2232
|
function attemptRowFor(taskId, runId, project) {
|
|
2683
2233
|
const family = familyOf(taskId);
|
|
2684
2234
|
const task = store.getTask(taskId);
|
|
@@ -2690,7 +2240,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2690
2240
|
const attempts = store.runsFor(ref.id).filter(one => (one.role === "builder" || one.role === "scout") && (one.finishedAt !== null || one.outcome !== null));
|
|
2691
2241
|
const latest = task.state === "failed" ? latestFinishedAttempt(attempts) : null;
|
|
2692
2242
|
const run = runId !== null ? attempts.find(one => one.id === runId) ?? null : latest;
|
|
2693
|
-
// A delivered result has its completed row; a failed task's latest attempt is what failed, whatever it ended as.
|
|
2694
2243
|
if (run === null || runIsLive(run) || ((run.outcome === "built" || run.outcome === "no-change") && run.id !== latest?.id))
|
|
2695
2244
|
return null;
|
|
2696
2245
|
return resultRowOf(task, ref.repo, family.problem, run);
|
|
@@ -2726,8 +2275,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2726
2275
|
function reviewCockpitViewOf(row, who, now) {
|
|
2727
2276
|
const ref = store.lookupRef(row.taskId);
|
|
2728
2277
|
const scope = store.getScope(row.taskId);
|
|
2729
|
-
// The result run, read once: the shared result detail below hangs off
|
|
2730
|
-
// this one record.
|
|
2731
2278
|
const run = row.runId === null ? null : store.getRun(row.runId);
|
|
2732
2279
|
const intent = scope === null
|
|
2733
2280
|
? null
|
|
@@ -2785,39 +2332,27 @@ export function createTasksHandlers(runtime) {
|
|
|
2785
2332
|
summary: detail.handoff?.conclusion ?? run.handoff,
|
|
2786
2333
|
},
|
|
2787
2334
|
detail,
|
|
2788
|
-
// How it ran: derived from the run's own records once it has finished, display only. A read ahead of the page's
|
|
2789
|
-
// link (x-toolroll-read: prefetch) derives it and saves nothing.
|
|
2790
2335
|
efficiency: (() => { try {
|
|
2791
2336
|
return runEfficiencyOf(store, evidenceRoot, run.id, now, requestContext.getStore()?.readPurpose !== "prefetch");
|
|
2792
2337
|
}
|
|
2793
2338
|
catch {
|
|
2794
2339
|
return null;
|
|
2795
2340
|
} })(),
|
|
2796
|
-
// What its network was and what its proxy saw (egress.ts), display only.
|
|
2797
2341
|
network: store.runNetwork(run.id),
|
|
2798
|
-
// Where the time went: its release check's parts and the task's deploys (latency-timeline.ts), display only.
|
|
2799
2342
|
timing: timingFor(store, run.id, row.taskId),
|
|
2800
|
-
// How far its checks reached (check-access.ts), display only.
|
|
2801
2343
|
checkAccess: store.runCheckAccess(run.id),
|
|
2802
|
-
// How its checks actually ran, by what was stamped at launch: said only for a result whose checks ran.
|
|
2803
2344
|
checkRan: store.artifactsFor(run.id).some(one => one.kind === "check-log") ? ranWords(runCheckStamp(store, run.id)) : null,
|
|
2804
2345
|
reviewRetry: store.reviewRetryStateOf(run.id),
|
|
2805
2346
|
review: reviewFactsFor(run.id),
|
|
2806
2347
|
notes: store.notesForRun(run.id),
|
|
2807
2348
|
};
|
|
2808
2349
|
}
|
|
2809
|
-
// ---- evidence ------------------------------------------------------------
|
|
2810
2350
|
function decisionEvidence(response, decisionId, artifactId) {
|
|
2811
|
-
// The ceiling applies to decision evidence exactly as to run evidence
|
|
2812
|
-
// (v2 review, finding 2): a decision whose task belongs to a repo this
|
|
2813
|
-
// server may not serve does not exist here, and neither do its bytes.
|
|
2814
2351
|
const decision = store.getDecision(decisionId);
|
|
2815
2352
|
const decisionRun = decision === null ? null : store.getRun(decision.run);
|
|
2816
2353
|
if (decisionRun !== null && !visible(taskRepoOf(decisionRun.taskRef))) {
|
|
2817
2354
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
2818
2355
|
}
|
|
2819
|
-
// Only through the decision's own relation — an artifact id from another
|
|
2820
|
-
// run simply is not in this list, whatever the URL claims.
|
|
2821
2356
|
const linked = store.evidenceFor(decisionId).find(one => one.id === artifactId);
|
|
2822
2357
|
if (linked === undefined) {
|
|
2823
2358
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
@@ -2829,8 +2364,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2829
2364
|
if (run === null || !runVisible(run)) {
|
|
2830
2365
|
return respond(response, 404, "text/plain; charset=utf-8", "no such run");
|
|
2831
2366
|
}
|
|
2832
|
-
// Membership is the lookup's own predicate — there is no way to check
|
|
2833
|
-
// the run and fetch the artifact as two separate acts here.
|
|
2834
2367
|
const linked = store.artifactForRun(runId, artifactId);
|
|
2835
2368
|
if (linked === null) {
|
|
2836
2369
|
return respond(response, 404, "text/plain; charset=utf-8", "no such evidence");
|
|
@@ -2842,9 +2375,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2842
2375
|
if (!read.ok) {
|
|
2843
2376
|
return respond(response, 410, "text/plain; charset=utf-8", "the evidence no longer matches its record");
|
|
2844
2377
|
}
|
|
2845
|
-
// A validated screenshot is the one evidence kind meant to render
|
|
2846
|
-
// inline (thumbnails, full-image links) — every other kind stays a
|
|
2847
|
-
// downloaded text record, exactly as before.
|
|
2848
2378
|
if (linked.kind === "screenshot") {
|
|
2849
2379
|
const imageType = linked.key.endsWith(".png") ? "image/png" : linked.key.endsWith(".jpg") ? "image/jpeg" : null;
|
|
2850
2380
|
if (imageType !== null) {
|
|
@@ -2860,7 +2390,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2860
2390
|
});
|
|
2861
2391
|
response.end(read.content);
|
|
2862
2392
|
}
|
|
2863
|
-
/** The full guard list (v3 §4) — run on every request, hit or miss. */
|
|
2864
2393
|
function peekGuards(runId) {
|
|
2865
2394
|
if (options.localRunner === undefined || options.poolRoot === undefined) {
|
|
2866
2395
|
return { ok: false, message: "live peek is off — start serve with --runner <name> naming this machine's runner", final: true };
|
|
@@ -2870,17 +2399,11 @@ export function createTasksHandlers(runtime) {
|
|
|
2870
2399
|
return { ok: false, message: "no such build", final: true };
|
|
2871
2400
|
if (run.outcome !== null)
|
|
2872
2401
|
return { ok: false, message: "this build has finished — the final diff below is the record", final: true };
|
|
2873
|
-
// The reviewer role (v29): artifact-only, honestly — there is no
|
|
2874
|
-
// checkout anywhere to watch, and there never was.
|
|
2875
2402
|
if (run.worktree === null) {
|
|
2876
2403
|
return { ok: false, message: "this run reviewed the sealed diff — no workspace existed to watch", final: true };
|
|
2877
2404
|
}
|
|
2878
2405
|
if (run.baseRevision === null)
|
|
2879
2406
|
return { ok: false, message: "the build has not settled its starting point yet" };
|
|
2880
|
-
// The run's lease must be the task's CURRENT live lease — max generation,
|
|
2881
|
-
// unreleased, strictly unexpired. liveClaimByLease proves only that the
|
|
2882
|
-
// lease exists; a superseded lease would still pass it (round-4
|
|
2883
|
-
// finding 15), and superseded is forever, so the poller may stop.
|
|
2884
2407
|
if (store.currentLiveLease(run.taskRef, clock()) !== run.leaseId) {
|
|
2885
2408
|
return { ok: false, message: "the build is not actively running right now", final: true };
|
|
2886
2409
|
}
|
|
@@ -2890,8 +2413,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2890
2413
|
if (row.runner !== options.localRunner) {
|
|
2891
2414
|
return { ok: false, message: "this build runs on another machine — open the console there to watch it", final: true };
|
|
2892
2415
|
}
|
|
2893
|
-
// Adoption-path rows can carry no epoch (round-3 finding 37): no fence,
|
|
2894
|
-
// no peek — never a guess.
|
|
2895
2416
|
if (row.leaseEpoch === null || row.leaseEpoch === undefined) {
|
|
2896
2417
|
return { ok: false, message: "this checkout was set up before live watching existed — the next fresh build can be watched", final: true };
|
|
2897
2418
|
}
|
|
@@ -2905,8 +2426,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2905
2426
|
catch {
|
|
2906
2427
|
return { ok: false, message: "the checkout could not be found on this machine" };
|
|
2907
2428
|
}
|
|
2908
|
-
// The snapshot: exactly one successful, untruncated base-tree artifact
|
|
2909
|
-
// whose envelope binds THIS run and THIS base (round-3 finding 42).
|
|
2910
2429
|
const artifact = store.artifactsFor(runId).find(one => one.kind === "base-tree");
|
|
2911
2430
|
if (artifact === undefined)
|
|
2912
2431
|
return { ok: false, message: "no base snapshot was captured for this build" };
|
|
@@ -2922,7 +2441,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2922
2441
|
}
|
|
2923
2442
|
return { ok: true, admit: { run, worktree: run.worktree, epoch: row.leaseEpoch, entries: snapshot } };
|
|
2924
2443
|
}
|
|
2925
|
-
/** The live subset of a bounded run page \u2014 one indexed lookup per row. */
|
|
2926
2444
|
function liveRunIds(rows) {
|
|
2927
2445
|
const live = new Set();
|
|
2928
2446
|
for (const run of rows)
|
|
@@ -2932,7 +2450,6 @@ export function createTasksHandlers(runtime) {
|
|
|
2932
2450
|
}
|
|
2933
2451
|
const tidyHandlers = createTidyHandlers(runtime);
|
|
2934
2452
|
const releaseSheet = createReleaseSheetHandlers(runtime);
|
|
2935
|
-
/** The question page, with a refusal in its box when an answer was refused (the box keeps the choice to make). */
|
|
2936
2453
|
function decisionScreen(ctx, id, back, refusal, code, now, draft) {
|
|
2937
2454
|
const { who, response, project } = ctx;
|
|
2938
2455
|
const decision = store.getDecision(id);
|
|
@@ -2959,13 +2476,10 @@ export function createTasksHandlers(runtime) {
|
|
|
2959
2476
|
"code.changes-read": showCode("changes", true),
|
|
2960
2477
|
"code.ship-preview": showCode("ship", true),
|
|
2961
2478
|
"code.other": showCode("unknown"),
|
|
2962
|
-
// Retired into Tasks and the task page (src/design/KIT.md): each old address still answers, as a redirect.
|
|
2963
|
-
// Retired pages (docs/plans/plain-toolroll.md P1.4): permanent redirects, no page handler of their own.
|
|
2964
2479
|
"inbox": async (ctx) => retiredRedirect("inbox", ctx.url, ctx.response),
|
|
2965
2480
|
"work": async (ctx) => retiredRedirect("work", ctx.url, ctx.response),
|
|
2966
2481
|
"next": async (ctx) => retiredRedirect("next", ctx.url, ctx.response),
|
|
2967
2482
|
"board": async (ctx) => retiredRedirect("board", ctx.url, ctx.response),
|
|
2968
|
-
// A result keeps its own page; the bare list moved to Tasks' Ready view.
|
|
2969
2483
|
"review": async (ctx) => ctx.url.searchParams.has("result") ? showReview(ctx) : retiredRedirect("review", ctx.url, ctx.response),
|
|
2970
2484
|
"done": async (ctx) => retiredRedirect("done", ctx.url, ctx.response),
|
|
2971
2485
|
"tasks": showTasks,
|
|
@@ -3036,33 +2550,26 @@ export function createTasksHandlers(runtime) {
|
|
|
3036
2550
|
"session.editor-links": sessionEditorLinks,
|
|
3037
2551
|
"incident.resolve": resolveIncident,
|
|
3038
2552
|
});
|
|
3039
|
-
/** The add page, once more: blank, from a shipped template (`?template=`, as the old task list did), or with a refused
|
|
3040
|
-
* filing's own words and status (the draft keeps the project revision it was written against). */
|
|
3041
2553
|
function newTaskScreen(ctx, status, problem, draft, text = null) {
|
|
3042
2554
|
const { who, response, project } = ctx;
|
|
3043
2555
|
const chainable = store
|
|
3044
2556
|
.listTasksScoped(project, undefined, 100, null)
|
|
3045
2557
|
.filter(one => one.state !== "done" && one.state !== "cancelled" && visible(one.repo))
|
|
3046
2558
|
.map(one => ({ id: one.id, title: one.title }));
|
|
3047
|
-
// A refused draft keeps the task it was to start after, even if the refreshed list no longer carries it.
|
|
3048
2559
|
const after = draft?.values?.get("after") ?? "";
|
|
3049
2560
|
if (after !== "" && !chainable.some(one => one.id === after))
|
|
3050
2561
|
chainable.unshift({ id: after, title: "(as submitted)" });
|
|
3051
2562
|
const chrome = chromeFor(project, "tasks");
|
|
3052
2563
|
const revision = draft?.values !== undefined ? undefined : who.via === "cookie" ? who.session.projectRevision : 0;
|
|
3053
|
-
// Ideas for the project the box starts on: what the first run found there (issues, TODOs), else the safe generic
|
|
3054
|
-
// ones while the first run is open; none once someone has filed work and nothing was found.
|
|
3055
2564
|
const startsOn = draft?.values?.get("repo") ?? project ?? chrome.projects?.[0]?.path ?? null;
|
|
3056
2565
|
const found = startsOn === null ? null : runtime.firstTasks.get(startsOn)?.found ?? null;
|
|
3057
2566
|
const ideas = found ?? (runtime.firstRunStepsNow(ctx.now) !== null && !store.hasAnyWork() ? firstTaskSuggestions({ issues: [], todos: [] }) : []);
|
|
3058
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));
|
|
3059
2568
|
}
|
|
3060
|
-
/** What the password rule reads for this request (approval-password.ts), the same facts the approve forms read. */
|
|
3061
2569
|
function fastPasswordFacts(who) {
|
|
3062
2570
|
return { passwordless: passwordlessSessionFor(store, who.name), localOwner: who.via === "cookie" && who.authority === "local-owner",
|
|
3063
2571
|
freshAt: withFreshness("approve-standard", () => freshnessFor(who.name, Date.now(), true))?.at ?? null, returnTo: "/tasks/new" };
|
|
3064
2572
|
}
|
|
3065
|
-
/** Build: the fast start's one write. Every check is made again inside fastStartBuild's transaction. */
|
|
3066
2573
|
async function buildNow(ctx) {
|
|
3067
2574
|
const { who, response, now, posted } = ctx;
|
|
3068
2575
|
const body = readForm(posted, CONSOLE_FORMS.tasksFast);
|
|
@@ -3082,7 +2589,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3082
2589
|
actionContext.createdTask = built.taskId;
|
|
3083
2590
|
return redirect(response, taskHref(built.taskId));
|
|
3084
2591
|
}
|
|
3085
|
-
/** "Approve it to keep it": a fast start that grew gets a plan for its exact commit, on the ordinary approval. It seals nothing. */
|
|
3086
2592
|
async function keepGrown(ctx) {
|
|
3087
2593
|
const { url, who, response, now, posted } = ctx;
|
|
3088
2594
|
readForm(posted, CONSOLE_FORMS.keepGrown);
|
|
@@ -3094,8 +2600,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3094
2600
|
return taskScreen(response, who, act.taskId, kept.message, 409);
|
|
3095
2601
|
return redirect(response, taskHref(act.taskId));
|
|
3096
2602
|
}
|
|
3097
|
-
/** Findings, a failed check's repair and evidence (render-follow-through.ts). Nothing here is an approval: a repair is a
|
|
3098
|
-
* draft, and its task page asks for the plan's approval as any other. */
|
|
3099
2603
|
async function followThroughAct(ctx) {
|
|
3100
2604
|
const { url, who, response, now, posted } = ctx;
|
|
3101
2605
|
const body = readForm(posted, CONSOLE_FORMS.followThrough);
|
|
@@ -3103,13 +2607,11 @@ export function createTasksHandlers(runtime) {
|
|
|
3103
2607
|
if (act === null)
|
|
3104
2608
|
return noPage(who, response);
|
|
3105
2609
|
const { taskId } = act;
|
|
3106
|
-
// Chat's gate, here too (findings.ts familyInReach): every project in this task's family, not only this page's.
|
|
3107
2610
|
if (familyInWebReach(store, who, taskId, visible) === null)
|
|
3108
2611
|
return refuse(response, who, 403, "That task is outside your access.", "/tasks");
|
|
3109
2612
|
const number = (name) => Number(body.get(name) ?? "");
|
|
3110
2613
|
const back = () => redirect(response, `${taskHref(taskId)}#findings`);
|
|
3111
2614
|
const refused = (message) => taskScreen(response, who, taskId, message, 409);
|
|
3112
|
-
/** A finding or a run named by a form must belong to this task's family: this page's project was the one admitted. */
|
|
3113
2615
|
const ownFinding = () => { const found = getFinding(store, number("finding")); return found !== null && found.familyRoot === familyRootOf(store, taskId) ? found : null; };
|
|
3114
2616
|
const ownRun = () => runOnTask(store, number("run"), taskId);
|
|
3115
2617
|
switch (body.get("act")) {
|
|
@@ -3167,9 +2669,6 @@ export function createTasksHandlers(runtime) {
|
|
|
3167
2669
|
}
|
|
3168
2670
|
return { registrations, runListPane, peekFragment, taskMutation, queueRegionFor, ciFailingFor, completedRowFor, attemptRowFor, resultRowOf, reviewCockpitViewOf, decisionEvidence, runEvidence, sendArtifact, peekGuards, liveRunIds };
|
|
3169
2671
|
}
|
|
3170
|
-
/** Put away and Restore one task, and Put away old tasks (docs/plans/task-tidy.md): the preview reads only (GET-quiet);
|
|
3171
|
-
* putting away many is an approver's step-up bound to the digest of exactly what the preview showed. Each write
|
|
3172
|
-
* re-proves the person's standing inside its own transaction. */
|
|
3173
2672
|
export function createTidyHandlers(runtime) {
|
|
3174
2673
|
const { store, sendScreen, chromeFor, authenticateApprover, workAccess, bustBadge } = runtime;
|
|
3175
2674
|
async function showPutAway(ctx) {
|
|
@@ -3216,19 +2715,11 @@ export function createTidyHandlers(runtime) {
|
|
|
3216
2715
|
return { "tasks.archive": showPutAway, "work.put-away": async (ctx) => retiredRedirect("work.put-away", ctx.url, ctx.response),
|
|
3217
2716
|
"work.put-away.apply": applyPutAway, "task.act.archive": oneTask("archive"), "task.act.restore": oneTask("restore") };
|
|
3218
2717
|
}
|
|
3219
|
-
/** A retired page's GET alias: a plain 302 (the shared 303 helper belongs to POST landings), as pages.ts morningAlias. */
|
|
3220
2718
|
function redirectGet(response, to) {
|
|
3221
2719
|
response.writeHead(302, { ...SAFETY, Location: to });
|
|
3222
2720
|
response.end();
|
|
3223
2721
|
}
|
|
3224
|
-
/** How many cards a Board column shows; the column's count covers them all and its "View all" opens the list. */
|
|
3225
2722
|
export const BOARD_COLUMN_LIMIT = 40;
|
|
3226
|
-
/**
|
|
3227
|
-
* Easy-start C1 (N1): the two writes a page load used to make, as keyed POSTs the shell sends (wave 1c wires the
|
|
3228
|
-
* browser). `agents.seen`: a finished result this person opened leaves their unread Done. `agents.watch`: hold (on each
|
|
3229
|
-
* keep-alive) or release (on unload) the short lease that quiets chat pings while this person's page shows the agent.
|
|
3230
|
-
* Each re-proves the run is in the person's projects; a reply carries nothing else.
|
|
3231
|
-
*/
|
|
3232
2723
|
export function createAgentSignalHandlers(runtime) {
|
|
3233
2724
|
const { store, runVisible } = runtime;
|
|
3234
2725
|
const answer = (response, status, ok) => respond(response, status, "application/json", JSON.stringify({ ok }));
|
|
@@ -3243,7 +2734,6 @@ export function createAgentSignalHandlers(runtime) {
|
|
|
3243
2734
|
const run = visibleRun(who, readForm(posted, CONSOLE_FORMS.agentSeen).get("run"));
|
|
3244
2735
|
if (run === null)
|
|
3245
2736
|
return answer(response, 404, false);
|
|
3246
|
-
// Only once it finished: a page shown while it ran saw no finished version (cockpit §3).
|
|
3247
2737
|
if (run.finishedAt === null)
|
|
3248
2738
|
return answer(response, 409, false);
|
|
3249
2739
|
markAgentSeen(store, who.name, run.id, now);
|
|
@@ -3267,17 +2757,9 @@ export function createAgentSignalHandlers(runtime) {
|
|
|
3267
2757
|
}
|
|
3268
2758
|
return { "agents.seen": agentSeen, "agents.watch": agentWatch };
|
|
3269
2759
|
}
|
|
3270
|
-
/**
|
|
3271
|
-
* One-tap release approval (docs/plans/trusted-release-reports.md, slice A): the sheet (`/t/<id>/release`), the push's
|
|
3272
|
-
* opaque locator (`/approve/<task ref>`, a GET that only redirects to the sheet) and the sheet's approval, which the
|
|
3273
|
-
* task approval POST hands here once its shared checks (cookie session, CSRF and the browser key at admission, the
|
|
3274
|
-
* single-use nonce, a password or a standing proof) passed. The approval itself is the shared card wrapper around the
|
|
3275
|
-
* unchanged approve() (release-approval.ts approveReleaseCard).
|
|
3276
|
-
*/
|
|
3277
2760
|
export function createReleaseSheetHandlers(runtime) {
|
|
3278
2761
|
const { store, sendScreen, chromeFor, visible, mintApprovalNonce, clock, authenticateApprover } = runtime;
|
|
3279
2762
|
const missing = (who, response) => refuse(response, who, 404, "There's no release waiting for approval at this address.", "/work");
|
|
3280
|
-
/** The sheet, with a problem said where it happened. */
|
|
3281
2763
|
function sheetScreen(ctx, taskId, problem, status) {
|
|
3282
2764
|
const { who, response, project } = ctx;
|
|
3283
2765
|
const ref = store.lookupRef(taskId);
|
|
@@ -3288,7 +2770,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3288
2770
|
return missing(who, response);
|
|
3289
2771
|
const card = built.card;
|
|
3290
2772
|
const open = card.approved === null && card.refusal === null;
|
|
3291
|
-
// This computer's local owner can't approve a release: the full sign-in comes first (scope.ts localApprovalEligible).
|
|
3292
2773
|
const local = who.via === "cookie" && who.authority === "local-owner" ? localOwnerRefusal(store.accountOf(who.name)?.passwordSet === true, releaseSheetHref(taskId)) : null;
|
|
3293
2774
|
const nonce = open && local === null && who.via === "cookie" && who.role === "approver" ? mintApprovalNonce(who.name, taskId, card.digest) : "";
|
|
3294
2775
|
const remembered = (() => {
|
|
@@ -3308,7 +2789,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3308
2789
|
return missing(ctx.who, ctx.response);
|
|
3309
2790
|
return sheetScreen(ctx, task.taskId, null, 200);
|
|
3310
2791
|
}
|
|
3311
|
-
/** The push's locator: proved a release in the person's projects from the plane's own state, then only redirected. */
|
|
3312
2792
|
async function locate(ctx) {
|
|
3313
2793
|
const { who, response, url } = ctx;
|
|
3314
2794
|
const raw = /^\/approve\/([1-9][0-9]{0,14})$/.exec(url.pathname)?.[1];
|
|
@@ -3317,7 +2797,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3317
2797
|
return missing(who, response);
|
|
3318
2798
|
return redirect(response, releaseSheetHref(ref.externalId));
|
|
3319
2799
|
}
|
|
3320
|
-
/** The sheet's Approve release, after the approval POST's shared checks. */
|
|
3321
2800
|
function approveFromSheet(ctx, taskId, cardDigest, token) {
|
|
3322
2801
|
const { who, response } = ctx;
|
|
3323
2802
|
const now = clock();
|
|
@@ -3333,7 +2812,6 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3333
2812
|
return sheetScreen(ctx, taskId, refused.message, 403);
|
|
3334
2813
|
return sheetScreen(ctx, taskId, approveRefusalWords(refused.reason), refused.reason === "changed" || refused.reason === "unrouted" ? 409 : 403);
|
|
3335
2814
|
}
|
|
3336
|
-
/** A held automatic release goes on: a person only, proved now. The watch then resumes it (release-next.ts). */
|
|
3337
2815
|
async function goOn(ctx) {
|
|
3338
2816
|
const { who, url, posted, now, response } = ctx;
|
|
3339
2817
|
const body = readForm(posted, CONSOLE_FORMS.releaseGoOn);
|
|
@@ -3352,27 +2830,15 @@ export function createReleaseSheetHandlers(runtime) {
|
|
|
3352
2830
|
}
|
|
3353
2831
|
return { routes: { "task.release": showSheet, "task.release.go-on": goOn, "release.locate": locate }, sheetScreen, approveFromSheet };
|
|
3354
2832
|
}
|
|
3355
|
-
/** The answer to an approval asked in place: its named outcome and the same words the page would show, as JSON. Written
|
|
3356
|
-
* only after the approve route's proofs, by the caller that knows the outcome. */
|
|
3357
2833
|
export function answerApprovalInPlace(response, outcome, words, status) {
|
|
3358
2834
|
respond(response, status, "application/json; charset=utf-8", JSON.stringify({ outcome, words }));
|
|
3359
2835
|
}
|
|
3360
|
-
/**
|
|
3361
|
-
* The task page's plan button for the laptop's local owner (local-owner slice 2): bound to the planning source the page
|
|
3362
|
-
* read (the form's hidden `source`), never the task as it is now; the writer (local-owner-acts.ts) proves the rest in one
|
|
3363
|
-
* transaction. No mode pre-authorization and no pins: the full session's road above is never reached from here.
|
|
3364
|
-
*/
|
|
3365
2836
|
export function localOwnerPlan(store, taskId, source, now) {
|
|
3366
2837
|
if (typeof source !== "string" || !/^[a-f0-9]{64}$/.test(source))
|
|
3367
2838
|
return { ok: false, status: 409, message: LOCAL_TASK_CHANGED };
|
|
3368
2839
|
const done = requestPlanAsLocalOwner(store, taskId, source, now);
|
|
3369
2840
|
return done.ok ? { ok: true } : { ok: false, status: done.reason === "local-owner" || done.reason === "refused" ? 403 : 409, message: done.message };
|
|
3370
2841
|
}
|
|
3371
|
-
/**
|
|
3372
|
-
* Retry for the laptop's local owner (local-owner slice 3): bound to the build and the approved plan the page read (the
|
|
3373
|
-
* form's hidden `run` and `digest`), never the task as it is now; the writer proves the rest in one transaction. A form
|
|
3374
|
-
* that carries neither (an older page) is refused, never bound to whatever is current.
|
|
3375
|
-
*/
|
|
3376
2842
|
export function localOwnerRetry(store, taskId, run, digest, now) {
|
|
3377
2843
|
if (typeof run !== "string" || !/^[1-9][0-9]{0,14}$/.test(run) || typeof digest !== "string" || !/^[a-f0-9]{32}$/.test(digest))
|
|
3378
2844
|
return { ok: false, status: 409, message: LOCAL_TASK_CHANGED };
|