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/serve.js
CHANGED
|
@@ -20,8 +20,6 @@ import { html, htmlString, jsonScript, textHtml } from "./html.js";
|
|
|
20
20
|
import { browserAssetsAvailable, browserWorkspaceDocument } from './browser-shell.js';
|
|
21
21
|
import { accessKey, countsKey, indexKey, projectSummaryOf, RevisionCache, summaryKey } from './console-chrome.js';
|
|
22
22
|
import { usageChipOf } from './limits-ui.js';
|
|
23
|
-
/** How often the background checks look at what is due (docs/plans/get-side-effects.md), and how often this
|
|
24
|
-
* computer's agent sign-ins are asked again. */
|
|
25
23
|
const BACKGROUND_CHECKS_MS = 30_000;
|
|
26
24
|
const LOCAL_AGENTS_EVERY_MS = 2 * 60_000;
|
|
27
25
|
import { browserCrewFromIndex, browserCrewOf, browserNavigationOf, browserProjectsOf, needsYouLabelOf } from './browser-workspace.js';
|
|
@@ -61,48 +59,6 @@ import {} from "./tools-ui.js";
|
|
|
61
59
|
import { WORK_INDEX_MAX_LIMIT, workCountsByProject, workIndexPage } from "./work-index.js";
|
|
62
60
|
import { WORKSPACE_MOTION_SCRIPT } from "./workspace-motion.js";
|
|
63
61
|
import { prepareWorkspaceRevision, WorkspaceValidatorCache } from "./workspace-revision.js";
|
|
64
|
-
/**
|
|
65
|
-
* The web console (§7, grown per the console review): the whole built-in
|
|
66
|
-
* queue, visible and operable from a phone. `toolroll serve` — node:http,
|
|
67
|
-
* no dependencies, no JavaScript in the page. TLS is a proxy's job and the
|
|
68
|
-
* docs say so; what is not delegated is everything else:
|
|
69
|
-
*
|
|
70
|
-
* **Authentication is required on every bind, localhost included.** The
|
|
71
|
-
* credential is the approver's — the same name-and-token that approves a
|
|
72
|
-
* scope and answers in the CLI — because `answered_by` must be an identity
|
|
73
|
-
* somebody proved, not a string a request asserted. A browser logs in once
|
|
74
|
-
* (POST /login) and carries an HttpOnly SameSite=Strict session cookie; an
|
|
75
|
-
* API caller sends `Authorization: Bearer <name>:<token>` per request. The
|
|
76
|
-
* token never travels in a URL, where it would land in history and logs.
|
|
77
|
-
*
|
|
78
|
-
* **Every request proves its Host** against the names this server was told
|
|
79
|
-
* it answers as. Cookie-authenticated mutations additionally pass one
|
|
80
|
-
* centralized gate — `authorizeMutation` — that proves content type, an
|
|
81
|
-
* allowed Origin, and the per-session CSRF nonce, and refuses duplicated
|
|
82
|
-
* security fields; a mutation route cannot forget a check it never wrote.
|
|
83
|
-
* Bearer mutations carry no cookie for a hostile page to ride, so they skip CSRF.
|
|
84
|
-
* Step-up ceremonies still require a cookie session; repeating a bearer password cannot approve.
|
|
85
|
-
*
|
|
86
|
-
* **Approval is step-up.** A session alone never approves a scope: the
|
|
87
|
-
* approval form restates the goal, the exclusions, and the touches — the
|
|
88
|
-
* three fields the digest binds — and requires the approver token typed
|
|
89
|
-
* again, plus (for browsers) a single-use nonce minted when the form was
|
|
90
|
-
* rendered, bound server-side to who saw which digest of which task. A
|
|
91
|
-
* stolen cookie can read; it cannot agree to work.
|
|
92
|
-
*
|
|
93
|
-
* **GET never mutates.** Overdue-ness is derived at render time from the
|
|
94
|
-
* deadline on the row; the durable expiry sweep belongs to the CLI's
|
|
95
|
-
* surfaces and the loop, not to a crawler hitting a page.
|
|
96
|
-
*
|
|
97
|
-
* **Everything rendered is escaped at the sink**, and every identifier in an
|
|
98
|
-
* href is URL-encoded first — HTML escaping does not make `a/b?x=1` a valid
|
|
99
|
-
* path segment. The CSP is belt to those suspenders.
|
|
100
|
-
*
|
|
101
|
-
* **Evidence goes through one verified reader** (`readVerifiedArtifact`) and
|
|
102
|
-
* membership is enforced by the lookup — a decision serves only its linked
|
|
103
|
-
* artifacts, a run only its own rows, and when this server was scoped to a
|
|
104
|
-
* repo, only runs whose task belongs to that repo (or to no repo yet).
|
|
105
|
-
*/
|
|
106
62
|
import { createHash, randomBytes } from "node:crypto";
|
|
107
63
|
import { keepSlowRequest, Timeline } from "./latency-timeline.js";
|
|
108
64
|
import { readFileSync } from "node:fs";
|
|
@@ -156,8 +112,9 @@ import { createPeopleHandlers } from './server/people-tokens.js';
|
|
|
156
112
|
import { createSettingsHandlers } from './server/settings.js';
|
|
157
113
|
import { readPurpose, requestContext } from "./server/request-context.js";
|
|
158
114
|
import { inPlaceRoute, prefetchRoute } from "./server/in-place.js";
|
|
115
|
+
import { advancedShownFor } from "./advanced.js";
|
|
159
116
|
import { LOCAL_OWNER_ELSEWHERE, asLocalOwner, localModeOn, localOwnerRefusal, localOwnerStandsNow } from "./local-owner.js";
|
|
160
|
-
import { defaultAgentOf, fillDefaultRouting } from "./model-choices.js";
|
|
117
|
+
import { defaultAgentOf, fillDefaultRouting, fillRoutingOnSignIn } from "./model-choices.js";
|
|
161
118
|
import { chromeScript, DEMO_BANNER, DEMO_BANNER_SHORT, focusDocument, KBD_HELP, pinnedTheme, QUEUE_VIEW, refuse, screen, SENSITIVE_INPUT, shell, sidebarScript } from "./server/chrome.js";
|
|
162
119
|
import { BODY_CAP, form, loginHref, passwordSetNext, refusalNext, matchTaskPath, page, projectChatHref, redactedPath, redirect, respond, safeReturn, SHUTDOWN_WAIT_MS, taskChatHref } from "./server/http.js";
|
|
163
120
|
import { decisionsFor, LEAD_BY_DEFAULT_FACT, leadBrowserMessages, leadChatVersion, NOT_STARTED_SESSION, TASK_COMPOSER_MODES, teamProposalCardParts } from "./server/render-chat.js";
|
|
@@ -178,8 +135,6 @@ import { loadConsoleUrl } from "./webhooks.js";
|
|
|
178
135
|
import { reviewFactsOf } from "./workspace-ui.js";
|
|
179
136
|
import { WorktreePool } from "./worktree.js";
|
|
180
137
|
export function createDecisionServer(options) {
|
|
181
|
-
// Identities come from what the console's start resolved off its thread (startConsole); a path that didn't answer
|
|
182
|
-
// stays unresolved, kept restrictive. Without them (embedders, tests) the old synchronous reads apply.
|
|
183
138
|
const identities = options.identities ?? syncProjectIdentities();
|
|
184
139
|
const { projectFamilyPeek, familiesInView, familyTasksInView, revisionDestination, runIsLive, runIsTaskResult, revisionViewOf, taskViewData, routeViewOf, taskChatFocus, pullRequestTargetOf, failureOf, explainAttempt, taskScreen, armTaskResume, planViewOf, planContractViewOf, revisionDocOf, revisionLedgerOf, resultDetailOf } = createTaskViews({
|
|
185
140
|
get store() { return store; },
|
|
@@ -232,18 +187,14 @@ export function createDecisionServer(options) {
|
|
|
232
187
|
}
|
|
233
188
|
}
|
|
234
189
|
}
|
|
235
|
-
// Live terminals (docs/plans/live-terminal.md): on a machine that runs agents, when this install has a pty library.
|
|
236
190
|
const terminals = terminalHostFor(store, options);
|
|
237
191
|
const clock = options.clock ?? (() => new Date());
|
|
238
|
-
// Heavy reads (the work index behind `task list`) run on read-only worker connections, off the request loop.
|
|
239
192
|
const readFile = store.isDemo() ? null : store.databaseFile();
|
|
240
193
|
const readWorkers = options.readWorkers ?? (process.env["VITEST"] !== undefined ? 0 : defaultReadWorkers());
|
|
241
194
|
const reads = readFile === null || readWorkers < 1 ? null : new ReadExecutor(readFile, readWorkers);
|
|
242
195
|
const detachReads = reads === null ? () => { } : attachReadExecutor(store, reads);
|
|
243
|
-
/** Task checkouts, for Settings → Storage: the pool's own root, or the folder beside the database. */
|
|
244
196
|
const storagePool = (databaseFile) => new WorktreePool(store, { root: options.poolRoot ?? join(dirname(databaseFile), "worktrees") });
|
|
245
197
|
const install = installMethod(options.installBin);
|
|
246
|
-
/** What the last daily check found (the cache only, never the network), or nothing while checks are off. */
|
|
247
198
|
const updateFacts = () => {
|
|
248
199
|
if (options.configDir === undefined)
|
|
249
200
|
return null;
|
|
@@ -251,7 +202,6 @@ export function createDecisionServer(options) {
|
|
|
251
202
|
const release = switched.off ? null : cachedRelease(options.configDir);
|
|
252
203
|
return { release, newer: release !== null && isNewer(release.version, PACKAGE_VERSION), on: !switched.off, byEnv: switched.byEnv };
|
|
253
204
|
};
|
|
254
|
-
/** Settings → Updates, for everyone who can open Settings; only an operator may flip the switch. */
|
|
255
205
|
const settingsUpdates = (actor, csrf) => {
|
|
256
206
|
const facts = updateFacts();
|
|
257
207
|
if (facts === null)
|
|
@@ -269,29 +219,20 @@ export function createDecisionServer(options) {
|
|
|
269
219
|
};
|
|
270
220
|
};
|
|
271
221
|
const workspaceRevision = prepareWorkspaceRevision(store);
|
|
272
|
-
// The sidebar, the Tasks count and the crew: read at most once per workspace revision per reader's exact access
|
|
273
|
-
// (console-chrome.ts), and filled from a read worker before a page renders when one is attached.
|
|
274
222
|
const chromeReads = new RevisionCache(workspaceRevision, clock);
|
|
275
223
|
const workspaceIncarnation = randomBytes(16).toString('hex');
|
|
276
224
|
const workspaceValidators = new WorkspaceValidatorCache();
|
|
277
225
|
const providerHome = options.connectionHome ?? homedir();
|
|
278
226
|
const checkConnection = createConnectionChecker({ home: providerHome, clock, ...(options.connectionProbe === undefined ? {} : { probe: options.connectionProbe }) });
|
|
279
|
-
// Every sign-in check the console makes also answers a sign-in pause.
|
|
280
|
-
// Whether this computer can fence agents: asked once as the console starts (a sandbox running /usr/bin/true), so
|
|
281
|
-
// Settings → Project never starts a process (docs/plans/get-side-effects.md).
|
|
282
227
|
const fenceHere = options.fenceAvailable === undefined ? macosFenceAvailable() || linuxFenceAvailable() : false;
|
|
283
|
-
// Phone notifications' signing pair, made once as the console starts so /push/key only reads it.
|
|
284
228
|
if (options.telegramTokenFile !== undefined) {
|
|
285
229
|
try {
|
|
286
230
|
loadOrCreateVapidKeys(dirname(options.telegramTokenFile));
|
|
287
231
|
}
|
|
288
|
-
catch {
|
|
232
|
+
catch { }
|
|
289
233
|
}
|
|
290
|
-
// The last answer of every other check a page shows (docs/plans/get-side-effects.md).
|
|
291
234
|
const lastChecks = new LastChecks();
|
|
292
|
-
/** The newest release, asked of npm (Settings → Updates shows the last answer). */
|
|
293
235
|
const checkRelease = () => lastChecks.run("release", () => latestReleaseFor(options.updates?.latest));
|
|
294
|
-
// What each sign-in check said last: what a page shows (docs/plans/get-side-effects.md). A page never checks.
|
|
295
236
|
const knownConnections = new Map();
|
|
296
237
|
const connectionKnown = (provider) => knownConnections.get(provider) ?? null;
|
|
297
238
|
const connectionCheck = async (provider, fresh) => {
|
|
@@ -300,10 +241,9 @@ export function createDecisionServer(options) {
|
|
|
300
241
|
try {
|
|
301
242
|
noteSignInProbe(store, provider, value.state, clock());
|
|
302
243
|
}
|
|
303
|
-
catch {
|
|
244
|
+
catch { }
|
|
304
245
|
return value;
|
|
305
246
|
};
|
|
306
|
-
// Settings → Integrations: checked in the background with a short cache, as the first-run suggestions are.
|
|
307
247
|
const integrations = createIntegrationMonitor(() => ({
|
|
308
248
|
store,
|
|
309
249
|
dir: options.configDir ?? null,
|
|
@@ -324,24 +264,10 @@ export function createDecisionServer(options) {
|
|
|
324
264
|
...(options.modelPath === undefined ? {} : { path: options.modelPath }),
|
|
325
265
|
};
|
|
326
266
|
const sessions = new PersistentSessions(store);
|
|
327
|
-
// Sessions from before a restart that ran out, or whose account changed since, go now.
|
|
328
267
|
store.sweepWebSessions(Date.now(), SESSION_IDLE_MS, SESSION_ABSOLUTE_MS);
|
|
329
|
-
/** Where a new session signs in from: the browser (its user agent, short) and the address. */
|
|
330
268
|
const arrival = (request) => ({ agent: (request.headers["user-agent"] ?? "").slice(0, 300) || null, address: forwardedSourceOf(request).replace(/^fwd:/, "") });
|
|
331
|
-
/** Wrong setup codes left before the first-account road closes. */
|
|
332
269
|
let setupAttemptsLeft = 5;
|
|
333
|
-
// The /join road's limiter (D6; Codex people round 1, finding 4):
|
|
334
|
-
// PER-SOURCE buckets so one stranger cannot drain sign-up capacity for
|
|
335
|
-
// everyone, under a global ceiling that bounds total KDF work. Spent
|
|
336
|
-
// only by WELL-FORMED submissions — malformed requests are refused by
|
|
337
|
-
// the shape guards for free. The per-invite attempt counter remains the
|
|
338
|
-
// durable meter; these buckets only price the trying.
|
|
339
270
|
const joinBySource = new Map();
|
|
340
|
-
/** The per-source key (round 2, finding 4): the direct peer — except
|
|
341
|
-
* behind the documented same-host TLS proxy, where every client would
|
|
342
|
-
* share the proxy's one bucket. A LOOPBACK peer is that proxy, and only
|
|
343
|
-
* then is the forwarded chain believed, taking the LAST hop (the one
|
|
344
|
-
* the trusted proxy itself appended; earlier entries are client-typed). */
|
|
345
271
|
function forwardedSourceOf(request) {
|
|
346
272
|
const peer = request.socket.remoteAddress ?? "unknown";
|
|
347
273
|
const loopback = LOOPBACK_PEERS.has(peer);
|
|
@@ -352,45 +278,27 @@ export function createDecisionServer(options) {
|
|
|
352
278
|
const lastHop = chain.split(",").pop()?.trim() ?? "";
|
|
353
279
|
return lastHop === "" ? peer : `fwd:${lastHop.slice(0, 64)}`;
|
|
354
280
|
}
|
|
355
|
-
/** That source as every per-source budget counts it: a native IPv6 caller by its /64 (source-key.ts). */
|
|
356
281
|
function joinSourceOf(request) { return sourceKey(forwardedSourceOf(request)); }
|
|
357
282
|
const signInBudget = new SourceBudget();
|
|
358
|
-
// A re-check or a link is the session that started it: its kept hash and credential generation ride the visit and the
|
|
359
|
-
// hand-off, and finish refuses any other session (a sign-out and a new sign-in in between never inherit it).
|
|
360
283
|
const ssoVisits = new Map();
|
|
361
284
|
const ssoHandoffs = new Map();
|
|
362
285
|
let ssoProvider = null;
|
|
363
286
|
const ssoSettings = () => readSsoSettings(options.configDir);
|
|
364
287
|
const ssoOffer = () => { const settings = ssoSettings(); return settings === null ? null : { label: settings.label, operatorsOnly: settings.passwords === "operators" }; };
|
|
365
|
-
/** A step-up within this long of the provider checking someone needs no password. */
|
|
366
|
-
// The one-time sign-in link `up` opens in the browser: single use, ten minutes, from this computer only. Only a hash
|
|
367
|
-
// of the code is kept, in memory; the code itself is never written to a log or the ledger.
|
|
368
288
|
const signInLinks = new Map();
|
|
369
289
|
const linkKey = (code) => createHash("sha256").update(code).digest("hex");
|
|
370
290
|
function mintSignInLink(account) {
|
|
371
291
|
const known = store.accountOf(account);
|
|
372
|
-
// A full link is for an account with a password: a local owner without one gets only mintLocalLink's.
|
|
373
292
|
if (known === null || known.role !== "approver" || known.revokedAt !== null || !known.passwordSet)
|
|
374
293
|
return null;
|
|
375
294
|
return holdSignInLink({ kind: "full", account, expires: Date.now() + SIGN_IN_LINK_MS });
|
|
376
295
|
}
|
|
377
|
-
/** v147: this console start's key epoch (easy-start C2): the browser-key wave binds each session's mutation key to it. */
|
|
378
296
|
const keyEpoch = options.keyEpoch ?? randomBytes(16).toString("hex");
|
|
379
|
-
/** This computer, and nothing in front of it: a loopback peer that names a loopback address, with no sign of a proxy —
|
|
380
|
-
* any forwarding header at all (Forwarded, X-Forwarded-*, X-Real-IP, Via, …) disqualifies the request. The one reading
|
|
381
|
-
* (public-access.ts), which guards.ts also applies to every request a local owner's session makes. */
|
|
382
297
|
const fromThisComputer = (request) => requestFromThisComputer(request);
|
|
383
|
-
/**
|
|
384
|
-
* Cockpit B2: a request's password-freshness facts — the one place they are made (scope.ts honours them). Every
|
|
385
|
-
* reader looks at the session as it is at the moment of the act, never a snapshot taken before the body arrived:
|
|
386
|
-
* still signed in here, under the account's current credential generation, after any Forget.
|
|
387
|
-
*/
|
|
388
298
|
function freshFactsOf(request, who, allowlisted = false) {
|
|
389
299
|
if (who?.via !== 'cookie')
|
|
390
300
|
return null;
|
|
391
301
|
const session = who.session, local = fromThisComputer(request);
|
|
392
|
-
// The same validity lookupSession applies, read again at the act: held here, within its idle and absolute
|
|
393
|
-
// lifetimes, under the account's current credential generation, not revoked.
|
|
394
302
|
const live = () => {
|
|
395
303
|
const now = Date.now(), account = store.accountOf(who.name);
|
|
396
304
|
return sessions.holds(session) && sessions.savedNow(session) && sessionWithinLifetime(session, now)
|
|
@@ -402,14 +310,12 @@ export function createDecisionServer(options) {
|
|
|
402
310
|
consumeSsoNow: () => {
|
|
403
311
|
const was = session.ssoNowAt;
|
|
404
312
|
delete session.ssoNowAt;
|
|
405
|
-
// A refund puts back only what this spend took, once, and only if nothing newer arrived (Forget still floors it).
|
|
406
313
|
let refunded = false;
|
|
407
314
|
return () => { if (refunded)
|
|
408
315
|
return; refunded = true; if (was !== undefined && session.ssoNowAt === undefined)
|
|
409
316
|
session.ssoNowAt = was; };
|
|
410
317
|
},
|
|
411
318
|
floor: () => session.freshFloor ?? 0,
|
|
412
|
-
// Only a direct local request may start a password window (a typed password elsewhere proves now, nothing more).
|
|
413
319
|
stamp: at => { if (local && live())
|
|
414
320
|
session.passwordAt = at; } };
|
|
415
321
|
}
|
|
@@ -421,9 +327,6 @@ export function createDecisionServer(options) {
|
|
|
421
327
|
ssoProvider = { issuer, provider: found.provider, at: Date.now() };
|
|
422
328
|
return found;
|
|
423
329
|
}
|
|
424
|
-
/** The identity provider as last discovered: what starting a sign-in uses (a GET, so it fetches nothing,
|
|
425
|
-
* docs/plans/get-side-effects.md). Discovered as the console starts, by the background checks every ten minutes, and
|
|
426
|
-
* when sign-in settings are saved or tested. */
|
|
427
330
|
function providerKnown(issuer) {
|
|
428
331
|
return ssoProvider !== null && ssoProvider.issuer === issuer ? ssoProvider.provider : null;
|
|
429
332
|
}
|
|
@@ -432,10 +335,8 @@ export function createDecisionServer(options) {
|
|
|
432
335
|
if (settings !== null)
|
|
433
336
|
void providerFor(settings.issuer).catch(() => undefined);
|
|
434
337
|
}
|
|
435
|
-
/** Password sign-in is only for instance operators when the provider says so (a way in if it's down). */
|
|
436
338
|
const passwordAllowed = (name) => { const settings = ssoSettings(); return settings === null || settings.passwords === "everyone" || store.isInstanceOperator(name); };
|
|
437
339
|
const minutesWords = (ms) => { const minutes = Math.max(1, Math.ceil(ms / 60_000)); return minutes >= 120 ? `${Math.round(minutes / 60)} hours` : `${minutes} minute${minutes === 1 ? "" : "s"}`; };
|
|
438
|
-
/** A sign-in event names the account only when it exists: what someone typed into the name box stays out of history. */
|
|
439
340
|
const signInActor = (name) => name !== null && store.accountOf(name) !== null ? name : "unknown account";
|
|
440
341
|
const recordSignIn = (actor, action, outcome, detail = null) => {
|
|
441
342
|
try {
|
|
@@ -452,28 +353,14 @@ export function createDecisionServer(options) {
|
|
|
452
353
|
};
|
|
453
354
|
let joinGlobal = { tokens: 30, refilledAt: Date.now() };
|
|
454
355
|
const approvalNonces = new Map();
|
|
455
|
-
// Startup authority: the configured repos and roots as their identities say (startupCeiling). Missing or unresolved
|
|
456
|
-
// paths remain restrictive. Native additions come only from the controller after its admission checks.
|
|
457
356
|
const { ceiling, unresolved: unresolvedRepos, defaultProject, configured, configuredPaths } = startupCeiling([...(options.repo === undefined ? [] : [options.repo]), ...(options.repos ?? [])], options.projectRoots ?? [], options.identities === undefined ? undefined : identities, identities.strict);
|
|
458
|
-
/** No ceiling configured at all: the legacy trust-everything mode, named. */
|
|
459
|
-
// An `up` console (it is handed its admitted set) is never unscoped: with every saved project away it is empty.
|
|
460
|
-
// Judged by what was configured, never by what has resolved so far: a console whose folders haven't answered yet is
|
|
461
|
-
// scoped and empty, not unscoped.
|
|
462
357
|
const unscopedMode = !configured && options.admittedRepos === undefined;
|
|
463
|
-
/** Per-row visibility under the ceiling — the authorization question for reads. */
|
|
464
|
-
/** The exact repositories this console serves now: `up`'s live admitted set when it supplies one, else startup's. */
|
|
465
358
|
const exactRepos = () => options.admittedRepos?.() ?? ceiling.repos;
|
|
466
359
|
const liveCeiling = () => {
|
|
467
360
|
const repos = [...exactRepos(), ...(options.additionalProjectRepos?.() ?? [])];
|
|
468
|
-
// An admitted set that is empty for now is an empty ceiling, never the legacy unscoped mode.
|
|
469
361
|
return { repos: repos.length === 0 && ceiling.roots.length === 0 && !unscopedMode ? [NO_PROJECT] : repos, roots: ceiling.roots, canon: identities.strict };
|
|
470
362
|
};
|
|
471
|
-
/** The explicit, currently proved project list. The callback is supplied
|
|
472
|
-
* only by `up`, after it has independently checked git-ness and the root
|
|
473
|
-
* ceiling; this server still filters every row through its own ceiling. */
|
|
474
|
-
/** Projects deleted while this console runs: gone from its lists though a builder started with them still watches. */
|
|
475
363
|
const deletedRepos = new Set();
|
|
476
|
-
/** Those still gone: a project added again (from here, `repos add`, or the lead) has its row back and shows again. */
|
|
477
364
|
const goneRepos = () => {
|
|
478
365
|
if (deletedRepos.size === 0)
|
|
479
366
|
return deletedRepos;
|
|
@@ -494,7 +381,6 @@ export function createDecisionServer(options) {
|
|
|
494
381
|
}
|
|
495
382
|
return repos;
|
|
496
383
|
};
|
|
497
|
-
/** Settings → Project's view of a project: what's held for it, what's running, and whether this person may delete it. */
|
|
498
384
|
const projectViewOf = (repo, who) => ({
|
|
499
385
|
repo, name: projectName(repo), holdings: projectHoldings(store, repo), running: projectRunning(store, repo, clock()),
|
|
500
386
|
canDelete: who.via === "cookie" && store.isInstanceOperator(who.name),
|
|
@@ -514,18 +400,15 @@ export function createDecisionServer(options) {
|
|
|
514
400
|
liveView: (() => {
|
|
515
401
|
const commands = liveCommandsShown(store, repo);
|
|
516
402
|
const canChange = who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo);
|
|
517
|
-
// Showing commands is consent to one exact change: a single-use nonce for this person, project and terms.
|
|
518
403
|
return { commands, canChange, ...(canChange && !commands ? { nonce: mintApprovalNonce(who.name, LIVE_VIEW_CONSENT, liveViewConsentDigest(repo)) } : {}) };
|
|
519
404
|
})(),
|
|
520
405
|
});
|
|
521
|
-
/** Settings → Project → Build access: the project's named tools and whether each loads for its builds. */
|
|
522
406
|
const projectAccessOf = (repo) => {
|
|
523
407
|
try {
|
|
524
408
|
const policy = store.orgPolicy();
|
|
525
409
|
return { tools: projectToolsOf(store, repo).map(tool => {
|
|
526
410
|
const refused = toolRefusal(policy, tool.name);
|
|
527
411
|
const set = secretsSetFor(repo, tool.spec, toolHome);
|
|
528
|
-
// As a launch decides (toolLaunchFor): a tool the organisation doesn't allow, or missing a secret, is left out.
|
|
529
412
|
return refused !== null ? { name: tool.name, loads: false, words: refused }
|
|
530
413
|
: { name: tool.name, loads: tool.spec.secrets.every(one => one.optional || set.includes(one.name)), words: toolStanding(tool, set).words };
|
|
531
414
|
}) };
|
|
@@ -534,7 +417,6 @@ export function createDecisionServer(options) {
|
|
|
534
417
|
return { problem: "Couldn't read this project's tools right now." };
|
|
535
418
|
}
|
|
536
419
|
};
|
|
537
|
-
/** Settings → Project → Builds at once: the saved number, its workers' capacity, and what builds now. */
|
|
538
420
|
const projectBuildsOf = (repo, who) => {
|
|
539
421
|
const capacities = store.listRunners().filter(one => one.retiredAt === null && one.repos.includes(repo)).map(one => one.capacity);
|
|
540
422
|
return {
|
|
@@ -544,7 +426,6 @@ export function createDecisionServer(options) {
|
|
|
544
426
|
canChange: who.via === "cookie" && who.role === "approver" && store.accountCanAccess(who.name, repo),
|
|
545
427
|
};
|
|
546
428
|
};
|
|
547
|
-
/** Codex's own MCP servers for a project (`codex mcp list --json`), for "Found on this computer"; null when Codex can't say. */
|
|
548
429
|
const codexServers = async (repo) => {
|
|
549
430
|
try {
|
|
550
431
|
const listed = await (options.codexToolList ?? (async (cwd) => {
|
|
@@ -558,38 +439,28 @@ export function createDecisionServer(options) {
|
|
|
558
439
|
return null;
|
|
559
440
|
}
|
|
560
441
|
};
|
|
561
|
-
/** One project's Tools page: its tools with which secrets are set (never values), the common tools not yet added, and what this computer already has. */
|
|
562
|
-
// A test's own folder for tool secrets and found tools; Toolroll's own (beside its database, and this home) otherwise.
|
|
563
442
|
const toolHome = options.toolHome;
|
|
564
443
|
const toolsViewOf = (repo, codex, kit = null, wanted = null) => {
|
|
565
444
|
const tools = projectToolsOf(store, repo);
|
|
566
445
|
const names = new Set(tools.map(one => one.name));
|
|
567
446
|
return {
|
|
568
447
|
repo, project: repo.split(/[\\/]/).filter(Boolean).at(-1) ?? repo,
|
|
569
|
-
// Secrets that can't be read (a refused folder, a locked keychain) read as none set: the page says why once (storage).
|
|
570
448
|
tools: tools.map(tool => { let secretsSet = []; try {
|
|
571
449
|
secretsSet = secretsSetFor(repo, tool.spec, toolHome);
|
|
572
450
|
}
|
|
573
451
|
catch {
|
|
574
452
|
secretsSet = [];
|
|
575
453
|
} return { tool, secretsSet }; }),
|
|
576
|
-
// A service that connects by signing in (or an app's own Connect) is offered only that way.
|
|
577
454
|
catalog: TOOL_CATALOG.filter(one => !names.has(one.name) && oneClickOf(one.name) === null && localConnectOf(one.name) === null),
|
|
578
455
|
connections: connectionsOf(store, repo, toolHome), kit, wanted,
|
|
579
|
-
// The project's own .mcp.json as the background pass last read it off the console's thread (never read here).
|
|
580
456
|
found: discoverTools(repo, codex, toolHome, process.env, options.identities === undefined ? undefined : savedProjectMcp.get(repo) ?? null).filter(one => !names.has(one.spec.name)),
|
|
581
457
|
storage: toolSecretStorage(),
|
|
582
458
|
};
|
|
583
459
|
};
|
|
584
460
|
const codingProjects = () => [...new Set([...managedRepos(), ...store.listProjects().map(project => project.path)])].filter(repo => rowVisible(liveCeiling(), repo));
|
|
585
|
-
/** Open chat streams (live replies), ended when the server closes. */
|
|
586
461
|
let liveTurnStarted = () => { };
|
|
587
|
-
/** Google sign-ins in progress (v89): each consent visit's state, for 10 minutes. */
|
|
588
462
|
const googleVisits = new Map();
|
|
589
|
-
/** One-click connections on their way: the service's sign-in page and back, 15 minutes at most. */
|
|
590
463
|
const connectVisits = new Map();
|
|
591
|
-
/** Flows open in a browser (v88): who's here, and a nudge when one changes. */
|
|
592
|
-
// Live views push on write (live-bus.ts): each commit moves the workspace revision, the rooms hear it.
|
|
593
464
|
const liveBus = createLiveBus();
|
|
594
465
|
const liveFollower = followWorkspace(store, () => workspaceRevision.current(), liveBus, { file: store.databaseFile() });
|
|
595
466
|
const flowRooms = createFlowRooms(flow => flowFingerprint(store, flow), { bus: liveBus });
|
|
@@ -600,9 +471,6 @@ export function createDecisionServer(options) {
|
|
|
600
471
|
provider: teamChatProvider,
|
|
601
472
|
...(options.subscriptionChatRunner ? { subscriptionRunner: options.subscriptionChatRunner } : {}),
|
|
602
473
|
});
|
|
603
|
-
// The personal lead queue (docs/plans/lead-message-queue.md). Projects and a message's task are re-proved AS the
|
|
604
|
-
// person (never from a live request's context), and its live reply display is the console's own (chat handlers below,
|
|
605
|
-
// reached only once the server is listening).
|
|
606
474
|
const asActor = (account, work) => requestContext.run({ csrf: "", returnTo: "/", actor: account }, work);
|
|
607
475
|
const admittedReposFor = (account) => asActor(account, () => managedRepos());
|
|
608
476
|
const personalQueue = createPersonalQueueRuntime({
|
|
@@ -622,12 +490,10 @@ export function createDecisionServer(options) {
|
|
|
622
490
|
return run !== null && family.versions.some(one => one.refId === run.taskRef);
|
|
623
491
|
}),
|
|
624
492
|
names: { project: projectName, modes: TASK_COMPOSER_MODES },
|
|
625
|
-
// A queued message's partials are shaped as its final reply will be: for its words, with this console's own addresses.
|
|
626
493
|
live: { begin: (thread, asked) => chatHandlers.beginLiveTurn(thread, { asked, appOrigin: [publicOrigin?.origin ?? null, options.configDir === undefined ? null : loadConsoleUrl(process.env, options.configDir)] }), end: (thread, ok, progress) => chatHandlers.endLiveTurn(thread, ok, progress) },
|
|
627
494
|
...(options.chatFetcher ? { fetcher: options.chatFetcher } : {}),
|
|
628
495
|
...(options.subscriptionChatRunner ? { subscriptionRunner: options.subscriptionChatRunner } : {}),
|
|
629
496
|
});
|
|
630
|
-
// Only browser sessions receive HTML cards. The CLI keeps its summary contract.
|
|
631
497
|
const teamBrowserReply = (reply, actor, csrf) => {
|
|
632
498
|
const snapshot = reply.snapshot;
|
|
633
499
|
if (!snapshot?.selected || !snapshot.proposals)
|
|
@@ -640,9 +506,7 @@ export function createDecisionServer(options) {
|
|
|
640
506
|
return { ...summary, card: teamProposalCardParts(store, actor, proposal, snapshot, csrf, decision, clock(), teamChatProvider).card };
|
|
641
507
|
}) } };
|
|
642
508
|
};
|
|
643
|
-
// v112: one request budget per server for person API tokens, shared by every route a token signs in at (request-budget.ts).
|
|
644
509
|
const requestBudget = new RequestBudget({ store, ...(options.requestBudgetClock === undefined ? {} : { clock: options.requestBudgetClock }) });
|
|
645
|
-
// Unproved password attempts share a source budget. Only successful proof spends an account budget.
|
|
646
510
|
const sourceClock = options.requestBudgetClock === undefined ? {} : { clock: options.requestBudgetClock };
|
|
647
511
|
const passwordSourceBudget = new SourceAdmission({ perMinute: SOURCE_BUDGET_DEFAULTS.password, ...sourceClock });
|
|
648
512
|
const passwordAccountBudget = new SourceAdmission({ perMinute: SOURCE_BUDGET_DEFAULTS.password, keyMode: "exact", ...sourceClock });
|
|
@@ -651,27 +515,19 @@ export function createDecisionServer(options) {
|
|
|
651
515
|
const oauthTokenBudget = new SourceAdmission({ perMinute: SOURCE_BUDGET_DEFAULTS.oauthToken, ...sourceClock });
|
|
652
516
|
const presentsPassword = (request) => /^Bearer (.+):(.+)$/.test(request.headers.authorization ?? "");
|
|
653
517
|
const admitPasswordSource = (request) => presentsPassword(request) ? passwordSourceBudget.admit(joinSourceOf(request)) : { ok: true };
|
|
654
|
-
/** Called only with a proved identity; cookies spend neither bearer budget. */
|
|
655
518
|
const admitBearer = (request, actor) => {
|
|
656
519
|
if (actor.principal !== undefined)
|
|
657
520
|
return requestBudget.admit(actor.principal.tokenId, "api");
|
|
658
521
|
return presentsPassword(request) ? passwordAccountBudget.admit(actor.name) : { ok: true };
|
|
659
522
|
};
|
|
660
|
-
/** Every project this person may pick in the console — the switcher, Projects, Settings, Tools and Flows read this
|
|
661
|
-
* one list: the live admitted set (taskless projects included) and every project with saved work, each through
|
|
662
|
-
* the ceiling and this account's project grants. A project removed or deleted here is gone from it. */
|
|
663
523
|
const consoleProjects = () => {
|
|
664
524
|
const gone = goneRepos();
|
|
665
525
|
return [...new Set([...(admissionList() ?? []), ...managedRepos(), ...store.knownRepos()])].filter(one => visible(one) && !gone.has(one));
|
|
666
526
|
};
|
|
667
527
|
const server = createServer((request, response) => {
|
|
668
528
|
instrumentRequest(store.telemetry, request, response);
|
|
669
|
-
// Every password checked while answering counts against where this request came from (sign-in-guard.ts).
|
|
670
|
-
// A GET or HEAD only reads (docs/plans/get-side-effects.md): store reads that would tidy up as they go don't.
|
|
671
529
|
const answer = () => consoleFolders(options, identities, () => handle(request, response));
|
|
672
530
|
void withPasswordSource(joinSourceOf(request), () => request.method === "GET" || request.method === "HEAD" ? asReadOnlyRequest(answer) : answer()).catch(error => {
|
|
673
|
-
// Every unhandled error is logged (v99): the path and the message, never the request's body or query. The reference
|
|
674
|
-
// is what a person's error page shows, so the log line can be found from it.
|
|
675
531
|
const reference = `err_${randomBytes(4).toString("hex")}`;
|
|
676
532
|
logEvent("error", "serve.error", { method: request.method, path: redactedPath(new URL(request.url ?? "/", "http://placeholder").pathname), error: error instanceof Error ? error.message : String(error), reference });
|
|
677
533
|
if (envValue(process.env, "SERVE_DEBUG") === "1")
|
|
@@ -680,15 +536,13 @@ export function createDecisionServer(options) {
|
|
|
680
536
|
const updating = error instanceof Error && error.message.includes(UPDATE_PAUSED);
|
|
681
537
|
if (updating)
|
|
682
538
|
response.setHeader("Retry-After", "5");
|
|
683
|
-
// A browser asking for a page gets a page (Wave E): what happened, whether anything changed, the reference. It
|
|
684
|
-
// holds no error text. Everything else keeps the plain answer.
|
|
685
539
|
if (/\btext\/html\b/.test(String(request.headers.accept ?? "")) && (request.method === "GET" || request.method === "POST")) {
|
|
686
540
|
const read = request.method === "GET";
|
|
687
541
|
const at = new URL(request.url ?? "/", "http://placeholder");
|
|
688
542
|
try {
|
|
689
543
|
return page(response, updating ? 503 : 500, serverErrorPage({ updating, read, reference, at: new Date(), retry: read ? at.pathname + at.search : null }));
|
|
690
544
|
}
|
|
691
|
-
catch {
|
|
545
|
+
catch { }
|
|
692
546
|
}
|
|
693
547
|
respond(response, updating ? 503 : 500, "text/plain; charset=utf-8", updating ? UPDATE_PAUSED : "something broke");
|
|
694
548
|
}
|
|
@@ -699,9 +553,6 @@ export function createDecisionServer(options) {
|
|
|
699
553
|
});
|
|
700
554
|
server.once('listening', () => store.telemetry.start());
|
|
701
555
|
server.once('close', () => store.telemetry.stop());
|
|
702
|
-
// --public-url (arc 3): validated to EXACTLY an https origin. Its host
|
|
703
|
-
// joins the allowed set, its origin authorizes POSTs, and cookies turn
|
|
704
|
-
// Secure. Anything malformed refuses at startup, loudly.
|
|
705
556
|
const publicOrigin = (() => {
|
|
706
557
|
if (options.publicUrl === undefined)
|
|
707
558
|
return null;
|
|
@@ -718,9 +569,7 @@ export function createDecisionServer(options) {
|
|
|
718
569
|
return parsed;
|
|
719
570
|
})();
|
|
720
571
|
const cookieSecure = publicOrigin === null ? "" : "; Secure";
|
|
721
|
-
/** Where Google may send someone back to (v89): the public https address, or this computer's own. */
|
|
722
572
|
const consoleOrigin = (host) => host === undefined ? null : publicOrigin !== null && host === publicOrigin.host ? publicOrigin.origin : /^(localhost|127\.0\.0\.1|\[::1\]):[0-9]{1,5}$/.test(host) ? `http://${host}` : null;
|
|
723
|
-
/** This computer's tailnet names, the last ones read (onboarding). */
|
|
724
573
|
let tailnet = [];
|
|
725
574
|
if (options.tailnetNames !== undefined) {
|
|
726
575
|
const readTailnet = options.tailnetNames;
|
|
@@ -734,7 +583,7 @@ export function createDecisionServer(options) {
|
|
|
734
583
|
const flushBudget = () => { try {
|
|
735
584
|
requestBudget.flush();
|
|
736
585
|
}
|
|
737
|
-
catch {
|
|
586
|
+
catch { } };
|
|
738
587
|
const timer = setInterval(flushBudget, REQUEST_BUDGET_FLUSH_MS);
|
|
739
588
|
timer.unref?.();
|
|
740
589
|
server.on("close", () => { clearInterval(timer); flushBudget(); });
|
|
@@ -743,7 +592,6 @@ export function createDecisionServer(options) {
|
|
|
743
592
|
const address = server.address();
|
|
744
593
|
return typeof address === "object" && address !== null ? address.port : null;
|
|
745
594
|
};
|
|
746
|
-
/** The names this server answers as. Anything else is a rebind, refused. */
|
|
747
595
|
const allowedHost = (host) => {
|
|
748
596
|
if (host === undefined)
|
|
749
597
|
return false;
|
|
@@ -751,8 +599,6 @@ export function createDecisionServer(options) {
|
|
|
751
599
|
const locals = port === null ? [] : [`localhost:${port}`, `127.0.0.1:${port}`, `[::1]:${port}`, ...tailnet.map(name => `${name}:${port}`)];
|
|
752
600
|
return [...locals, ...(options.allowedHosts ?? []), ...(publicOrigin === null ? [] : [publicOrigin.host])].includes(host);
|
|
753
601
|
};
|
|
754
|
-
/** Easy-start C2: a protected loopback install (bound to loopback only, no --allow-host, no public URL, no tailnet
|
|
755
|
-
* names) has one browser host, and there every browser mutation also presents the session's key (mutation-key.ts). */
|
|
756
602
|
const browserKeys = createBrowserKeys({
|
|
757
603
|
enabled: options.browserKey === true,
|
|
758
604
|
epoch: keyEpoch,
|
|
@@ -765,7 +611,6 @@ export function createDecisionServer(options) {
|
|
|
765
611
|
return address.address === "127.0.0.1" ? `127.0.0.1:${port}` : address.address === "::1" ? `[::1]:${port}` : null;
|
|
766
612
|
},
|
|
767
613
|
});
|
|
768
|
-
/** The exact command that starts this console again as it runs now, plus a listening address or one more allowed host. */
|
|
769
614
|
const consoleCommand = (change) => {
|
|
770
615
|
const port = servedPort() ?? 4180;
|
|
771
616
|
const address = server.address();
|
|
@@ -775,7 +620,6 @@ export function createDecisionServer(options) {
|
|
|
775
620
|
return [`toolroll ${options.upConsole === true ? "up" : "serve"}`, ...(host === null ? [] : [`--host ${host}`]), ...(port === 4180 ? [] : [`--port ${port}`]),
|
|
776
621
|
...(allowed.length === 0 ? [] : [`--allow-host ${allowed.join(",")}`])].join(" ");
|
|
777
622
|
};
|
|
778
|
-
/** The wrong-host page's facts: the address opened, where the console answers, and the exact command that admits it. */
|
|
779
623
|
const wrongHost = (host) => {
|
|
780
624
|
const opened = host !== undefined && /^[A-Za-z0-9.-]{1,253}(:[0-9]{1,5})?$|^\[[0-9A-Fa-f:.]{2,45}\](:[0-9]{1,5})?$/.test(host) ? host : null;
|
|
781
625
|
return { opened, served: `127.0.0.1:${servedPort() ?? 4180}`, command: opened === null ? null : consoleCommand({ allow: opened }) };
|
|
@@ -790,7 +634,6 @@ export function createDecisionServer(options) {
|
|
|
790
634
|
approvalNonces.set(nonce, { name, taskId, digest, expiresAt: Date.now() + NONCE_TTL_MS });
|
|
791
635
|
return nonce;
|
|
792
636
|
}
|
|
793
|
-
/** Single use, bound to who saw which digest of which task, and young. */
|
|
794
637
|
function consumeApprovalNonce(nonce, name, taskId, digest) {
|
|
795
638
|
const held = approvalNonces.get(nonce);
|
|
796
639
|
if (held === undefined)
|
|
@@ -803,22 +646,13 @@ export function createDecisionServer(options) {
|
|
|
803
646
|
}
|
|
804
647
|
const hookContext = { store, clock, options };
|
|
805
648
|
async function handle(request, response) {
|
|
806
|
-
// Webhooks come through a public relay (Tailscale Funnel, a reverse
|
|
807
|
-
// proxy) that forwards its own host name. The host check guards pages a
|
|
808
|
-
// signed-in browser reads; a delivery carries no session and its answer
|
|
809
|
-
// reveals nothing, so /hooks/ is answered before it, and only there.
|
|
810
649
|
const hook = new URL(request.url ?? "/", "http://placeholder");
|
|
811
|
-
// v99: a liveness probe for a load balancer or orchestrator. It answers before the host check (a probe
|
|
812
|
-
// uses the address it reached), reads one row, and says nothing else about the installation.
|
|
813
650
|
const method = request.method ?? "GET";
|
|
814
651
|
const matchedRoute = matchRoute(method, hook.pathname);
|
|
815
|
-
// Where a slow answer's time went (latency-timeline.ts): milestones by route id only, kept when it took a second.
|
|
816
652
|
const timeline = new Timeline();
|
|
817
653
|
timeline.mark("route matched");
|
|
818
654
|
const edgeRoute = matchedRoute?.stage === 'edge' ? matchedRoute : null;
|
|
819
655
|
const wrongMethodEdge = edgeRoute === null ? ROUTES.find(row => row.stage === 'edge' && new RegExp(row.pattern).test(hook.pathname)) ?? null : null;
|
|
820
|
-
// D7: a password on a request still signs in this release, announced on every answer and named in every refusal;
|
|
821
|
-
// from the release that removes it, it is refused here before anything checks it.
|
|
822
656
|
if (isPasswordBearer(request.headers.authorization)) {
|
|
823
657
|
if (!(options.passwordBearerAccepted ?? passwordBearerAccepted())) {
|
|
824
658
|
request.resume();
|
|
@@ -835,9 +669,6 @@ export function createDecisionServer(options) {
|
|
|
835
669
|
if (!allowedHost(request.headers.host)) {
|
|
836
670
|
return respond(response, 421, "text/html; charset=utf-8", wrongHostPage(wrongHost(request.headers.host)));
|
|
837
671
|
}
|
|
838
|
-
// Easy-start C2: a protected loopback install has one browser origin, whose storage holds the session's mutation key.
|
|
839
|
-
// A browser's page read at another loopback name (localhost, [::1]) moves there; machine callers and protocol
|
|
840
|
-
// adapters (an API token, MCP's own addresses) are left where they are.
|
|
841
672
|
const canonical = browserKeys.canonicalHost();
|
|
842
673
|
if (canonical !== null && request.headers.host !== canonical && (method === "GET" || method === "HEAD") && request.headers.authorization === undefined
|
|
843
674
|
&& (edgeRoute === null || edgeRoute.domain === "people")) {
|
|
@@ -846,8 +677,6 @@ export function createDecisionServer(options) {
|
|
|
846
677
|
response.end();
|
|
847
678
|
return;
|
|
848
679
|
}
|
|
849
|
-
// A real domain (public-access.ts): HSTS for the public https host reached over HTTPS, and no API token over
|
|
850
|
-
// plain HTTP from outside this computer and the tailnet — refused before anything reads or checks it.
|
|
851
680
|
const transport = transportOf({ peer: request.socket.remoteAddress, joinSource: forwardedSourceOf(request), forwardedProto: request.headers["x-forwarded-proto"], forwarded: request.headers["forwarded"] });
|
|
852
681
|
const hsts = hstsFor(publicOrigin?.host ?? null, request.headers.host, transport);
|
|
853
682
|
if (hsts !== null)
|
|
@@ -858,31 +687,19 @@ export function createDecisionServer(options) {
|
|
|
858
687
|
return respond(response, 403, "text/plain; charset=utf-8", insecure);
|
|
859
688
|
}
|
|
860
689
|
const url = new URL(request.url ?? "/", "http://placeholder");
|
|
861
|
-
// A token in a URL is a token in history, logs, and referers. Refused
|
|
862
|
-
// outright rather than ignored, so nobody learns the habit works.
|
|
863
690
|
if (url.searchParams.has("token")) {
|
|
864
691
|
return respond(response, 400, "text/plain; charset=utf-8", "credentials never travel in URLs");
|
|
865
692
|
}
|
|
866
693
|
if (edgeRoute === null && isEdgeAddress(url.pathname))
|
|
867
694
|
return refuseEdge(request, response, url.pathname, wrongMethodEdge);
|
|
868
|
-
// Live rooms share the browser identity/context below; their adapter carries token limits into each room.
|
|
869
695
|
if (edgeRoute !== null && edgeRoute.domain !== 'people' && edgeRoute.domain !== 'live')
|
|
870
696
|
return dispatchEdge(edgeRoute, { url, who: null, request, response, method });
|
|
871
|
-
// Passive polls authenticate without extending the browser session.
|
|
872
697
|
const fragmentName = url.searchParams.get("fragment");
|
|
873
698
|
const workspaceRead = method === "GET" && url.searchParams.get('format') === 'workspace';
|
|
874
|
-
// A workspace read's purpose (live-pages-and-home.md A1.4): bookkeeping only. Read on workspace GETs alone; on any other
|
|
875
|
-
// request the header means nothing. No authorisation decision below reads it.
|
|
876
699
|
const purpose = workspaceRead ? readPurpose(request.headers['x-toolroll-read']) : 'poll';
|
|
877
|
-
// The reads that never extend the session, whatever their header says.
|
|
878
700
|
const noTouch = edgeRoute?.domain === 'live' || (fragmentName !== null && NO_TOUCH_FRAGMENTS.has(fragmentName)) || /^\/code\/[a-f0-9]{32}\/state$/.test(url.pathname) || url.pathname === '/term/state'
|
|
879
|
-
// The Agents view's Live grid only watches: its polls never extend or write the session.
|
|
880
701
|
|| url.pathname === '/agents/live' || /^\/agents\/live\/[0-9]{1,15}$/.test(url.pathname) || (url.pathname === '/agents' && url.searchParams.get('view') === 'live');
|
|
881
|
-
// A followed link (`navigate`) extends the session exactly as the HTML GET of the same address would; every other
|
|
882
|
-
// workspace read (a re-read, a prefetch) does not.
|
|
883
702
|
const touch = !(method === "GET" && (noTouch || (workspaceRead && purpose !== 'navigate')));
|
|
884
|
-
// A read ahead is answered only for a browser session, only for the prefetch allowlist (in-place.ts): anything else
|
|
885
|
-
// hears 204 before any sign-in bookkeeping (a token's last use, a sign-in charge) is written.
|
|
886
703
|
if (purpose === 'prefetch' && (request.headers.authorization !== undefined || !prefetchRoute(matchedRoute?.id, url))) {
|
|
887
704
|
request.resume();
|
|
888
705
|
return respond(response, 204, "text/plain; charset=utf-8", "");
|
|
@@ -896,15 +713,11 @@ export function createDecisionServer(options) {
|
|
|
896
713
|
respond(response, admitted.status, "text/plain; charset=utf-8", admitted.status === 429 ? limitWords(admitted.limit, admitted.retryAfter) : "Request limits could not be checked; nothing ran. Try again shortly.");
|
|
897
714
|
return true;
|
|
898
715
|
};
|
|
899
|
-
// One source charge before password proof and one account/token charge after it, including GET /login.
|
|
900
716
|
if (refuseBudget(admitPasswordSource(request)))
|
|
901
717
|
return;
|
|
902
718
|
const refusedToken = {};
|
|
903
719
|
const who = identify(request, touch, edgeRoute?.domain === 'live', refusedToken);
|
|
904
720
|
timeline.mark("signed in");
|
|
905
|
-
// Local-owner slice 0: a local owner's session presented from anywhere but this computer (another address, a
|
|
906
|
-
// proxy, a tailnet or LAN name) signs in no one and changes nothing. Sign-in pages still answer (a password signs
|
|
907
|
-
// in there); everything else is refused in plain words.
|
|
908
721
|
if (refusedToken.elsewhere === true && edgeRoute?.domain !== 'people') {
|
|
909
722
|
request.resume();
|
|
910
723
|
response.setHeader("x-toolroll-refused", "local-owner-elsewhere");
|
|
@@ -920,7 +733,6 @@ export function createDecisionServer(options) {
|
|
|
920
733
|
}
|
|
921
734
|
if (who?.via === "bearer" && refuseBudget(admitBearer(request, who)))
|
|
922
735
|
return;
|
|
923
|
-
// A read ahead from anything but a signed-in browser session (signed out, a token): 204, never the sign-in page.
|
|
924
736
|
if (purpose === 'prefetch' && who?.via !== 'cookie') {
|
|
925
737
|
request.resume();
|
|
926
738
|
return respond(response, 204, "text/plain; charset=utf-8", "");
|
|
@@ -930,11 +742,8 @@ export function createDecisionServer(options) {
|
|
|
930
742
|
if (edgeRoute?.domain === 'people')
|
|
931
743
|
return freshFacts.run(fresh, () => provenPasswordAccount.run(passwordProof, () => dispatchEdge(edgeRoute, { url, who, request, response, method })));
|
|
932
744
|
if (who === null) {
|
|
933
|
-
// A password on a request that did not sign in is a machine's refusal, never a login page.
|
|
934
745
|
if (isPasswordBearer(request.headers.authorization))
|
|
935
746
|
return respond(response, 401, "text/plain; charset=utf-8", "authenticate first");
|
|
936
|
-
// A GET to an exact task or result (a phone's deep link) signs in and
|
|
937
|
-
// comes back to it — the destination is a same-site path only.
|
|
938
747
|
return method === "GET"
|
|
939
748
|
? redirect(response, loginHref(url.pathname + url.search))
|
|
940
749
|
: respond(response, 401, "text/plain; charset=utf-8", "authenticate first");
|
|
@@ -946,15 +755,11 @@ export function createDecisionServer(options) {
|
|
|
946
755
|
actor: who.name,
|
|
947
756
|
csrf: who.via === "cookie" ? who.session.csrf : "",
|
|
948
757
|
returnTo: safeReturn(url.pathname + url.search),
|
|
949
|
-
// This console's own addresses: a lead reply's links there read as "the task", "the result", "Settings → Lead".
|
|
950
758
|
appOrigins: [consoleOrigin(request.headers.host), publicOrigin?.origin ?? null, options.configDir === undefined ? null : loadConsoleUrl(process.env, options.configDir)],
|
|
951
|
-
// Every signed-in page shares the workspace shell; pages showing a one-time secret opt out (forceSensitive).
|
|
952
759
|
browser: who.via === 'cookie',
|
|
953
|
-
// Passwordless (read once for rendering; every act proves it again at the act): ceremony fields render as nothing.
|
|
954
760
|
passwordless: who.via === 'cookie' && passwordlessOn(store),
|
|
761
|
+
advanced: advancedShownFor(store, who.name),
|
|
955
762
|
openProject: who.via === 'cookie' ? who.session.project : null,
|
|
956
|
-
// v100: signed in with the identity provider: its label, and whether it checked them recently enough to stand in for a password.
|
|
957
|
-
// Cockpit B2: "fresh" is an explicit re-check made on request and not yet spent (read live; one step-up uses it).
|
|
958
763
|
sso: who.via === 'cookie' && who.session.sso !== undefined ? { label: ssoSettings()?.label ?? "your identity provider",
|
|
959
764
|
get fresh() { return freshFacts.getStore() != null && ssoNowAvailable(who.name); } } : undefined,
|
|
960
765
|
refusal: (answer, status, body) => sendScreen(answer, status, screen(status === 404 ? "Not found" : "Request refused", body, { chrome: chromeFor(who.via === "cookie" ? who.session.project : null, "work") })),
|
|
@@ -966,15 +771,11 @@ export function createDecisionServer(options) {
|
|
|
966
771
|
...(workspaceRead && typeof request.headers['if-none-match'] === 'string' ? { workspaceIfNoneMatch: request.headers['if-none-match'] } : {}),
|
|
967
772
|
workspaceRequest: url.searchParams.get('request'),
|
|
968
773
|
timeline,
|
|
969
|
-
// Easy-start C2: every page that posts carries the key fill while the key is required; a session whose key is from
|
|
970
|
-
// an earlier start (or has none) is told to reconnect.
|
|
971
774
|
keyFill: browserKeys.required(),
|
|
972
|
-
// Easy start: a local owner with no password sees "Set a password to do this." where a step-up field would be.
|
|
973
775
|
...(who.via === "cookie" && who.authority === "local-owner" && store.accountOf(who.name)?.passwordSet === false
|
|
974
776
|
? { localStepUp: localOwnerRefusal(false, method === "GET" ? passwordSetNext(pagePathOf(url)) : "/").href } : {}),
|
|
975
777
|
reconnect: browserKeys.stale(who, method === "GET" ? safeReturn(pagePathOf(url)) : "/"),
|
|
976
778
|
};
|
|
977
|
-
// A read ahead writes nothing, not even a slow request's record.
|
|
978
779
|
if (purpose !== 'prefetch')
|
|
979
780
|
response.once("finish", () => keepSlowRequest(store, timeline, matchedRoute?.id ?? "unmatched", response.statusCode, clock()));
|
|
980
781
|
if (method === "GET" || method === "POST")
|
|
@@ -984,16 +785,11 @@ export function createDecisionServer(options) {
|
|
|
984
785
|
const body = method === "POST" ? await form(request, (matchedRoute?.stage === "console" ? matchedRoute.bodyCap : undefined) ?? BODY_CAP) : null;
|
|
985
786
|
const target = actionTarget(url, who, request, body === null ? null : readForm(body, CONSOLE_FORMS.ledgerTarget));
|
|
986
787
|
const execute = async () => {
|
|
987
|
-
// THE ROUTE TABLE (server/route-table.ts): nothing reaches a handler unless a row declares this method and
|
|
988
|
-
// path and admits this kind of caller. Undeclared addresses retain the legacy instance-access refusal
|
|
989
|
-
// for project-limited accounts, before the unrestricted router's not-found response.
|
|
990
788
|
const route = matchedRoute?.stage === "console" ? matchedRoute : null;
|
|
991
789
|
if (route === null)
|
|
992
790
|
return restricted()
|
|
993
791
|
? refuse(response, who, 403, "This area requires instance access. Your account operates within its assigned projects.", "/projects")
|
|
994
792
|
: refuse(response, who, 404, "There's no page at this address.", "/chat");
|
|
995
|
-
// Easy-start C1: a local owner's session reaches only the rows marked for it (route-table.ts `local`), decided
|
|
996
|
-
// first, before the route's policy reads anything and before any handler runs, GET and POST alike.
|
|
997
793
|
if (who.via === "cookie" && who.authority !== "full" && (route.local !== "allow" || localPrincipalOf(who, route) === null)) {
|
|
998
794
|
request.resume();
|
|
999
795
|
return refuseLocalOwner(response, who, method, url, request.headers.accept);
|
|
@@ -1005,8 +801,6 @@ export function createDecisionServer(options) {
|
|
|
1005
801
|
request.resume();
|
|
1006
802
|
if (method === "POST" && who.via === "bearer" && who.principal?.scope === "read")
|
|
1007
803
|
return refuse(response, who, 403, REMOTE_MESSAGES.read);
|
|
1008
|
-
// A viewer's act stays refused even when the table rejects their caller first (for example a
|
|
1009
|
-
// password bearer at a step-up route). Preserve the viewer wording and explicit protocol refusals.
|
|
1010
804
|
if (policy.reason === "scope" || (method === "POST" && who.role === "viewer" && !route.viewer && route.callerRefusal === undefined)) {
|
|
1011
805
|
return refuse(response, who, 403, route.scopeRefusal ?? "your login can watch, not act — ask an approver to upgrade you");
|
|
1012
806
|
}
|
|
@@ -1015,8 +809,6 @@ export function createDecisionServer(options) {
|
|
|
1015
809
|
: respond(response, route.callerRefusal.status, route.callerRefusal.type, route.callerRefusal.body);
|
|
1016
810
|
}
|
|
1017
811
|
if (method === "GET") {
|
|
1018
|
-
// Authorize every read before considering a conditional response.
|
|
1019
|
-
// Task/result opening and receipt reconciliation always re-read work.
|
|
1020
812
|
const facts = requestContext.getStore();
|
|
1021
813
|
if (facts?.workspaceRead && who.via === 'cookie' && route.id === 'chat.page' &&
|
|
1022
814
|
!url.searchParams.has('task') && !url.searchParams.has('result') && !url.searchParams.has('request')) {
|
|
@@ -1030,15 +822,11 @@ export function createDecisionServer(options) {
|
|
|
1030
822
|
return respond(response, 304, 'application/json; charset=utf-8', '');
|
|
1031
823
|
}
|
|
1032
824
|
const expiresAt = workspaceRevision.expiresAt(now);
|
|
1033
|
-
// A clock-bound refresh receives a different validator even when
|
|
1034
|
-
// no database row changed (for example an expired worker lease).
|
|
1035
825
|
facts.workspaceValidator = { key, revision, expiresAt,
|
|
1036
826
|
etag: '"' + createHash('sha256').update(`${key}:${revision}:${expiresAt}`).digest('hex') + '"' };
|
|
1037
827
|
}
|
|
1038
828
|
await prefetchChrome(route, url, who);
|
|
1039
829
|
timeline.mark("chrome and worker reads");
|
|
1040
|
-
// The worker wait lets a sign-out, credential/access change or console ceiling change land. Prove the
|
|
1041
|
-
// cookie and route again before rendering protected content or answering with a content validator.
|
|
1042
830
|
if (who.via === 'cookie') {
|
|
1043
831
|
const current = identify(request, false);
|
|
1044
832
|
if (current?.via !== 'cookie' || current.session !== who.session)
|
|
@@ -1050,16 +838,12 @@ export function createDecisionServer(options) {
|
|
|
1050
838
|
}
|
|
1051
839
|
return handlePost(route, url, who, request, response, body);
|
|
1052
840
|
};
|
|
1053
|
-
// Easy-start C1: an allowed row runs as the local owner, in the act the row is (execute refuses every other): the
|
|
1054
|
-
// prover answers "local-owner" only for that act, and every write it makes re-proves it still stands.
|
|
1055
841
|
const local = who.via === "cookie" && who.authority !== "full" && matchedRoute?.stage === "console" && matchedRoute.local === "allow" ? localPrincipalOf(who, matchedRoute) : null;
|
|
1056
842
|
if (local !== null)
|
|
1057
843
|
response.once("close", () => { local.request.ended = true; });
|
|
1058
844
|
const run = () => local === null ? execute() : asLocalOwner(local, execute);
|
|
1059
845
|
if (method === "GET")
|
|
1060
846
|
return projectAuthority.run({ actor: who.name, repo: target.repo }, run);
|
|
1061
|
-
// Request acceptance is separate from durable work completion. Never
|
|
1062
|
-
// persist a body, query string, token, password, or arbitrary URL.
|
|
1063
847
|
const entry = { at: clock().toISOString(), actor: who.name, ...target, source: "request", ...(who.via === "bearer" && who.token !== undefined ? { detail: `API token: ${who.token}` } : {}) };
|
|
1064
848
|
store.recordAction({ ...entry, outcome: "requested" });
|
|
1065
849
|
try {
|
|
@@ -1083,7 +867,7 @@ export function createDecisionServer(options) {
|
|
|
1083
867
|
try {
|
|
1084
868
|
repo = coding.get(match[1], { name: who.name, generation: who.session.generation }).repo;
|
|
1085
869
|
}
|
|
1086
|
-
catch {
|
|
870
|
+
catch { }
|
|
1087
871
|
}
|
|
1088
872
|
return { repo, taskId: null, runId: null, action: `coding ${body ? url.pathname.split('/').at(-1) : 'view'}` };
|
|
1089
873
|
}
|
|
@@ -1134,9 +918,6 @@ export function createDecisionServer(options) {
|
|
|
1134
918
|
if (project === undefined) {
|
|
1135
919
|
return refuse(response, who, 403, "that project is outside what this server was configured to show");
|
|
1136
920
|
}
|
|
1137
|
-
// A project link is a read context, not a session-changing operation.
|
|
1138
|
-
// Prove it against both admission and the known project catalog before
|
|
1139
|
-
// collection queries; unknown/foreign paths reveal no work.
|
|
1140
921
|
if ((route.id === 'tasks' || route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
|
|
1141
922
|
const wanted = url.searchParams.get('project') ?? '';
|
|
1142
923
|
if (url.searchParams.getAll('project').length !== 1 || !visible(wanted) ||
|
|
@@ -1145,8 +926,6 @@ export function createDecisionServer(options) {
|
|
|
1145
926
|
}
|
|
1146
927
|
project = wanted;
|
|
1147
928
|
}
|
|
1148
|
-
// Home (UI revamp wave B) shows every project unless its address names one (proved the same way), and the rail's
|
|
1149
|
-
// and the dock's Needs-you count follow that same one scope.
|
|
1150
929
|
if (route.id === 'home') {
|
|
1151
930
|
const wanted = url.searchParams.get('project');
|
|
1152
931
|
if (wanted !== null && (url.searchParams.getAll('project').length !== 1 || !visible(wanted) ||
|
|
@@ -1155,19 +934,12 @@ export function createDecisionServer(options) {
|
|
|
1155
934
|
}
|
|
1156
935
|
project = wanted;
|
|
1157
936
|
}
|
|
1158
|
-
// All projects, asked for by name on Tasks (its project filter): the rolled-up list, admission-bound as ever.
|
|
1159
|
-
// Tasks (P1.4) says every project as scope=all; an old link's all=1 still reads so.
|
|
1160
937
|
if (route.id === 'tasks' && !url.searchParams.has('project') && ((url.searchParams.get('scope') === 'all' && url.searchParams.getAll('scope').length === 1)
|
|
1161
938
|
|| (url.searchParams.get('all') === '1' && url.searchParams.getAll('all').length === 1)))
|
|
1162
939
|
project = null;
|
|
1163
|
-
// Every page's Tasks count covers this one project view, whatever project the page itself shows.
|
|
1164
940
|
const facts = requestContext.getStore();
|
|
1165
941
|
if (facts !== undefined)
|
|
1166
942
|
facts.lens = project;
|
|
1167
|
-
// Exact result links carry their own read context. Check the stored
|
|
1168
|
-
// placement against both account and instance access before using it;
|
|
1169
|
-
// viewing a result never changes the session's selected project, and
|
|
1170
|
-
// the page's project switch keeps showing the person's own choice.
|
|
1171
943
|
const chosenProject = project;
|
|
1172
944
|
if (route.id === "review" && url.searchParams.has("result")) {
|
|
1173
945
|
const wanted = url.searchParams.get("result") ?? "";
|
|
@@ -1180,24 +952,6 @@ export function createDecisionServer(options) {
|
|
|
1180
952
|
if (who.via === "cookie" && ref !== null && visible(ref.repo))
|
|
1181
953
|
project = ref.repo;
|
|
1182
954
|
}
|
|
1183
|
-
// Nothing open and more than one thing to choose: land on the opener.
|
|
1184
|
-
// Decisions and their evidence stay reachable — answering must never be
|
|
1185
|
-
// blocked by project state — and the opener itself must not loop.
|
|
1186
|
-
// A run's page and its evidence (workspace package 1): a bookmarked
|
|
1187
|
-
// `/r/<id>` from All projects used to bounce to the opener until a
|
|
1188
|
-
// project was chosen. The handler below re-proves the run's repo
|
|
1189
|
-
// against the ceiling and the account (`runVisible`) before a byte
|
|
1190
|
-
// renders, so letting the path through widens nothing.
|
|
1191
|
-
// The chat's two read-only refresh routes (package 2 revision): the
|
|
1192
|
-
// page itself is allowed from All projects, so its status poll and
|
|
1193
|
-
// task fragment must be too — a 303 to the opener answered the poll
|
|
1194
|
-
// with HTML and the page wrongly said the sign-in was lost. Each
|
|
1195
|
-
// route keeps its own cookie, role, session, ceiling, and task
|
|
1196
|
-
// admission checks. Shared action links likewise recheck the saved
|
|
1197
|
-
// owner and project in their handler, so they stay reachable from All
|
|
1198
|
-
// projects without changing the selected project or granting access.
|
|
1199
|
-
// Which reads first need an open project is the route table's `needsProject` column; an exact result link
|
|
1200
|
-
// and the all-projects board carry their own read context.
|
|
1201
955
|
const needsProject = who.via === "cookie" && project === null && !unscopedMode &&
|
|
1202
956
|
route.needsProject &&
|
|
1203
957
|
!(route.id === "review" && url.searchParams.has("result")) &&
|
|
@@ -1206,32 +960,15 @@ export function createDecisionServer(options) {
|
|
|
1206
960
|
return redirect(response, `/projects?return=${encodeURIComponent(safeReturn(url.pathname + url.search))}`);
|
|
1207
961
|
return dispatchConsole(route, { url, who, request, response, route, now, project, chosenProject, posted: new URLSearchParams() });
|
|
1208
962
|
}
|
|
1209
|
-
/**
|
|
1210
|
-
* The first run (adoption track, step 3): three plain steps derived from
|
|
1211
|
-
* live state on every render, never a stored cursor, and retired
|
|
1212
|
-
* PERMANENTLY by the first-success installation fact (Codex adoption
|
|
1213
|
-
* review, finding 14). Each step is either something this console can do,
|
|
1214
|
-
* or the exact command where only the CLI can (finding e).
|
|
1215
|
-
*/
|
|
1216
963
|
function firstRunStepsNow(now) {
|
|
1217
964
|
if (restricted() || store.isDemo() || store.firstSuccessAt(now) !== null)
|
|
1218
965
|
return null;
|
|
1219
966
|
return firstRunSteps({ agentSignedIn: agentSignedIn(now), projects: managedRepos().length, hasTask: store.hasAnyWork(), firstResultAt: null, signInCommand: agentSignInCommand() });
|
|
1220
967
|
}
|
|
1221
|
-
/**
|
|
1222
|
-
* Whether a coding agent is signed in where the work runs. This machine's
|
|
1223
|
-
* own checks (the ones Settings makes) speak only for a worker on this
|
|
1224
|
-
* machine, or for the first one while none is registered yet (it is started
|
|
1225
|
-
* here); a worker elsewhere speaks through its own readiness report, and
|
|
1226
|
-
* the console never claims to have checked that machine (finding 15).
|
|
1227
|
-
* Nothing here waits on a probe: this machine's answer is the last one
|
|
1228
|
-
* seen, refreshed in the background, and null until the first one is in.
|
|
1229
|
-
*/
|
|
1230
968
|
function agentSignedIn(now) {
|
|
1231
969
|
const here = hostname();
|
|
1232
970
|
const registered = store.listRunners().filter(one => one.retiredAt === null);
|
|
1233
971
|
const workers = registered.filter(one => runnerAlive(one, now));
|
|
1234
|
-
// This machine under any of its own names (machine-identity.ts): a hostname that moved with the network is still here.
|
|
1235
972
|
if (workers.some(one => !sameMachineHost(one.host, here) && store.providerReadiness(one.name).some(seen => seen.state === "ready")))
|
|
1236
973
|
return true;
|
|
1237
974
|
return options.localRunner !== undefined || registered.length === 0 || workers.some(one => sameMachineHost(one.host, here)) ? localAgentSignedIn() : false;
|
|
@@ -1239,7 +976,6 @@ export function createDecisionServer(options) {
|
|
|
1239
976
|
let localSignIn = null;
|
|
1240
977
|
let localSignInChecking = null;
|
|
1241
978
|
let leadRecheckedAt = 0;
|
|
1242
|
-
/** Ask this computer's agent CLIs again (no model, nothing spent); `fresh` skips their 30-second cache. */
|
|
1243
979
|
function checkLocalAgents(fresh = false) {
|
|
1244
980
|
if (localSignInChecking !== null)
|
|
1245
981
|
return localSignInChecking;
|
|
@@ -1247,22 +983,16 @@ export function createDecisionServer(options) {
|
|
|
1247
983
|
.then(([claude, codex]) => {
|
|
1248
984
|
localSignIn = { at: Date.now(), signedIn: [claude, codex].some(state => state === "connected" || state === "key-works" || state === "key-present"), states: { claude: claude, codex: codex } };
|
|
1249
985
|
leadByDefault();
|
|
986
|
+
if (options.leadByDefault === true && !store.isDemo())
|
|
987
|
+
fillRoutingOnSignIn(store, localSignIn.states, clock());
|
|
1250
988
|
})
|
|
1251
989
|
.catch(() => { })
|
|
1252
990
|
.finally(() => { localSignInChecking = null; });
|
|
1253
991
|
return localSignInChecking;
|
|
1254
992
|
}
|
|
1255
|
-
/** The last answer only (docs/plans/get-side-effects.md): this computer is asked again by the background checks or a
|
|
1256
|
-
* person's Check now, never because a page was opened. */
|
|
1257
993
|
function localAgentSignedIn() {
|
|
1258
994
|
return localSignIn?.signedIn ?? null;
|
|
1259
995
|
}
|
|
1260
|
-
/**
|
|
1261
|
-
* The lead on by default (onboarding): with no lead set up yet, the agent CLI signed in on this computer runs it
|
|
1262
|
-
* (Claude Code first, else Codex) on its membership with today's safe defaults: the CLI's own default model, 50 turns
|
|
1263
|
-
* a day, no dollar spend, and every action it proposes still a card a person confirms. Once only, ever: a lead
|
|
1264
|
-
* someone turned off stays off, and Settings → Lead changes it.
|
|
1265
|
-
*/
|
|
1266
996
|
function leadByDefault() {
|
|
1267
997
|
if (options.leadByDefault !== true || store.isDemo() || store.getChatConfig() !== null || store.installationFact(LEAD_BY_DEFAULT_FACT) !== null)
|
|
1268
998
|
return;
|
|
@@ -1273,29 +1003,21 @@ export function createDecisionServer(options) {
|
|
|
1273
1003
|
store.transact(() => {
|
|
1274
1004
|
store.setChatConfig({ provider, model: "default", dailyTurns: 50, weeklyCeilingMicrousd: 0, priceInMicrousd: 0, priceOutMicrousd: 0 }, "toolroll", now);
|
|
1275
1005
|
store.recordInstallationFact(LEAD_BY_DEFAULT_FACT, provider, now);
|
|
1276
|
-
// A laptop install (local mode on): the agent chosen here also starts the models, on its default preset, while
|
|
1277
|
-
// nothing is chosen yet, so the owner's first task plans without a password (model-choices.ts fillDefaultRouting).
|
|
1278
1006
|
const agent = defaultAgentOf(provider);
|
|
1279
1007
|
if (agent !== null && localModeOn(store))
|
|
1280
1008
|
fillDefaultRouting(store, agent, "toolroll", { kind: "first-start" }, now);
|
|
1281
1009
|
});
|
|
1282
1010
|
}
|
|
1283
|
-
// Look once at start, so the lead is on by the time the browser opens.
|
|
1284
1011
|
if (options.leadByDefault === true && !store.isDemo() && store.getChatConfig() === null)
|
|
1285
1012
|
void checkLocalAgents();
|
|
1286
|
-
/** What the lead runs on, in words for one line ("your Claude Code sign-in"); null for a direct API or no lead. */
|
|
1287
1013
|
function leadWords() {
|
|
1288
1014
|
const config = store.getChatConfig();
|
|
1289
1015
|
return config?.provider === "claude-subscription" ? "your Claude Code sign-in" : config?.provider === "codex-subscription" ? "your Codex sign-in" : null;
|
|
1290
1016
|
}
|
|
1291
|
-
/** The one command that gets an agent signed in here, for this operating system: sign in when its CLI is installed, else install Claude Code and sign in. */
|
|
1292
1017
|
function agentSignInCommand() {
|
|
1293
1018
|
return signInCommandFor(localSignIn?.states ?? null, options.platform ?? process.platform);
|
|
1294
1019
|
}
|
|
1295
|
-
/** First tasks per project: the last ones found (safe generic ones until then), re-read in the background at most
|
|
1296
|
-
* every ten minutes. A render never waits on `gh` or `git grep`. */
|
|
1297
1020
|
const firstTasks = new Map();
|
|
1298
|
-
/** The phone setup itself (Settings → Chat apps): a chat app, or this console over Tailscale. */
|
|
1299
1021
|
function phoneSetup(who) {
|
|
1300
1022
|
if (who.role !== "approver" || store.isDemo())
|
|
1301
1023
|
return undefined;
|
|
@@ -1310,49 +1032,27 @@ export function createDecisionServer(options) {
|
|
|
1310
1032
|
dismissHref: "/onboarding/phone/dismiss",
|
|
1311
1033
|
};
|
|
1312
1034
|
}
|
|
1313
|
-
// ---- fleet chat (v13) ----------------------------------------------------
|
|
1314
1035
|
const chatFetcher = options.chatFetcher ?? fetch;
|
|
1315
1036
|
const chatEnv = options.chatEnv ?? process.env;
|
|
1316
|
-
/** The lead's last non-answer per BROWSER session (keyed by its csrf —
|
|
1317
|
-
* never by name, so two browsers on one account do not read each other's
|
|
1318
|
-
* notes), bound to the mate turn it came from so a note from a session
|
|
1319
|
-
* that has since ended never shows; bounded; read once. */
|
|
1320
1037
|
const leadSaid = new Map();
|
|
1321
|
-
/** The unified conversation's rows for one reader (package 2): the SAME
|
|
1322
|
-
* rows the page renders and the status poll's fragments re-render, so a
|
|
1323
|
-
* live update can never show a card the page would not. A task lens
|
|
1324
|
-
* keeps only that task's coordinator cards; the lead's own thread is one
|
|
1325
|
-
* thread regardless of lens. */
|
|
1326
1038
|
function leadConversationRows(who, principal, focusTask, now, chatProject = null) {
|
|
1327
1039
|
const allCoordinatorRows = store.listCoordinatorProposals({ repos: managedRepos(), states: ["pending", "confirmed", "refused"], limit: 30 });
|
|
1328
1040
|
const coordinatorProposals = focusTask !== null ? allCoordinatorRows.filter(one => focusTask.family.versions.some(version => version.id === one.payload["task"]))
|
|
1329
1041
|
: chatProject !== null ? allCoordinatorRows.filter(one => one.repo === chatProject) : allCoordinatorRows;
|
|
1330
|
-
// A visit only reads (quiet page visits): this opens no thread. The first message opens it (chatSend), and a
|
|
1331
|
-
// live thread kept under another ceiling is what that message replaces, so it reads here as the earlier one.
|
|
1332
1042
|
const found = store.liveLeadThreadFor(who.name, chatScopeOf(focusTask, chatProject));
|
|
1333
1043
|
const thread = found !== null && found.ceilingDigest === principal.ceilingDigest ? found : null;
|
|
1334
1044
|
const proposals = thread === null ? [] : store.listLeadProposals(thread.id);
|
|
1335
|
-
// One reply runs at a time per person; this thread shows it only when
|
|
1336
|
-
// the reply is its own.
|
|
1337
1045
|
const live = store.liveLeadTurnFor(who.name);
|
|
1338
1046
|
const messages = thread === null ? [] : store.listLeadMessages(thread.id, 40);
|
|
1339
|
-
// The lead's question with buttons, while its reply is the last word in the thread.
|
|
1340
1047
|
const last = messages.at(-1);
|
|
1341
1048
|
const asking = last?.role === "assistant" && last.turn !== null && store.getLeadTurn(last.turn)?.approver === who.name ? store.leadAskOpen(last.turn, now) : null;
|
|
1342
|
-
// A question about this task loses its buttons once the version shown moved after it was asked (its plan
|
|
1343
|
-
// rewritten or approved, a new attempt started): its options answered a state that is gone. Its words stay, marked so.
|
|
1344
1049
|
const staleAsk = asking !== null && focusTask !== null && taskMovedSince(store, focusTask.executionId, asking.createdAt) ? asking.turn : null;
|
|
1345
1050
|
const ask = staleAsk === null ? asking : null;
|
|
1346
|
-
// Answered questions stay readable above the answer; only their buttons go.
|
|
1347
1051
|
const asks = new Map(messages.flatMap(one => { const asked = one.role === "assistant" && one.turn !== null ? store.leadAsk(one.turn) : null; return asked === null ? [] : [[asked.turn, asked]]; }));
|
|
1348
|
-
// The person's queued messages in this thread: each shows waiting (with Remove) or why it was not sent.
|
|
1349
1052
|
const queue = new Map(thread === null ? [] : personalQueue.queue.forThread(thread.id).map(row => [row.message, row]));
|
|
1350
|
-
// The thread a ceiling change replaced (ruling 9), display only: closed already, or still live under the old ceiling.
|
|
1351
1053
|
const replaced = thread !== null ? store.replacedLeadThread(thread)
|
|
1352
1054
|
: found !== null && found.scope.kind === "lead" && store.listLeadMessages(found.id, 1).length > 0 ? found : null;
|
|
1353
1055
|
const previousProposals = replaced === null ? [] : store.listLeadProposals(replaced.id);
|
|
1354
|
-
// How this thread's last reply ended, read from its saved turn (never process memory, which a restart loses): a
|
|
1355
|
-
// failed turn that saved no message of its own says why in the thread, until the next reply starts.
|
|
1356
1056
|
const lastTurn = thread === null ? null : latestLeadTurnOfThread(store, thread.id);
|
|
1357
1057
|
const failure = lastTurn !== null && lastTurn.state === "failed" && !messages.some(one => one.role === "assistant" && one.turn === lastTurn.id)
|
|
1358
1058
|
? leadFailureText(lastTurn.failureReason, store.leadTurnCostUnconfirmed(lastTurn.id), lastTurn.failureDetail ?? null) : null;
|
|
@@ -1371,18 +1071,10 @@ export function createDecisionServer(options) {
|
|
|
1371
1071
|
recent: store.recentLeadTurns(who.name, 5),
|
|
1372
1072
|
};
|
|
1373
1073
|
}
|
|
1374
|
-
/** The thread a chat surface speaks in (v77): the task's own thread, the
|
|
1375
|
-
* project's, or the lead conversation across every project. */
|
|
1376
1074
|
function chatScopeOf(focusTask, chatProject) {
|
|
1377
1075
|
return focusTask !== null ? { kind: "task", key: focusTask.id } : chatProject !== null ? { kind: "project", key: chatProject } : LEAD_THREAD;
|
|
1378
1076
|
}
|
|
1379
1077
|
const liveTurns = new Map();
|
|
1380
|
-
/** The Ask panel (v77): the conversation a task, result or project page
|
|
1381
|
-
* docks beside itself — that page's own thread, the same session and
|
|
1382
|
-
* cards as /chat. Null when this person has no lead chat here. A page
|
|
1383
|
-
* view starts nothing (quiet page visits): with no membership
|
|
1384
|
-
* conversation yet, the panel binds its sends to NOT_STARTED_SESSION and
|
|
1385
|
-
* the first message starts one (chatSend). */
|
|
1386
1078
|
function dockedConversation(who, focusTask, chatProject, now, back, resultRunId = null) {
|
|
1387
1079
|
if (who.via !== "cookie" || who.role !== "approver" || (focusTask === null && chatProject === null))
|
|
1388
1080
|
return null;
|
|
@@ -1403,21 +1095,13 @@ export function createDecisionServer(options) {
|
|
|
1403
1095
|
taskId: focusTask?.id ?? null, resultRunId, project: focusTask === null ? chatProject : null, failure: rows.pending === null ? rows.failure : null,
|
|
1404
1096
|
};
|
|
1405
1097
|
}
|
|
1406
|
-
/** The session-layer principal (ruling 3): cookie, csrf, and role were
|
|
1407
|
-
* proved at the edge; the row and the generation are re-proved here. */
|
|
1408
|
-
/** Start the person's lead conversation: the session every later turn
|
|
1409
|
-
* debits (a membership spends nothing; direct API gets a per-conversation
|
|
1410
|
-
* ceiling) and its thread. Starting ends any older session. */
|
|
1411
1098
|
function startLeadConversation(who, principal, enabled, ceilingUsd, follow, now, scope = LEAD_THREAD, request) {
|
|
1412
|
-
// A page's first send (quiet page visits) starts it under that send's request: the start and its record are one
|
|
1413
|
-
// write, so a retry of the same request finds the conversation it started and never starts another.
|
|
1414
1099
|
if (request !== undefined) {
|
|
1415
1100
|
return store.transact(() => store.replay({ idempotencyKey: `mate-start:${who.name}:${request}`, actor: who.name, at: now }, "mate-start", () => ({ session: startLeadConversation(who, principal, enabled, ceilingUsd, follow, now, scope) })).session);
|
|
1416
1101
|
}
|
|
1417
1102
|
const ceilingMicrousd = enabled.billing === "subscription" ? 0 : Math.round(ceilingUsd * 1_000_000);
|
|
1418
1103
|
const termsDigest = createHash("sha256").update(`${ceilingMicrousd}\n${principal.ceilingDigest}`).digest("hex");
|
|
1419
1104
|
const sessionId = store.mintLeadSession({ approver: who.name, approverGeneration: principal.generation, credentialKey: enabled.credentialKey, ceilingMicrousd, ceilingDigest: principal.ceilingDigest, termsDigest }, now);
|
|
1420
|
-
// The thread the first message goes to (quiet page visits: a task's first message opens only the task's thread).
|
|
1421
1105
|
const thread = store.openLeadThread(who.name, principal.ceilingDigest, now, scope).thread;
|
|
1422
1106
|
if (follow)
|
|
1423
1107
|
configureLeadFollow(store, principal, store.getLeadSession(sessionId), thread, true, now);
|
|
@@ -1430,15 +1114,10 @@ export function createDecisionServer(options) {
|
|
|
1430
1114
|
}
|
|
1431
1115
|
const CHAT_CANDIDATES_PER_APPROVER = 9;
|
|
1432
1116
|
const CHAT_CANDIDATE_TTL_MS = 30 * 60_000;
|
|
1433
|
-
/** The frozen explicit repo list, digested canonically (sorted) — every
|
|
1434
|
-
* candidate binds to it and filing re-proves it (v2 new finding 5). */
|
|
1435
1117
|
const chatCeilingDigest = (repos = managedRepos()) => createHash("sha256").update([...repos].sort().join("\n")).digest("hex");
|
|
1436
|
-
/** The scripted lead answers only inside a demo database. */
|
|
1437
1118
|
function demoLeadHere() {
|
|
1438
1119
|
return options.demoLead !== undefined && store.isDemo() ? options.demoLead : null;
|
|
1439
1120
|
}
|
|
1440
|
-
/** Every condition re-proved per request — the render and the POST each
|
|
1441
|
-
* ask again; nothing is cached into authority. */
|
|
1442
1121
|
function chatEnablement() {
|
|
1443
1122
|
if (store.isDemo())
|
|
1444
1123
|
return { ok: false, code: "demo", why: "this is a demo database — chat cannot contact an external model" };
|
|
@@ -1471,13 +1150,6 @@ export function createDecisionServer(options) {
|
|
|
1471
1150
|
return { ok: false, code: "no-key", why: `no ${config.provider} key — paste one below (stored 0600 beside the database, never in it), or export ${CHAT_KEY_ENV[config.provider]} in the serve environment` };
|
|
1472
1151
|
return { ok: true, billing: "metered", config: config, key: key.key, keySource: key.source, price, credentialKey: credentialKeyOf(config.provider, key.key) };
|
|
1473
1152
|
}
|
|
1474
|
-
/**
|
|
1475
|
-
* Where a chat key comes from, in priority order: the serve process
|
|
1476
|
-
* environment, then the 0600 key file under the config directory (the
|
|
1477
|
-
* Telegram bot-token precedent — settable from the console, never the
|
|
1478
|
-
* database, never echoed whole). The file exists so onboarding lives
|
|
1479
|
-
* in the UI; the environment exists so operators who prefer it keep it.
|
|
1480
|
-
*/
|
|
1481
1153
|
function chatKeyFor(provider) {
|
|
1482
1154
|
const fromEnv = chatEnv[CHAT_KEY_ENV[provider]];
|
|
1483
1155
|
if (fromEnv !== undefined && fromEnv !== "")
|
|
@@ -1492,13 +1164,7 @@ export function createDecisionServer(options) {
|
|
|
1492
1164
|
return null;
|
|
1493
1165
|
}
|
|
1494
1166
|
}
|
|
1495
|
-
/** OpenRouter's live catalog, cached briefly: every selectable model
|
|
1496
|
-
* arrives WITH the price the config will pin (operator request — the
|
|
1497
|
-
* whole catalog, not a hand-pinned shortlist). null = no key or the
|
|
1498
|
-
* catalog is unreachable; callers fall back to the compiled table. */
|
|
1499
1167
|
let catalogCache = null;
|
|
1500
|
-
/** The catalog as last fetched, for a page to show (docs/plans/get-side-effects.md): a page never fetches it. The
|
|
1501
|
-
* background checks keep it current while an OpenRouter key is saved; saving a choice fetches it (chatCatalog). */
|
|
1502
1168
|
function chatCatalogKnown() {
|
|
1503
1169
|
return chatKeyFor("openrouter-api") === null ? null : catalogCache?.models ?? null;
|
|
1504
1170
|
}
|
|
@@ -1524,11 +1190,6 @@ export function createDecisionServer(options) {
|
|
|
1524
1190
|
clearTimeout(timer);
|
|
1525
1191
|
}
|
|
1526
1192
|
}
|
|
1527
|
-
/**
|
|
1528
|
-
* The palette's server-rendered index (attended review, finding 4): a
|
|
1529
|
-
* non-executable JSON block on an already-authorized page — the same
|
|
1530
|
-
* titles the page itself may render, bounded, saturation declared.
|
|
1531
|
-
*/
|
|
1532
1193
|
function paletteIndexTag(project) {
|
|
1533
1194
|
const admitted = project === null ? admissionList() : null;
|
|
1534
1195
|
const entries = [
|
|
@@ -1558,15 +1219,6 @@ export function createDecisionServer(options) {
|
|
|
1558
1219
|
const safeEntries = restricted() ? entries.filter(one => ["/tasks", "/tasks?view=needs-you", "/", "/tasks?view=board", "/flows", "/tasks?view=done", "/tasks?view=ready", "/runs", "/projects", "/ledger"].includes(one.href) || one.href.startsWith("/t/")) : entries;
|
|
1559
1220
|
return jsonScript(saturated ? [...safeEntries, { label: "… more in Tasks", href: "/tasks" }] : safeEntries, { id: "palette-index" });
|
|
1560
1221
|
}
|
|
1561
|
-
/**
|
|
1562
|
-
* The palette cache (arc 4, finding 6), and its honest contract: a
|
|
1563
|
-
* render may be up to five seconds stale after OUT-OF-PROCESS changes;
|
|
1564
|
-
* an accepted in-process mutation invalidates immediately (bustBadge),
|
|
1565
|
-
* so "one query per five seconds" holds only between invalidations;
|
|
1566
|
-
* and an OPEN page keeps its navigation-time snapshot until the next
|
|
1567
|
-
* navigation — no refresh mechanism exists or is promised. The key
|
|
1568
|
-
* carries the one configuration bit the entries vary by.
|
|
1569
|
-
*/
|
|
1570
1222
|
const paletteCache = new Map();
|
|
1571
1223
|
function paletteTagCached(project) {
|
|
1572
1224
|
const actor = requestContext.getStore()?.actor;
|
|
@@ -1578,44 +1230,26 @@ export function createDecisionServer(options) {
|
|
|
1578
1230
|
paletteCache.set(key, { at: Date.now(), tag });
|
|
1579
1231
|
return tag;
|
|
1580
1232
|
}
|
|
1581
|
-
/**
|
|
1582
|
-
* Every chromed HTML response leaves through here (arc 4, findings
|
|
1583
|
-
* 5/18): one place owns the sensitivity call, the nonce, the palette
|
|
1584
|
-
* index, the shortcuts overlay, script composition, and the CSP —
|
|
1585
|
-
* at most one nonce-bearing script per response, connect-src only when
|
|
1586
|
-
* that script fetches. The named exception: /fleet and /settings keep
|
|
1587
|
-
* their FUNCTIONAL scripts beside credential fields (a poller and the
|
|
1588
|
-
* push enrollment — neither reads the fields); the chrome additions
|
|
1589
|
-
* are what sensitivity strips.
|
|
1590
|
-
*/
|
|
1591
1233
|
function sendScreen(response, status, s) {
|
|
1592
1234
|
requestContext.getStore()?.timeline?.mark("handler done; rendering");
|
|
1593
|
-
// Sensitivity is the page as authored (cockpit §2, R14): its own explicit word, else a password field it was written
|
|
1594
|
-
// with — judged before an identity-provider sign-in replaces that field, so an SSO step-up page stays sensitive.
|
|
1595
1235
|
const authored = s.sensitive ?? (s.forceSensitive === true ||
|
|
1596
1236
|
SENSITIVE_INPUT.test(htmlString(s.body)) ||
|
|
1597
1237
|
(s.workspace?.pageHtml != null && SENSITIVE_INPUT.test(htmlString(s.workspace.pageHtml))) ||
|
|
1598
1238
|
(s.chrome?.listPane !== undefined && SENSITIVE_INPUT.test(htmlString(s.chrome.listPane))));
|
|
1599
|
-
// v100: signed in with the identity provider, a step-up's password field is that sign-in instead.
|
|
1600
1239
|
const ssoFacts = requestContext.getStore()?.sso;
|
|
1601
1240
|
if (ssoFacts !== undefined) {
|
|
1602
1241
|
const back = requestContext.getStore()?.returnTo ?? "/";
|
|
1603
|
-
// A typed-only proof (settings-kit.ts) stays a password field: its handler takes nothing else.
|
|
1604
1242
|
s = { ...s, body: keepTypedFields(s.body, ssoStepUps, ssoFacts, back), ...(s.workspace?.pageHtml == null ? {} : { workspace: { ...s.workspace, pageHtml: keepTypedFields(s.workspace.pageHtml, ssoStepUps, ssoFacts, back) } }) };
|
|
1605
1243
|
if (s.workspace?.view?.kind === "flow")
|
|
1606
1244
|
s = { ...s, workspace: { ...s.workspace, view: { ...s.workspace.view, stepUp: { label: ssoFacts.label, fresh: ssoFacts.fresh, confirmHref: `/login/sso?reauth=1&return=${encodeURIComponent(back)}` } } } };
|
|
1607
1245
|
}
|
|
1608
|
-
// Easy start: a local owner with no password has none to type: each step-up field says how to set one instead.
|
|
1609
1246
|
const localStepUp = requestContext.getStore()?.localStepUp;
|
|
1610
1247
|
if (localStepUp !== undefined) {
|
|
1611
1248
|
s = { ...s, body: localOwnerStepUps(s.body, localStepUp), ...(s.workspace?.pageHtml == null ? {} : { workspace: { ...s.workspace, pageHtml: localOwnerStepUps(s.workspace.pageHtml, localStepUp) } }) };
|
|
1612
1249
|
}
|
|
1613
|
-
// D5: team chat (the central team service) is deprecated; /chat?team=1 still opens this release, but nothing links to it.
|
|
1614
1250
|
const sensitive = authored || s.forceSensitive === true;
|
|
1615
1251
|
const requestFacts = requestContext.getStore();
|
|
1616
|
-
// Easy-start C2: while the browser mutation key is required, every page's one nonce'd script also fills the key.
|
|
1617
1252
|
const keyFill = requestFacts?.keyFill === true ? KEY_FILL_SCRIPT : "";
|
|
1618
|
-
// The settings frame (settings-kit.ts): its breadcrumb, for the shell and the workspace alike.
|
|
1619
1253
|
if (s.chrome !== undefined && s.chrome.crumbs === undefined) {
|
|
1620
1254
|
const crumbs = settingsCrumbs(new URL(requestFacts?.returnTo ?? '/', 'http://standing-orders.local').pathname, s.title, htmlString(s.body));
|
|
1621
1255
|
if (crumbs !== undefined)
|
|
@@ -1627,8 +1261,6 @@ export function createDecisionServer(options) {
|
|
|
1627
1261
|
path.searchParams.delete('request');
|
|
1628
1262
|
const currentPath = path.pathname + path.search;
|
|
1629
1263
|
path.searchParams.set('format', 'workspace');
|
|
1630
|
-
// The legacy list pane (every task or build as links) duplicates the
|
|
1631
|
-
// Crew panel and Tasks page; inside the workspace the page stands alone.
|
|
1632
1264
|
const pageHtml = htmlString(s.body);
|
|
1633
1265
|
const extras = s.workspace ?? {};
|
|
1634
1266
|
const notices = [...(extras.notices ?? [])];
|
|
@@ -1642,7 +1274,6 @@ export function createDecisionServer(options) {
|
|
|
1642
1274
|
try {
|
|
1643
1275
|
const project = s.chrome.active === 'chat' ? null : s.chrome.project;
|
|
1644
1276
|
crew = extras.team?.tasks ? browserCrewFromIndex(extras.team.tasks, extras.team.selected?.id) : requestFacts.workCrew?.project === project ? browserCrewFromIndex(requestFacts.workCrew.page)
|
|
1645
|
-
// The reader's own lead's claims read "<name> is on it" here too.
|
|
1646
1277
|
: (() => {
|
|
1647
1278
|
const access = { principal: 'operator', repos: managedRepos(), includeUnplaced: false, viewer: requestFacts.actor ?? null };
|
|
1648
1279
|
return chromeRead(`crew\u0000${accessKey(access)}\u0000${project ?? ''}`, () => browserCrewOf(store, clock(), access, { evidenceRoot, project }));
|
|
@@ -1651,7 +1282,6 @@ export function createDecisionServer(options) {
|
|
|
1651
1282
|
catch {
|
|
1652
1283
|
notices.push('Crew updates are unavailable. Open Tasks to inspect saved work.');
|
|
1653
1284
|
}
|
|
1654
|
-
// A running row says what its agent did last, and when (the task page's own line).
|
|
1655
1285
|
try {
|
|
1656
1286
|
const now = clock(), live = new Map();
|
|
1657
1287
|
if (crew.crew.length > 0)
|
|
@@ -1663,14 +1293,9 @@ export function createDecisionServer(options) {
|
|
|
1663
1293
|
if (live.size > 0)
|
|
1664
1294
|
crew = { ...crew, crew: crew.crew.map(item => { const activity = live.get(item.id); return activity === undefined ? item : { ...item, activity }; }) };
|
|
1665
1295
|
}
|
|
1666
|
-
catch {
|
|
1667
|
-
// "Wake me only for these": the navigation carries the sidebar's own
|
|
1668
|
-
// Tasks count (chromeFor) and links to the project view it covers, so
|
|
1669
|
-
// it matches that page's Needs you tab on every screen.
|
|
1296
|
+
catch { }
|
|
1670
1297
|
const needsYou = s.chrome.inboxCount;
|
|
1671
1298
|
const tasksProject = s.chrome.inboxProject === undefined ? s.chrome.project : s.chrome.inboxProject;
|
|
1672
|
-
// The person's own project and task conversations (v77), for the
|
|
1673
|
-
// sidebar's chat list; a thread whose project is out of view is left out.
|
|
1674
1299
|
let chats = [];
|
|
1675
1300
|
try {
|
|
1676
1301
|
const actor = requestFacts.actor ?? '';
|
|
@@ -1693,31 +1318,18 @@ export function createDecisionServer(options) {
|
|
|
1693
1318
|
}
|
|
1694
1319
|
const conversation = extras.conversation ?? null;
|
|
1695
1320
|
const request = requestFacts.workspaceRequest;
|
|
1696
|
-
// React owns the conversation and its refresh/draft lifecycle. Native
|
|
1697
|
-
// guarded forms keep their current behavior after React inserts them.
|
|
1698
|
-
// A page with its own view keeps its script; the chat page runs the result script.
|
|
1699
|
-
// The exact page script the document would run: the JSON arm and the document arm read this one value.
|
|
1700
1321
|
const ownScript = conversation === null || extras.view;
|
|
1701
1322
|
const pageScript = ownScript ? (s.functional?.script ?? '') : RESULT_REVIEW_SCRIPT;
|
|
1702
1323
|
const routeInPlace = inPlaceRoute(requestFacts.routeId, path);
|
|
1703
|
-
// The app runs the page's behaviour itself (docs/plans/task-page-in-app.md §2) only when all of these hold: the
|
|
1704
|
-
// app covers the WHOLE script, no password field (a password page keeps its string path), an in-place route, and a
|
|
1705
|
-
// reader that can run it: a document load (its bundle is this server's, served no-store) or a workspace read that
|
|
1706
|
-
// says so. Anything else is the page exactly as before: the string, no work, a document.
|
|
1707
1324
|
const covered = ownScript ? s.functional?.app : undefined;
|
|
1708
1325
|
const work = pageScript !== '' && covered !== undefined && covered.length > 0 && !sensitive && routeInPlace
|
|
1709
1326
|
&& (!requestFacts.workspaceRead || requestFacts.appWork === true) ? covered : null;
|
|
1710
1327
|
const functional = work === null ? pageScript : '';
|
|
1711
|
-
// May replace another page without a document load (live-pages-and-home.md A1.1): an allowlisted route, no password
|
|
1712
|
-
// field, no page script (a page script runs once per document, so its page always loads as one).
|
|
1713
1328
|
const inPlace = routeInPlace && !sensitive && functional === '';
|
|
1714
1329
|
const workspace = {
|
|
1715
1330
|
version: 1, path: currentPath, title: s.title, user: requestFacts.actor ?? '', csrf: requestFacts.csrf, sensitive, inPlace,
|
|
1716
1331
|
...(work === null ? {} : { work }),
|
|
1717
|
-
// Said on the document that ships it: this document's page script listens for as long as the document lives.
|
|
1718
1332
|
...(functional !== '' && !requestFacts.workspaceRead ? { scripted: true } : {}),
|
|
1719
|
-
// The project picker names the open project; the settings frame carries its breadcrumb.
|
|
1720
|
-
// Only a project this person may see now: never the raw saved path (settings-kit.ts openProjectFor).
|
|
1721
1333
|
openProject: openProjectFor(requestFacts.openProject ?? null, s.chrome.project, s.chrome.projects ?? []),
|
|
1722
1334
|
...(s.chrome.crumbs === undefined ? {} : { crumbs: s.chrome.crumbs }),
|
|
1723
1335
|
...(requestFacts.passwordless === true ? { passwordless: true } : {}),
|
|
@@ -1726,7 +1338,6 @@ export function createDecisionServer(options) {
|
|
|
1726
1338
|
receipt: conversation !== null && request && REQUEST_TOKEN.test(request)
|
|
1727
1339
|
? { request, received: store.leadRequestReceived(conversation.sessionId, request) } : null,
|
|
1728
1340
|
projects: browserProjectsOf(s.chrome.projects ?? []), ...crew,
|
|
1729
|
-
// The sidebar's project states: never on a sensitive page (no rail, no summary stream there).
|
|
1730
1341
|
...(() => { if (sensitive)
|
|
1731
1342
|
return {}; try {
|
|
1732
1343
|
return { projectStates: projectSummary() };
|
|
@@ -1734,7 +1345,6 @@ export function createDecisionServer(options) {
|
|
|
1734
1345
|
catch {
|
|
1735
1346
|
return {};
|
|
1736
1347
|
} })(),
|
|
1737
|
-
// Cockpit B2: the remembered password's chip, only where it could be used (a direct local request).
|
|
1738
1348
|
...(() => {
|
|
1739
1349
|
const facts = freshFacts.getStore();
|
|
1740
1350
|
if (sensitive || facts == null || !facts.local || !facts.live())
|
|
@@ -1745,10 +1355,9 @@ export function createDecisionServer(options) {
|
|
|
1745
1355
|
const left = FRESH_WINDOW_MS - (Date.now() - at);
|
|
1746
1356
|
return left <= 0 ? {} : { fresh: { minutes: Math.max(1, Math.ceil(left / 60_000)), forget: '/session/forget-password' } };
|
|
1747
1357
|
})(),
|
|
1748
|
-
// The usage chip: the Limits view's own audience (an operator on a browser session), never a sensitive page.
|
|
1749
1358
|
...(() => {
|
|
1750
1359
|
const actor = requestFacts.actor;
|
|
1751
|
-
if (sensitive || !actor || requestFacts.csrf === '' || !store.isInstanceOperator(actor))
|
|
1360
|
+
if (sensitive || !actor || requestFacts.csrf === '' || requestFacts.advanced === false || !store.isInstanceOperator(actor))
|
|
1752
1361
|
return {};
|
|
1753
1362
|
try {
|
|
1754
1363
|
const usage = usageChipOf(store.providerLimits(), clock());
|
|
@@ -1762,15 +1371,12 @@ export function createDecisionServer(options) {
|
|
|
1762
1371
|
catchUpHtml: extras.catchUpHtml === undefined ? '' : htmlString(extras.catchUpHtml), controlsHtml: extras.controlsHtml === undefined ? '' : htmlString(extras.controlsHtml), notices, view: extras.view ?? null,
|
|
1763
1372
|
...(s.chrome.demo ? { demo: { text: DEMO_BANNER, short: DEMO_BANNER_SHORT } } : {}),
|
|
1764
1373
|
pageHtml: extras.pageHtml === undefined ? (conversation === null ? pageHtml : null) : extras.pageHtml === null ? null : htmlString(extras.pageHtml),
|
|
1765
|
-
navigation: browserNavigationOf(currentPath, s.chrome.project, needsYou, tasksProject, s.chrome.inboxLabel),
|
|
1766
|
-
|
|
1767
|
-
// view (or every project), so the rail, the phone header and Home all read the same number.
|
|
1374
|
+
navigation: browserNavigationOf(currentPath, s.chrome.project, needsYou, tasksProject, s.chrome.inboxLabel, requestFacts.advanced !== false),
|
|
1375
|
+
...(requestFacts.advanced === false ? { advanced: false } : {}),
|
|
1768
1376
|
needsYou: { count: needsYou, saturated: s.chrome.inboxSaturated === true, scope: tasksProject ?? null,
|
|
1769
1377
|
label: s.chrome.inboxLabel ?? `${needsYou} ${needsYou === 1 ? 'needs' : 'need'} you`,
|
|
1770
|
-
// Every project, said by name (all=1), so a session's own open project never narrows the list the count opens.
|
|
1771
1378
|
href: tasksProject === null ? '/tasks?scope=all&view=needs-you' : `/tasks?project=${encodeURIComponent(tasksProject)}&view=needs-you` },
|
|
1772
1379
|
chats,
|
|
1773
|
-
// The same count per project (the rail's project rows), read from the same work index totals.
|
|
1774
1380
|
...(() => { if (sensitive)
|
|
1775
1381
|
return {}; try {
|
|
1776
1382
|
return { needsYouByProject: projectCounts(clock()).map(one => ({ path: one.repo, count: one.totals['needs-you'] })) };
|
|
@@ -1784,7 +1390,6 @@ export function createDecisionServer(options) {
|
|
|
1784
1390
|
...(extras.firstRun === undefined ? {} : { firstRun: extras.firstRun }),
|
|
1785
1391
|
...(extras.phone === undefined ? {} : { phone: extras.phone }),
|
|
1786
1392
|
...(extras.home == null ? {} : { home: extras.home }),
|
|
1787
|
-
// Easy-start C2: this tab's key is from an earlier start (or it has none): one way to reconnect.
|
|
1788
1393
|
...(requestFacts.reconnect == null ? {} : { reconnect: requestFacts.reconnect }),
|
|
1789
1394
|
};
|
|
1790
1395
|
if (requestFacts.workspaceRead) {
|
|
@@ -1794,9 +1399,6 @@ export function createDecisionServer(options) {
|
|
|
1794
1399
|
response.setHeader('ETag', validator.etag);
|
|
1795
1400
|
}
|
|
1796
1401
|
const body = JSON.stringify(workspace);
|
|
1797
|
-
// Every other page's re-read after a live `change` (chat keeps its own validator, and its receipt, task and
|
|
1798
|
-
// result reads none): when what it renders now is exactly what the page holds, it hears 304 and keeps its view
|
|
1799
|
-
// (no transfer, no re-render).
|
|
1800
1402
|
if (status === 200 && validator === undefined && path.pathname !== '/chat') {
|
|
1801
1403
|
const etag = '"w' + createHash('sha256').update(body).digest('base64url') + '"';
|
|
1802
1404
|
response.setHeader('ETag', etag);
|
|
@@ -1807,14 +1409,8 @@ export function createDecisionServer(options) {
|
|
|
1807
1409
|
}
|
|
1808
1410
|
const nonce = randomBytes(16).toString('base64');
|
|
1809
1411
|
const document = shell(s.title, s.body, { chrome: s.chrome, sensitive });
|
|
1810
|
-
// The keys and their list (keymap.ts) work here as on every chromed page; the list sits beside the app React owns.
|
|
1811
|
-
// A sensitive page keeps to its own script.
|
|
1812
1412
|
return page(response, status, browserWorkspaceDocument(document, workspace, nonce, functional + MOBILE_VIEWPORT_SCRIPT + keyFill + (sensitive ? '' : chromeScript()), sensitive ? html `` : KBD_HELP), nonce, true);
|
|
1813
1413
|
}
|
|
1814
|
-
// A one-time secret on screen (a token, an invite link, a pairing code): the
|
|
1815
|
-
// page carries no script of any kind, so it leaves the workspace for a
|
|
1816
|
-
// focused page in the same look: the brand, the one card, and the way back.
|
|
1817
|
-
// Easy-start C2: but for the key fill when it has a form that posts (the fill reads nothing on the page).
|
|
1818
1414
|
if (s.forceSensitive === true) {
|
|
1819
1415
|
if (keyFill === "" || !/<form\b[^>]*method="post"/i.test(htmlString(s.body)))
|
|
1820
1416
|
return page(response, status, focusDocument(s.title, s.body));
|
|
@@ -1823,10 +1419,7 @@ export function createDecisionServer(options) {
|
|
|
1823
1419
|
}
|
|
1824
1420
|
const chromeLayer = !sensitive && s.chrome !== undefined;
|
|
1825
1421
|
const functional = s.functional?.script ?? "";
|
|
1826
|
-
// Sensitive pages strip the palette and keys but keep the sidebar toggle.
|
|
1827
1422
|
const sensitiveChrome = sensitive && s.chrome !== undefined ? sidebarScript() : "";
|
|
1828
|
-
// Kit markup the workspace bundle would have wired (a composer, an overlay, a switch, an idea) gets the kit's own small
|
|
1829
|
-
// behaviour here (kit-standalone.ts); never on a sensitive page, which carries no chrome additions.
|
|
1830
1423
|
const kitBehavior = chromeLayer && KIT_BEHAVIOR_MARKUP.test(htmlString(s.body)) ? KIT_STANDALONE_SCRIPT : "";
|
|
1831
1424
|
const script = functional + (chromeLayer ? chromeScript() + WORKSPACE_MOTION_SCRIPT + kitBehavior : sensitiveChrome) + keyFill;
|
|
1832
1425
|
const nonce = script === "" ? undefined : randomBytes(16).toString("base64");
|
|
@@ -1840,23 +1433,14 @@ export function createDecisionServer(options) {
|
|
|
1840
1433
|
...(s.refreshSeconds === undefined ? {} : { refreshSeconds: s.refreshSeconds }),
|
|
1841
1434
|
...(nonce === undefined ? {} : { live: { nonce, script, fallbackRefresh: s.functional?.fetches === true } }),
|
|
1842
1435
|
});
|
|
1843
|
-
// Pages that ship the chrome layer keep connect-src (v28 granted it for
|
|
1844
|
-
// the since-removed watched-session beat), beside pages whose own
|
|
1845
|
-
// functional script polls.
|
|
1846
1436
|
return page(response, status, document, nonce, s.functional?.fetches === true || chromeLayer || sensitiveChrome !== "");
|
|
1847
1437
|
}
|
|
1848
|
-
/** The needs-you count every surface wears, read from this request's own
|
|
1849
|
-
* Work counts (one read per request, kept only while the workspace revision
|
|
1850
|
-
* it was read at stands), so a live page's badge and its Needs you tab
|
|
1851
|
-
* always agree. */
|
|
1852
1438
|
function needsYouBadge(project) {
|
|
1853
1439
|
return needsYouCount(project);
|
|
1854
1440
|
}
|
|
1855
1441
|
const bustBadge = () => {
|
|
1856
1442
|
paletteCache.clear();
|
|
1857
1443
|
};
|
|
1858
|
-
/** Enrolled projects first (most recently opened), then the repos this server was told to serve that nobody has
|
|
1859
|
-
* opened yet — the switcher lists every project it is allowed to show, each exactly once. */
|
|
1860
1444
|
function sidebarProjects() {
|
|
1861
1445
|
const seen = new Set();
|
|
1862
1446
|
const rows = [];
|
|
@@ -1871,33 +1455,21 @@ export function createDecisionServer(options) {
|
|
|
1871
1455
|
}
|
|
1872
1456
|
return rows;
|
|
1873
1457
|
}
|
|
1874
|
-
/** The sidebar's projects with their states (agent-state.ts), for the request's own reader: the page's first read
|
|
1875
|
-
* and the summary room's snapshots are this one function, so the two never disagree. Never marks anything seen.
|
|
1876
|
-
* Work with no project yet is its own entry when this reader may see it and something counts there. */
|
|
1877
1458
|
function projectSummary() {
|
|
1878
1459
|
const projects = sidebarProjects();
|
|
1879
1460
|
const actor = requestContext.getStore()?.actor ?? '';
|
|
1880
1461
|
const access = workAccess();
|
|
1881
1462
|
return chromeRead(summaryKey(actor, access, projects), () => projectSummaryOf(store, clock(), access, actor, projects, evidenceRoot));
|
|
1882
1463
|
}
|
|
1883
|
-
/** What one account may see now, as the summary room keys it: a narrowed ceiling or grant is a different key, so a
|
|
1884
|
-
* snapshot read for the wider scope never reaches it. Null: no such account. */
|
|
1885
1464
|
const projectScopeFor = (account) => store.accountOf(account) === null ? null : requestContext.run({ csrf: '', returnTo: '/', actor: account }, () => {
|
|
1886
|
-
// Canonical: what may be seen, never the order it was last opened in.
|
|
1887
1465
|
const access = workAccess();
|
|
1888
1466
|
return JSON.stringify({ projects: sidebarProjects().map(one => one.path).sort(), access: { ...access, repos: access.repos === null ? null : [...access.repos].sort() } });
|
|
1889
1467
|
});
|
|
1890
|
-
/** One account's summary snapshot, read as that account for this exact scope (the summary room's fingerprint): null
|
|
1891
|
-
* when the account is gone or its scope moved. */
|
|
1892
1468
|
const projectSummaryFor = (account, scope) => projectScopeFor(account) !== scope ? null : requestContext.run({ csrf: '', returnTo: '/', actor: account }, () => JSON.stringify(projectSummary()));
|
|
1893
|
-
/** The sidebar's facts for this request. */
|
|
1894
1469
|
function chromeFor(project, active, listPane, scope) {
|
|
1895
1470
|
if (restricted() && !visible(project))
|
|
1896
1471
|
project = null;
|
|
1897
1472
|
const actor = requestContext.getStore()?.actor;
|
|
1898
|
-
// One Tasks count per request: Needs you in the request's project view
|
|
1899
|
-
// (the open project, else every admitted project), never the page's own
|
|
1900
|
-
// project — a flow or task in another project shows the same number.
|
|
1901
1473
|
const lens = requestContext.getStore()?.lens;
|
|
1902
1474
|
const inboxProject = lens !== undefined && (!restricted() || visible(lens)) ? lens : project;
|
|
1903
1475
|
const badge = needsYouBadge(inboxProject);
|
|
@@ -1909,7 +1481,6 @@ export function createDecisionServer(options) {
|
|
|
1909
1481
|
projectPeek = projectFamilyPeek(project, clock());
|
|
1910
1482
|
}
|
|
1911
1483
|
catch {
|
|
1912
|
-
// Chrome is orientation, never a reason to fail the actual screen.
|
|
1913
1484
|
projectPeek = undefined;
|
|
1914
1485
|
}
|
|
1915
1486
|
}
|
|
@@ -1920,9 +1491,6 @@ export function createDecisionServer(options) {
|
|
|
1920
1491
|
project,
|
|
1921
1492
|
projectScoped: restricted(),
|
|
1922
1493
|
...(projectPeek === undefined ? {} : { projectPeek }),
|
|
1923
|
-
// Enrolled projects first (most recently opened), then the repos this
|
|
1924
|
-
// server was told to serve that nobody has opened yet — the switcher
|
|
1925
|
-
// lists every project it is allowed to show, each exactly once.
|
|
1926
1494
|
projects: sidebarProjects(),
|
|
1927
1495
|
...(facts === undefined ? {} : { csrf: facts.csrf, returnTo: facts.returnTo }),
|
|
1928
1496
|
inboxCount: badge.count,
|
|
@@ -1934,7 +1502,6 @@ export function createDecisionServer(options) {
|
|
|
1934
1502
|
...(store.isDemo() ? { demo: true } : {}),
|
|
1935
1503
|
...(() => { const signIn = signInNotices(store); return signIn.length === 0 ? {} : { signIn }; })(),
|
|
1936
1504
|
...(() => {
|
|
1937
|
-
// Operators only (only someone at this computer can update it), and gone once this version is dismissed.
|
|
1938
1505
|
if (!facts?.csrf || !actor || !store.isInstanceOperator(actor))
|
|
1939
1506
|
return {};
|
|
1940
1507
|
const update = updateFacts();
|
|
@@ -1944,7 +1511,6 @@ export function createDecisionServer(options) {
|
|
|
1944
1511
|
})(),
|
|
1945
1512
|
...(() => {
|
|
1946
1513
|
const databaseFile = store.databaseFile();
|
|
1947
|
-
// Settings → Updates says a `toolroll update` in full; every other page (and the app's update everywhere) names it once.
|
|
1948
1514
|
if (!actor || databaseFile === null || !store.isInstanceOperator(actor))
|
|
1949
1515
|
return {};
|
|
1950
1516
|
const waiting = waitingUpdate(databaseFile, run => store.stopQuiescenceProblem(run) !== null, clock());
|
|
@@ -1959,15 +1525,11 @@ export function createDecisionServer(options) {
|
|
|
1959
1525
|
},
|
|
1960
1526
|
}),
|
|
1961
1527
|
...(!restricted() && !unscopedMode && managedRepos().length > 0 ? { chat: true } : {}),
|
|
1962
|
-
// Live terminals: offered to an installation-wide operator (the routes prove it again).
|
|
1963
1528
|
...(actor !== undefined && !store.isDemo() && store.isInstanceOperator(actor) ? { code: true } : {}),
|
|
1964
1529
|
...(listPane === undefined ? {} : { listPane }),
|
|
1965
1530
|
...(scope === undefined ? {} : { scope }),
|
|
1966
1531
|
};
|
|
1967
1532
|
}
|
|
1968
|
-
// All project counts are read together, at most once per workspace revision
|
|
1969
|
-
// for this reader's access. No task artifacts or processes are inspected to
|
|
1970
|
-
// paint a badge or a project switcher.
|
|
1971
1533
|
function projectCounts(now) {
|
|
1972
1534
|
const facts = requestContext.getStore();
|
|
1973
1535
|
if (facts?.workCounts !== undefined)
|
|
@@ -1983,16 +1545,11 @@ export function createDecisionServer(options) {
|
|
|
1983
1545
|
.reduce((sum, one) => sum + one.totals['needs-you'], 0);
|
|
1984
1546
|
return { count, saturated: false };
|
|
1985
1547
|
}
|
|
1986
|
-
/** One work index page for an already-admitted reader, through the chrome cache: a whole view the chat landing reads
|
|
1987
|
-
* on every refresh. */
|
|
1988
1548
|
function sharedIndexPage(access, options) {
|
|
1989
|
-
// Receipt reconciliation, task and result reads always read work afresh (disk state included).
|
|
1990
1549
|
if (requestContext.getStore()?.freshWork === true)
|
|
1991
1550
|
return workIndexPage(store, clock(), access, options);
|
|
1992
1551
|
return chromeRead(indexKey(access, options), () => workIndexPage(store, clock(), access, options));
|
|
1993
1552
|
}
|
|
1994
|
-
/** A chrome read for this request: what it already read (its prefetch included) stands for the whole request, else
|
|
1995
|
-
* the revision cache's value, else `compute()` now. */
|
|
1996
1553
|
function chromeRead(key, compute) {
|
|
1997
1554
|
const facts = requestContext.getStore();
|
|
1998
1555
|
const held = facts?.chromeReads?.get(key);
|
|
@@ -2003,23 +1560,16 @@ export function createDecisionServer(options) {
|
|
|
2003
1560
|
(facts.chromeReads ??= new Map()).set(key, value);
|
|
2004
1561
|
return value;
|
|
2005
1562
|
}
|
|
2006
|
-
/** The chat landing's three whole views (chat.ts chatHomeOf), as it asks for them. */
|
|
2007
1563
|
const chatHomeViews = () => ["all", "needs-you", "completed"]
|
|
2008
1564
|
.map(view => ({ view, limit: WORK_INDEX_MAX_LIMIT, ...(evidenceRoot === undefined ? {} : { root: evidenceRoot }) }));
|
|
2009
|
-
/** Pages that wear the chrome (the sidebar's states and the Tasks count). */
|
|
2010
1565
|
const CHROME_PAGES = new Set(["home", "work", "board", "agents", "agents.live", "task.page", "run.page", "chat.page", "review", "tasks", "inbox",
|
|
2011
1566
|
"next", "done", "projects.page", "flows.page", "flow.page", "settings.page", "decision.page", "menu"]);
|
|
2012
|
-
/** Before a chromed page renders: its chrome reads (and the chat landing's views) run on a read worker, so the
|
|
2013
|
-
* request thread finds them cached instead of computing them. The reader is the one this request admitted; the keys
|
|
2014
|
-
* carry its exact access (console-chrome.ts). Without a worker, or when one fails, the page computes them as before. */
|
|
2015
1567
|
async function prefetchChrome(route, url, who) {
|
|
2016
1568
|
if (reads === null || who.via !== "cookie" || !CHROME_PAGES.has(route.id))
|
|
2017
1569
|
return;
|
|
2018
1570
|
try {
|
|
2019
1571
|
const actor = requestContext.getStore()?.actor ?? "";
|
|
2020
1572
|
const access = workAccess(), projects = sidebarProjects(), now = clock();
|
|
2021
|
-
// Populate only the revision cache. Each answer must still pass its revision/expiry check when rendering:
|
|
2022
|
-
// another job can remain pending while an earlier answer's approval or Needs-you state changes.
|
|
2023
1573
|
const fill = async (key, read) => { await chromeReads.fill(key, read); };
|
|
2024
1574
|
const jobs = [
|
|
2025
1575
|
fill(countsKey(access), () => reads.workCounts(now, access)),
|
|
@@ -2029,7 +1579,6 @@ export function createDecisionServer(options) {
|
|
|
2029
1579
|
if (!["project", "room", "team"].some(name => url.searchParams.has(name)) && requestContext.getStore()?.freshWork !== true)
|
|
2030
1580
|
for (const options of chatHomeViews())
|
|
2031
1581
|
jobs.push(fill(indexKey(access, options), () => reads.workIndexPage(now, access, options)));
|
|
2032
|
-
// The conversation's briefing (chat.ts: the fleet snapshot's states), read as chat reads it.
|
|
2033
1582
|
const repos = managedRepos();
|
|
2034
1583
|
if (repos.length > 0 && requestContext.getStore()?.freshWork !== true) {
|
|
2035
1584
|
const fleet = { principal: "operator", repos, includeUnplaced: false, viewer: who.name };
|
|
@@ -2039,26 +1588,15 @@ export function createDecisionServer(options) {
|
|
|
2039
1588
|
}
|
|
2040
1589
|
await Promise.all(jobs);
|
|
2041
1590
|
}
|
|
2042
|
-
catch {
|
|
1591
|
+
catch { }
|
|
2043
1592
|
}
|
|
2044
|
-
/** A live page's own beat without a docked chat: 10 s while any admitted task is building, else 30 s. */
|
|
2045
1593
|
function liveRefreshSeconds() {
|
|
2046
1594
|
return projectCounts(clock()).some(one => one.totals.running > 0) ? 10 : 30;
|
|
2047
1595
|
}
|
|
2048
|
-
/** This exact run's review facts for the shared projection (review
|
|
2049
|
-
* fixes, finding 4): the store's bounded retry projection plus the live
|
|
2050
|
-
* reviewer's own liveness — read per run, so an older selected result
|
|
2051
|
-
* never wears a newer run's review. */
|
|
2052
1596
|
const reviewFactsFor = (runId) => reviewFactsOf(store.reviewRetryStateOf(runId), runner => {
|
|
2053
1597
|
const one = store.getRunner(runner)?.runner;
|
|
2054
1598
|
return one !== undefined && runnerAlive(one, clock());
|
|
2055
1599
|
}, buildReviewOf(store, runId)?.state === "pending");
|
|
2056
|
-
// ---- the live peek (A2; three review rounds' findings are the spec) ----
|
|
2057
|
-
//
|
|
2058
|
-
// Names and counts only, never content; nothing durable, ever. The cache
|
|
2059
|
-
// holds finished ESCAPED fragments keyed by run:base:epoch — the epoch
|
|
2060
|
-
// rotates with every lease AND release, so a stale entry's key can never
|
|
2061
|
-
// be asked for again; hits still re-prove the whole guard list.
|
|
2062
1600
|
const peekCache = new Map();
|
|
2063
1601
|
let peekCacheBytes = 0;
|
|
2064
1602
|
const peekInFlight = new Map();
|
|
@@ -2077,39 +1615,24 @@ export function createDecisionServer(options) {
|
|
|
2077
1615
|
peekCacheBytes -= entry.bytes;
|
|
2078
1616
|
}
|
|
2079
1617
|
};
|
|
2080
|
-
/** One typed sentence inside the region — plain words, no raw errors.
|
|
2081
|
-
* `final` marks conditions that cannot heal for this run (finished,
|
|
2082
|
-
* superseded, wrong machine): the region poller reads the marker and
|
|
2083
|
-
* stops, instead of refetching a dead build every beat forever. */
|
|
2084
1618
|
const peekSay = (message, final = false) => html `<p class="meta"${final ? html ` data-region-stop` : ""}>${message}</p>`;
|
|
2085
|
-
/** The sanitize pipeline (finding 30/35): normalize → mask → escape. */
|
|
2086
1619
|
const peekName = (path) => {
|
|
2087
1620
|
const normalized = path.replace(/[\u0000-\u001f\u007f]/g, "");
|
|
2088
1621
|
const masked = scanForSecrets(normalized).length > 0 ? "[redacted: a credential-shaped name]" : normalized;
|
|
2089
1622
|
return textHtml(masked);
|
|
2090
1623
|
};
|
|
2091
1624
|
async function handlePost(route, url, who, request, response, posted) {
|
|
2092
|
-
// Every POST passes the shared mutation guard. Caller, scope, project (including a limited account's posted repo)
|
|
2093
|
-
// and role were admitted by the route table.
|
|
2094
1625
|
const denied = authorizeMutation(request, who, readForm(posted, CONSOLE_FORMS.mutationGuard));
|
|
2095
1626
|
if (denied !== null)
|
|
2096
1627
|
return refuse(response, who, denied.status, denied.message, "/", denied.reconnect?.kind === "password" ? { label: "Reconnect", href: denied.reconnect.href } : undefined);
|
|
2097
|
-
// Standing can change after a token was minted: a viewer's act stays refused, cookie and bearer alike, except
|
|
2098
|
-
// the row's session-local acts.
|
|
2099
1628
|
if (who.role === "viewer" && !route.viewer)
|
|
2100
1629
|
return refuse(response, who, 403, "your login can watch, not act — ask an approver to upgrade you");
|
|
2101
1630
|
const now = clock();
|
|
2102
|
-
// Any accepted mutation may change what the inbox owes; the badge
|
|
2103
|
-
// re-counts within five seconds either way, this just makes it exact.
|
|
2104
1631
|
bustBadge();
|
|
2105
1632
|
return dispatchConsole(route, { url, who, request, response, route, now, project: projectOf(who, request) ?? null, chosenProject: projectOf(who, request) ?? null, posted });
|
|
2106
1633
|
}
|
|
2107
|
-
// Only explicitly authorized conversations receive automatic turns. The
|
|
2108
|
-
// deterministic scan is idle without new meaningful work; shutdown drains it.
|
|
2109
1634
|
let leadMaintenance = null;
|
|
2110
1635
|
let leadClosing = false;
|
|
2111
|
-
// Started in the console's folder scope (folder-gate.ts), so their own timers and the personal queue's kick (which
|
|
2112
|
-
// restores the context it was started in, never a request's) read folders as the console's work does.
|
|
2113
1636
|
server.once('listening', () => consoleFolders(options, identities, () => {
|
|
2114
1637
|
team.start();
|
|
2115
1638
|
personalQueue.start();
|
|
@@ -2117,23 +1640,17 @@ export function createDecisionServer(options) {
|
|
|
2117
1640
|
run: () => runLeadFollowPass({ store, repos: managedRepos, evidenceRoot, clock,
|
|
2118
1641
|
provider: () => { const enabled = chatEnablement(); return enabled.ok ? { config: enabled.config, key: enabled.key } : null; },
|
|
2119
1642
|
fetcher: chatFetcher, ...(options.subscriptionChatRunner ? { subscriptionRunner: options.subscriptionChatRunner } : {}) }),
|
|
2120
|
-
// Pending delivery is durable and is read again on the next pass; a failure is said where follow status is read.
|
|
2121
1643
|
onError: error => recordLeadFollowFailure(store, error, clock()),
|
|
2122
1644
|
});
|
|
2123
1645
|
}));
|
|
2124
|
-
// Background checks (docs/plans/get-side-effects.md): what pages show about this computer's agent sign-ins and the
|
|
2125
|
-
// services Toolroll uses is asked here, on a timer, and a page reads the last answer. A page visit never starts a
|
|
2126
|
-
// process or a network call, and never acts on what a check finds: lifting a sign-in pause and the lead-by-default
|
|
2127
|
-
// rule run from this pass (or a person's Check now), not from a GET.
|
|
2128
1646
|
let backgroundChecks = null;
|
|
2129
1647
|
let agentsCheckedAt = 0;
|
|
2130
1648
|
if (options.backgroundChecks === true)
|
|
2131
1649
|
server.once('listening', () => {
|
|
2132
|
-
// This Toolroll's folder for secrets, checked once now, so a page can read which are set without preparing it.
|
|
2133
1650
|
try {
|
|
2134
1651
|
secretFolder();
|
|
2135
1652
|
}
|
|
2136
|
-
catch {
|
|
1653
|
+
catch { }
|
|
2137
1654
|
backgroundChecks = startMaintenance({ intervalMs: options.backgroundChecksMs ?? BACKGROUND_CHECKS_MS, shouldStop: () => leadClosing,
|
|
2138
1655
|
run: () => consoleFolders(options, identities, async () => {
|
|
2139
1656
|
const now = Date.now();
|
|
@@ -2141,11 +1658,9 @@ export function createDecisionServer(options) {
|
|
|
2141
1658
|
if (now - agentsCheckedAt >= (options.backgroundChecksMs ?? LOCAL_AGENTS_EVERY_MS)) {
|
|
2142
1659
|
agentsCheckedAt = now;
|
|
2143
1660
|
waits.push(checkLocalAgents());
|
|
2144
|
-
// The other agents Settings lists: their last answer is what the page shows.
|
|
2145
1661
|
for (const provider of PROVIDER_IDS.filter(isKeyedProvider).filter(one => one !== "claude" && one !== "codex"))
|
|
2146
1662
|
waits.push(connectionCheck(provider).catch(() => undefined));
|
|
2147
1663
|
}
|
|
2148
|
-
// Project identities, resolved off the thread: what pages asked about, and answers gone stale.
|
|
2149
1664
|
waits.push(identities.refresh([...configuredPaths, ...exactRepos(), ...(options.currentRepos?.() ?? []), ...store.listProjects().map(one => one.path), ...store.knownRepos()]));
|
|
2150
1665
|
integrations.refreshIfDue();
|
|
2151
1666
|
const sso = ssoSettings();
|
|
@@ -2154,28 +1669,22 @@ export function createDecisionServer(options) {
|
|
|
2154
1669
|
if (chatKeyFor("openrouter-api") !== null)
|
|
2155
1670
|
waits.push(chatCatalog());
|
|
2156
1671
|
const openrouter = readProviderKey("openrouter", providerHome);
|
|
2157
|
-
// The cache answers until its list is due again (ten minutes, or 30 s after a failure), then fetches.
|
|
2158
1672
|
if (openrouter !== null)
|
|
2159
1673
|
waits.push(modelCatalog(openrouter));
|
|
2160
|
-
// What used to be closed by whichever page read it first: an operating mode or a flow's "runs on its own"
|
|
2161
|
-
// grant past its expiry, a stalled update, old coordinator proposals. (Lead turns past their deadline are the
|
|
2162
|
-
// follow pass's, which settles them even while an update drains.)
|
|
2163
1674
|
const at = clock();
|
|
2164
1675
|
store.closeExpiredModes(at);
|
|
2165
1676
|
closeExpiredUnattendedGrants(store, at);
|
|
2166
1677
|
store.sweepCoordinatorProposals(at);
|
|
2167
|
-
// The demo's scripted story, if a beat timer missed (its pages only read it).
|
|
2168
1678
|
try {
|
|
2169
1679
|
options.demoLead?.advance(at);
|
|
2170
1680
|
}
|
|
2171
|
-
catch {
|
|
1681
|
+
catch { }
|
|
2172
1682
|
const databaseFile = store.databaseFile();
|
|
2173
1683
|
if (databaseFile !== null && !updateChecksOff(process.env, options.configDir ?? dirname(databaseFile)).off) {
|
|
2174
1684
|
const last = lastChecks.known("release");
|
|
2175
1685
|
if (lastChecks.due("release", last !== null && "problem" in last.value ? 60_000 : 15 * 60_000))
|
|
2176
1686
|
waits.push(checkRelease());
|
|
2177
1687
|
}
|
|
2178
|
-
// Chat's first tasks (issues and TODOs) while the first run is open and nothing is filed yet.
|
|
2179
1688
|
if (firstRunStepsNow(clock()) !== null && !store.hasAnyWork()) {
|
|
2180
1689
|
for (const repo of managedRepos()) {
|
|
2181
1690
|
const entry = firstTasks.get(repo);
|
|
@@ -2183,18 +1692,11 @@ export function createDecisionServer(options) {
|
|
|
2183
1692
|
continue;
|
|
2184
1693
|
const reading = { until: Date.now() + 10 * 60_000, found: entry?.found ?? null, reading: true };
|
|
2185
1694
|
firstTasks.set(repo, reading);
|
|
2186
|
-
// A test's runner reads in-process; otherwise in a process of its own (learning-look.ts), so the hardened
|
|
2187
|
-
// git's synchronous reads of the project's folder never hold the console's thread.
|
|
2188
1695
|
waits.push((options.firstTaskRunner !== undefined ? findFirstTasks(repo, options.firstTaskRunner) : firstTasksOffThread(repo)).then(found => { reading.found = found; }, () => { }).finally(() => { reading.reading = false; }));
|
|
2189
1696
|
}
|
|
2190
1697
|
}
|
|
2191
|
-
// Learning recovered from reviewed runs (and a project's saved rows carried to its current identity), which
|
|
2192
|
-
// Settings → Learning and Knowledge used to do as they opened.
|
|
2193
1698
|
if (lastChecks.due("learning", 10 * 60_000)) {
|
|
2194
1699
|
waits.push(lastChecks.run("learning", async () => {
|
|
2195
|
-
// Its reads of each project's Git folder are synchronous, so with a database file they run in a process of
|
|
2196
|
-
// their own (learning-look.ts): a folder that doesn't answer costs its own recovery, never the console. An
|
|
2197
|
-
// in-memory database (a test) can't be shared, so it is read here.
|
|
2198
1700
|
if (databaseFile !== null) {
|
|
2199
1701
|
await recoverLearningOffThread({ databaseFile, evidenceRoot, repos: managedRepos() }, options.learningRunner === undefined ? {} : { runner: options.learningRunner });
|
|
2200
1702
|
return;
|
|
@@ -2203,17 +1705,15 @@ export function createDecisionServer(options) {
|
|
|
2203
1705
|
try {
|
|
2204
1706
|
acceptedIdentities(store, repo);
|
|
2205
1707
|
}
|
|
2206
|
-
catch {
|
|
1708
|
+
catch { }
|
|
2207
1709
|
try {
|
|
2208
1710
|
recoverLearning(store, evidenceRoot, repo);
|
|
2209
1711
|
}
|
|
2210
|
-
catch {
|
|
1712
|
+
catch { }
|
|
2211
1713
|
}
|
|
2212
1714
|
}));
|
|
2213
1715
|
}
|
|
2214
|
-
// What Codex has configured, per project, for Settings → Tools to offer.
|
|
2215
1716
|
for (const repo of managedRepos()) {
|
|
2216
|
-
// The project's own .mcp.json, read off the console's thread (folder-look.ts) for the Tools page and the lead.
|
|
2217
1717
|
if (options.identities !== undefined && lastChecks.due(`project-mcp:${repo}`, 10 * 60_000)) {
|
|
2218
1718
|
waits.push(lastChecks.run(`project-mcp:${repo}`, async () => { const looked = await lookProjectMcp(repo); if (looked.ok)
|
|
2219
1719
|
savedProjectMcp.set(repo, looked.value); return looked.ok; }));
|
|
@@ -2224,25 +1724,17 @@ export function createDecisionServer(options) {
|
|
|
2224
1724
|
if (databaseFile !== null && lastChecks.due("storage", 30 * 60_000)) {
|
|
2225
1725
|
waits.push(lastChecks.run("storage", () => checkoutPlan(store, storagePool(databaseFile), clock(), { manual: true })));
|
|
2226
1726
|
}
|
|
2227
|
-
// The same reading the chrome does, outside a page visit, so it releases a stalled `toolroll update` and a stalled
|
|
2228
|
-
// desktop update in every folder the chrome looks in.
|
|
2229
1727
|
if (databaseFile !== null) {
|
|
2230
1728
|
try {
|
|
2231
1729
|
waitingUpdate(databaseFile, run => store.stopQuiescenceProblem(run) !== null, at);
|
|
2232
1730
|
}
|
|
2233
|
-
catch {
|
|
1731
|
+
catch { }
|
|
2234
1732
|
}
|
|
2235
1733
|
await Promise.all(waits);
|
|
2236
1734
|
}),
|
|
2237
1735
|
onError: () => { }, });
|
|
2238
1736
|
void backgroundChecks.runNow();
|
|
2239
1737
|
});
|
|
2240
|
-
// Keep native process custody until shutdown has verified agent/tool exit.
|
|
2241
|
-
// Coding custody does not depend on subagents or the lead's follow pass, so
|
|
2242
|
-
// it closes at once and never waits behind a model turn: a stop must release
|
|
2243
|
-
// the owner record well inside the service's exit window (Oct 2: deploys
|
|
2244
|
-
// over 0.9.11 found it still held by a killed process).
|
|
2245
|
-
/** Set once the terminal handlers exist (below): drops every socket and ends every program. */
|
|
2246
1738
|
const terminalClosing = {};
|
|
2247
1739
|
let codingClosing = null;
|
|
2248
1740
|
const closeCoding = () => {
|
|
@@ -2259,14 +1751,13 @@ export function createDecisionServer(options) {
|
|
|
2259
1751
|
try {
|
|
2260
1752
|
requestBudget.flush();
|
|
2261
1753
|
}
|
|
2262
|
-
catch {
|
|
1754
|
+
catch { }
|
|
2263
1755
|
flowRooms.close();
|
|
2264
1756
|
taskRooms.close();
|
|
2265
1757
|
liveHandlers.close();
|
|
2266
1758
|
detachReads();
|
|
2267
1759
|
liveFollower.close();
|
|
2268
1760
|
void Promise.all([closeCoding(), terminalClosing.close?.().then(problem => { terminalClosing.problem = problem; }), bounded(team.close()), bounded(personalQueue.close()), bounded(leadMaintenance?.stop()), bounded(backgroundChecks?.stop()), bounded(reads?.close())])
|
|
2269
|
-
// The server always closes; a terminal whose processes couldn't be proved stopped is the close's error.
|
|
2270
1761
|
.then(() => closeServer(error => callback?.(error ?? terminalClosing.problem ?? undefined))).catch(error => {
|
|
2271
1762
|
if (callback)
|
|
2272
1763
|
callback(error instanceof Error ? error : Error('Coding session shutdown failed.'));
|
|
@@ -2464,7 +1955,6 @@ export function createDecisionServer(options) {
|
|
|
2464
1955
|
};
|
|
2465
1956
|
const liveHandlers = createLiveHandlers(handlerRuntime, { bus: liveBus, workspaceRevision, chatProjectOf: chatHandlers.chatProjectOf, projectSummaryFor, projectScopeFor });
|
|
2466
1957
|
liveTurnStarted = liveHandlers.turnStarted;
|
|
2467
|
-
// The one upgrade this server takes is a terminal's socket (terminals.ts listens); anything else is dropped.
|
|
2468
1958
|
const terminalHandlers = createTerminalHandlers(handlerRuntime, { ...terminals, bus: liveBus, allowedHost, publicOrigin, forwardedSourceOf, server });
|
|
2469
1959
|
terminalClosing.close = terminalHandlers.close;
|
|
2470
1960
|
const remoteHandlers = createRemoteHandlers(remoteRuntime);
|
|
@@ -2474,7 +1964,6 @@ export function createDecisionServer(options) {
|
|
|
2474
1964
|
...remoteHandlers.registrations, ...liveHandlers.registrations, ...terminalHandlers.registrations, ...createSweepHandlers(handlerRuntime).registrations,
|
|
2475
1965
|
...createWelcomeHandlers(handlerRuntime).registrations,
|
|
2476
1966
|
]);
|
|
2477
|
-
/** The row's role, after admission and before its one handler. */
|
|
2478
1967
|
function dispatchConsole(route, ctx) {
|
|
2479
1968
|
const { who, response } = ctx;
|
|
2480
1969
|
const held = route.role === "any" || ((!route.roleBrowser || who.via === "cookie") &&
|
|
@@ -2497,8 +1986,6 @@ export function createDecisionServer(options) {
|
|
|
2497
1986
|
}
|
|
2498
1987
|
return withEdgePolicy(route, () => registry.edge(route, { ...ctx, route }));
|
|
2499
1988
|
}
|
|
2500
|
-
/** Easy-start C1: the local owner a browser session acts as on an allowed row, bound to its session's saved row and
|
|
2501
|
-
* the generations it was made under; null when it no longer stands (refused like any other row). */
|
|
2502
1989
|
function localPrincipalOf(who, route) {
|
|
2503
1990
|
const sessionHash = sessions.hashOf(who.session);
|
|
2504
1991
|
if (route.localAct === null || who.session.localGeneration === null || sessionHash === null)
|
|
@@ -2507,17 +1994,13 @@ export function createDecisionServer(options) {
|
|
|
2507
1994
|
transport: "browser", act: route.localAct, sessionHash, request: { ended: false } };
|
|
2508
1995
|
return localOwnerStandsNow(store, principal) ? principal : null;
|
|
2509
1996
|
}
|
|
2510
|
-
/** What a local owner hears on a row not marked for it: set a first password, or sign in with the one set. */
|
|
2511
1997
|
function refuseLocalOwner(response, who, method, url, accept) {
|
|
2512
|
-
// The page it was refused on, built here from the request (never from a header): a form's nearest page above it.
|
|
2513
1998
|
const words = localOwnerRefusal(store.accountOf(who.name)?.passwordSet === true, refusalNext(method, url));
|
|
2514
|
-
// Which refusal this was, for the shell (it offers the same way on) and the route inventory's rule table.
|
|
2515
1999
|
response.setHeader("x-toolroll-refused", "local-owner");
|
|
2516
2000
|
if (String(accept ?? "").includes("application/json"))
|
|
2517
2001
|
return respond(response, 403, "application/json", JSON.stringify({ ok: false, said: words.message, href: words.href }));
|
|
2518
2002
|
return refuse(response, who, 403, words.message, words.href, { label: words.action, href: words.href });
|
|
2519
2003
|
}
|
|
2520
|
-
// Defined last, so the reviewed functions above keep their places (password-freshness.test.ts).
|
|
2521
2004
|
function holdSignInLink(link) {
|
|
2522
2005
|
for (const [key, one] of signInLinks)
|
|
2523
2006
|
if (one.expires < Date.now())
|
|
@@ -2528,8 +2011,6 @@ export function createDecisionServer(options) {
|
|
|
2528
2011
|
signInLinks.set(linkKey(code), link);
|
|
2529
2012
|
return `${SIGN_IN_LINK_PATH}${code}`;
|
|
2530
2013
|
}
|
|
2531
|
-
/** Easy-start C4: a local owner's one-time link. It names no account: local mode's own owner, read now, while local
|
|
2532
|
-
* mode is on and the owner is active. Redemption reads local mode again and issues only a local-owner session. */
|
|
2533
2014
|
function mintLocalLink() {
|
|
2534
2015
|
const binding = localOwnerBinding(store);
|
|
2535
2016
|
if (binding === null)
|
|
@@ -2546,12 +2027,6 @@ export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
|
2546
2027
|
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches } from "./server/render-results.js";
|
|
2547
2028
|
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords } from "./server/render-tasks.js";
|
|
2548
2029
|
export { SIGN_IN_LINK_MS, SIGN_IN_LINK_PATH } from "./server/session.js";
|
|
2549
|
-
/**
|
|
2550
|
-
* The console's configured repos and roots. Without identities (embedders and tests) they resolve once, synchronously,
|
|
2551
|
-
* as before. With them, the console resolves them in the background after it listens (operate.ts startConsole), so
|
|
2552
|
-
* each is read from the last answer: a configured path counts by its real path from the moment its folder answers,
|
|
2553
|
-
* and until then only by its spelling, which the strict `canon` never matches for an unresolved row.
|
|
2554
|
-
*/
|
|
2555
2030
|
function startupCeiling(repos, roots, identities, canon) {
|
|
2556
2031
|
const configured = repos.length > 0 || roots.length > 0;
|
|
2557
2032
|
const configuredPaths = [...repos, ...roots];
|
|
@@ -2565,8 +2040,6 @@ function startupCeiling(repos, roots, identities, canon) {
|
|
|
2565
2040
|
configuredPaths,
|
|
2566
2041
|
};
|
|
2567
2042
|
}
|
|
2568
|
-
// Only resolved entries authorize: an unresolved configured path is in no list, so it matches nothing (not even its
|
|
2569
|
-
// own spelling) and is no session's default until its folder answers.
|
|
2570
2043
|
const resolved = (paths) => [...new Set(paths.flatMap(path => { const real = identities.known(path); return typeof real === "string" ? [real] : []; }))];
|
|
2571
2044
|
const ceiling = {
|
|
2572
2045
|
get repos() { return resolved(repos); },
|
|
@@ -2581,14 +2054,7 @@ function startupCeiling(repos, roots, identities, canon) {
|
|
|
2581
2054
|
configuredPaths,
|
|
2582
2055
|
};
|
|
2583
2056
|
}
|
|
2584
|
-
/** Each console's folder gate (folder-gate.ts), made once for its options. */
|
|
2585
2057
|
const consoleGates = new WeakMap();
|
|
2586
|
-
/**
|
|
2587
|
-
* Runs the console's own work (a request, a background pass) in its folder scope: with identities resolved off its
|
|
2588
|
-
* thread (up and serve), it reads a person's folder synchronously only while that folder answered a look lately; its
|
|
2589
|
-
* own data (the database's folder, evidence, build checkouts) is read freely. Without identities (embedders, tests):
|
|
2590
|
-
* as before. Work that isn't the console's (a worker in the same process) never runs in it.
|
|
2591
|
-
*/
|
|
2592
2058
|
function consoleFolders(options, identities, work) {
|
|
2593
2059
|
if (options.identities === undefined)
|
|
2594
2060
|
return work();
|