tumwater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -13
- package/dist/build-info.json +2 -2
- package/dist/src/agent/agent-args.js +8 -9
- package/dist/src/agent/agent-backend.js +8 -6
- package/dist/src/agent/backend-traits.js +42 -25
- package/dist/src/agent/claude/claude-account.js +71 -204
- package/dist/src/agent/claude/claude-args.js +9 -6
- package/dist/src/agent/claude/claude-backend.js +10 -10
- package/dist/src/agent/claude/claude-env.js +1 -1
- package/dist/src/agent/claude/claude-stream.js +4 -3
- package/dist/src/agent/claude/claude-write-guard.js +49 -0
- package/dist/src/agent/claude/write-guard-hook.js +13 -0
- package/dist/src/agent/codex/codex-account.js +119 -0
- package/dist/src/agent/codex/codex-args.js +181 -0
- package/dist/src/agent/codex/codex-backend.js +279 -0
- package/dist/src/agent/codex/codex-catalog.js +97 -0
- package/dist/src/agent/codex/codex-env.js +18 -0
- package/dist/src/agent/codex/codex-hook-trust.js +246 -0
- package/dist/src/agent/codex/codex-patch-paths.js +36 -0
- package/dist/src/agent/codex/codex-rollout.js +179 -0
- package/dist/src/agent/codex/codex-stream.js +402 -0
- package/dist/src/agent/codex/codex-write-guard.js +86 -0
- package/dist/src/agent/codex/write-guard-hook.js +12 -0
- package/dist/src/agent/image-input.js +29 -24
- package/dist/src/agent/notes-shim.js +11 -12
- package/dist/src/agent/opencode/opencode-args.js +0 -1
- package/dist/src/agent/opencode/opencode-backend.js +12 -9
- package/dist/src/agent/opencode/opencode-catalog.js +55 -29
- package/dist/src/agent/opencode/opencode-config.js +19 -14
- package/dist/src/agent/opencode/opencode-env.js +0 -1
- package/dist/src/agent/opencode/opencode-session-id.js +1 -2
- package/dist/src/agent/opencode/opencode-stream.js +1 -1
- package/dist/src/agent/opencode/write-guard-plugin/index.js +48 -0
- package/dist/src/agent/role-notes-write.js +5 -6
- package/dist/src/agent/run-agent.js +465 -448
- package/dist/src/agent/run-settle.js +214 -0
- package/dist/src/agent/session-ledger.js +86 -16
- package/dist/src/agent/subscription-account.js +220 -0
- package/dist/src/agent/write-guard.js +148 -0
- package/dist/src/backlog/backlog-archive.js +246 -55
- package/dist/src/backlog/backlog-cli-view.js +280 -0
- package/dist/src/backlog/backlog-cli.js +85 -274
- package/dist/src/backlog/backlog-commit.js +4 -5
- package/dist/src/backlog/backlog-eligibility.js +175 -242
- package/dist/src/backlog/backlog-index.js +149 -0
- package/dist/src/backlog/backlog-md.js +54 -6
- package/dist/src/backlog/backlog-parts.js +254 -0
- package/dist/src/backlog/backlog-release.js +117 -0
- package/dist/src/backlog/backlog-render.js +27 -0
- package/dist/src/backlog/backlog-structure.js +99 -156
- package/dist/src/backlog/backlog-write.js +40 -127
- package/dist/src/backlog/backlog.js +21 -6
- package/dist/src/backlog/question-answer.js +21 -15
- package/dist/src/baseline/main-baseline.js +89 -20
- package/dist/src/baseline/main-culprit.js +94 -0
- package/dist/src/baseline/main-guardrails.js +209 -0
- package/dist/src/baseline/main-red.js +139 -32
- package/dist/src/baseline/main-revert.js +133 -0
- package/dist/src/baseline/main-watch.js +184 -0
- package/dist/src/brief/brief-edit.js +9 -11
- package/dist/src/brief/brief.js +31 -51
- package/dist/src/budget/budget.js +30 -20
- package/dist/src/budget/fallback-breaker.js +26 -27
- package/dist/src/build/build-check-detect.js +23 -15
- package/dist/src/build/build-check-events.js +25 -6
- package/dist/src/build/build-check-report.js +49 -9
- package/dist/src/build/build-check-scoped.js +18 -11
- package/dist/src/build/build-check.js +2 -1
- package/dist/src/build/build-info.js +2 -3
- package/dist/src/build/build-stage.js +9 -14
- package/dist/src/build/dep-install.js +1 -2
- package/dist/src/change/change-data.js +123 -31
- package/dist/src/change/change-render.js +46 -5
- package/dist/src/cli/brief-command.js +3 -4
- package/dist/src/cli/cli-args.js +118 -33
- package/dist/src/cli/cli-command-args.js +46 -18
- package/dist/src/cli/cli-editor.js +2 -1
- package/dist/src/cli/cli-flag-specs.js +150 -45
- package/dist/src/cli/cli-init.js +51 -0
- package/dist/src/cli/cli-marker-commands.js +4 -4
- package/dist/src/cli/cli-query-commands.js +308 -590
- package/dist/src/cli/cli-repo-gate.js +11 -1
- package/dist/src/cli/cli-role-command.js +420 -0
- package/dist/src/cli/cli-start-summary.js +160 -0
- package/dist/src/cli/{cli-run.js → cli-start.js} +165 -237
- package/dist/src/cli/completion.js +149 -22
- package/dist/src/cli/config-commands.js +41 -18
- package/dist/src/cli/follow-view.js +75 -0
- package/dist/src/cli/help.js +189 -73
- package/dist/src/cli/log-commands.js +148 -82
- package/dist/src/cli/question-commands.js +205 -10
- package/dist/src/cli.js +106 -43
- package/dist/src/collections.js +26 -10
- package/dist/src/concurrency/check-permit.js +20 -3
- package/dist/src/concurrency/lock.js +17 -13
- package/dist/src/concurrency/provider-lease.js +44 -8
- package/dist/src/concurrency/semaphore.js +102 -26
- package/dist/src/config/config-aliases.js +0 -1
- package/dist/src/config/config-editable-keys.js +13 -1
- package/dist/src/config/config-fallbacks.js +93 -56
- package/dist/src/config/config-field-checks.js +40 -10
- package/dist/src/config/config-keys.js +30 -8
- package/dist/src/config/config-live.js +63 -24
- package/dist/src/config/config-request.js +137 -0
- package/dist/src/config/config-schema.js +31 -24
- package/dist/src/config/config-selector-checks.js +123 -0
- package/dist/src/config/config-validation-agents.js +80 -0
- package/dist/src/config/config-validation-model.js +116 -0
- package/dist/src/config/config-validation.js +141 -199
- package/dist/src/config/config-views.js +127 -53
- package/dist/src/config/config-write-core.js +135 -0
- package/dist/src/config/config-write.js +131 -264
- package/dist/src/config/config.js +48 -38
- package/dist/src/config/model-selector.js +34 -34
- package/dist/src/doctor/doctor-backlog-bugs.js +287 -0
- package/dist/src/doctor/doctor-backlog-plans.js +263 -0
- package/dist/src/doctor/doctor-backlog.js +100 -496
- package/dist/src/doctor/doctor-check-names.js +81 -0
- package/dist/src/doctor/doctor-checks.js +52 -579
- package/dist/src/doctor/doctor-claude-checks.js +145 -0
- package/dist/src/doctor/doctor-codex-checks.js +279 -0
- package/dist/src/doctor/doctor-contention-checks.js +380 -0
- package/dist/src/doctor/doctor-holds.js +82 -66
- package/dist/src/doctor/doctor-install.js +2 -1
- package/dist/src/doctor/doctor-model-checks.js +236 -402
- package/dist/src/doctor/doctor-notify.js +3 -4
- package/dist/src/doctor/doctor-opencode-checks.js +162 -0
- package/dist/src/doctor/doctor-orphans.js +182 -63
- package/dist/src/doctor/doctor-project-checks.js +303 -0
- package/dist/src/doctor/doctor.js +121 -77
- package/dist/src/doctor/image-probe.js +21 -8
- package/dist/src/doctor/outcome.js +3 -2
- package/dist/src/doctor/probe.js +7 -11
- package/dist/src/events/event-format.js +181 -86
- package/dist/src/events/event-labels.js +12 -5
- package/dist/src/events/event-legacy.js +39 -15
- package/dist/src/events/event-read.js +39 -39
- package/dist/src/events/event-tally.js +16 -0
- package/dist/src/events/event-window.js +60 -24
- package/dist/src/events/events.js +30 -13
- package/dist/src/events/notify.js +7 -7
- package/dist/src/failure/failure-cluster.js +12 -12
- package/dist/src/failure/failure-data.js +56 -56
- package/dist/src/failure/failure-render.js +31 -23
- package/dist/src/failure/failure-state-change.js +17 -12
- package/dist/src/failure/time-spend.js +99 -35
- package/dist/src/files/files.js +111 -35
- package/dist/src/files/json-files.js +3 -3
- package/dist/src/files/json-object.js +28 -7
- package/dist/src/files/stat-cache.js +2 -2
- package/dist/src/files/tail.js +1 -1
- package/dist/src/gates/bootstrap-gates.js +4 -5
- package/dist/src/gates/budget-gates.js +177 -84
- package/dist/src/gates/disk-gate.js +1 -1
- package/dist/src/gates/gate-polls.js +108 -58
- package/dist/src/gates/maintenance-quota.js +10 -13
- package/dist/src/gates/pause-gates.js +28 -10
- package/dist/src/gates/readiness.js +7 -3
- package/dist/src/gates/role-cap-gates.js +8 -8
- package/dist/src/gates/startup-gate.js +94 -32
- package/dist/src/gates/streak-gate.js +54 -30
- package/dist/src/git/commit-message.js +77 -46
- package/dist/src/git/git-diff.js +16 -10
- package/dist/src/git/git-run.js +79 -38
- package/dist/src/git/git.js +36 -34
- package/dist/src/git/slot-salvage.js +253 -0
- package/dist/src/git/slots-state.js +6 -6
- package/dist/src/git/worktree-pool.js +132 -38
- package/dist/src/git/worktree-use.js +4 -11
- package/dist/src/git/worktree.js +94 -37
- package/dist/src/gui/gui-admin-endpoints.js +96 -0
- package/dist/src/gui/gui-args.js +79 -8
- package/dist/src/gui/gui-backlog-commands.js +42 -18
- package/dist/src/gui/gui-backlog-endpoints.js +155 -0
- package/dist/src/gui/gui-command.js +8 -13
- package/dist/src/gui/gui-config-commands.js +94 -72
- package/dist/src/gui/gui-endpoint-commands.js +4 -3
- package/dist/src/gui/gui-endpoint-common.js +4 -4
- package/dist/src/gui/gui-endpoints.js +11 -380
- package/dist/src/gui/gui-history-endpoints.js +301 -0
- package/dist/src/gui/gui-operator-commands.js +108 -13
- package/dist/src/gui/gui-prompt-commands.js +11 -14
- package/dist/src/gui/gui-report-endpoints.js +90 -0
- package/dist/src/gui/gui-server.js +11 -4
- package/dist/src/gui/gui-team-commands.js +7 -7
- package/dist/src/gui/http-body.js +1 -1
- package/dist/src/history/history-data.js +122 -234
- package/dist/src/history/history-queued.js +147 -0
- package/dist/src/history/history-render.js +42 -22
- package/dist/src/history/history.js +193 -49
- package/dist/src/inbox/inbox-attachments.js +29 -30
- package/dist/src/inbox/inbox-cancel.js +10 -11
- package/dist/src/inbox/inbox-edit.js +9 -9
- package/dist/src/inbox/inbox-submit.js +18 -18
- package/dist/src/inbox/inbox-top.js +25 -9
- package/dist/src/inbox/inbox.js +42 -43
- package/dist/src/inbox/pending-prompt.js +26 -26
- package/dist/src/inbox/prompt-commands.js +62 -49
- package/dist/src/inbox/prompt-not-before.js +2 -2
- package/dist/src/init/init-templates.js +1 -2
- package/dist/src/init/init.js +28 -23
- package/dist/src/merge/backlog-conflicts.js +215 -35
- package/dist/src/merge/merge-batch.js +14 -8
- package/dist/src/merge/merge-cancel.js +53 -0
- package/dist/src/merge/merge-check-failures.js +44 -22
- package/dist/src/merge/merge-core.js +81 -32
- package/dist/src/merge/merge-diff.js +5 -4
- package/dist/src/merge/merge-drain.js +150 -11
- package/dist/src/merge/merge-git.js +177 -38
- package/dist/src/merge/merge-pipeline.js +15 -3
- package/dist/src/merge/merge-post-review.js +90 -0
- package/dist/src/merge/merge-queue-render.js +49 -11
- package/dist/src/merge/merge-queue.js +31 -15
- package/dist/src/merge/merge-requeue.js +102 -0
- package/dist/src/merge/merge-slot.js +61 -16
- package/dist/src/merge/merge-stack.js +33 -11
- package/dist/src/merge/merge-to-main.js +86 -27
- package/dist/src/merge/merge-top.js +69 -0
- package/dist/src/merge/merge-verify.js +12 -10
- package/dist/src/notes-cli.js +30 -15
- package/dist/src/operator/operator-commands.js +192 -81
- package/dist/src/operator/operator-intent.js +69 -42
- package/dist/src/operator/operator-requests.js +35 -40
- package/dist/src/operator/retire.js +5 -6
- package/dist/src/operator/revert.js +142 -34
- package/dist/src/orchestrator/orchestrator-launch.js +60 -52
- package/dist/src/orchestrator/orchestrator-poll.js +320 -0
- package/dist/src/orchestrator/orchestrator-scheduling.js +68 -369
- package/dist/src/orchestrator/orchestrator.js +128 -369
- package/dist/src/orchestrator/retention.js +42 -8
- package/dist/src/orchestrator/scheduling-admit.js +116 -0
- package/dist/src/orchestrator/scheduling-scope.js +201 -0
- package/dist/src/orchestrator/scheduling-skip.js +185 -0
- package/dist/src/orchestrator/startup-migration-steps.js +8 -7
- package/dist/src/orchestrator/startup-migrations.js +11 -7
- package/dist/src/paths.js +116 -49
- package/dist/src/pi/command-shape.js +12 -1
- package/dist/src/pi/pi-args.js +6 -4
- package/dist/src/pi/pi-backend.js +6 -6
- package/dist/src/pi/pi-bin.js +54 -63
- package/dist/src/pi/pi-listed-models.js +53 -0
- package/dist/src/pi/pi-models.js +63 -30
- package/dist/src/pi/pi-run-result.js +1 -1
- package/dist/src/pi/pi-settings.js +1 -1
- package/dist/src/pi/pi-stream.js +6 -6
- package/dist/src/pi/pi-watchdogs.js +18 -19
- package/dist/src/pi-extension/bounded-output.js +5 -3
- package/dist/src/pi-extension/context-budget.js +2 -2
- package/dist/src/pi-extension/context-shake.js +1 -1
- package/dist/src/pi-extension/context-window.js +0 -1
- package/dist/src/pi-extension/full-output.js +3 -10
- package/dist/src/pi-extension/strip-thinking.js +0 -1
- package/dist/src/pi-extension/trim-system-prompt.js +3 -4
- package/dist/src/pi-extension/write-guard.js +37 -0
- package/dist/src/process/launch-services.js +1 -2
- package/dist/src/process/node-bin.js +16 -0
- package/dist/src/process/process-group.js +8 -18
- package/dist/src/process/process.js +41 -2
- package/dist/src/process/run-marker.js +18 -6
- package/dist/src/process/supervisor.js +22 -21
- package/dist/src/prompt/dialect.js +17 -2
- package/dist/src/prompt/gate-notes.js +203 -0
- package/dist/src/prompt/gate-prompts.js +121 -211
- package/dist/src/prompt/notes-backlog.js +181 -0
- package/dist/src/prompt/principles.js +1 -2
- package/dist/src/prompt/prompt-followup.js +19 -14
- package/dist/src/prompt/prompt.js +129 -204
- package/dist/src/redeploy/redeploy-policy.js +24 -19
- package/dist/src/redeploy/redeploy-probes.js +1 -1
- package/dist/src/redeploy/redeploy.js +2 -3
- package/dist/src/redeploy/redeployer.js +20 -20
- package/dist/src/redeploy/self-reload.js +2 -1
- package/dist/src/report/report-data.js +161 -77
- package/dist/src/report/report-fold.js +129 -52
- package/dist/src/report/report-main-red.js +55 -0
- package/dist/src/report/report-render.js +133 -64
- package/dist/src/report/report-types.js +1 -0
- package/dist/src/report/report.js +26 -9
- package/dist/src/request-timeouts.js +2 -2
- package/dist/src/review/known-flakes.js +100 -1
- package/dist/src/review/post-merge-review.js +106 -0
- package/dist/src/review/protected-edits.js +4 -5
- package/dist/src/review/review-followup.js +8 -8
- package/dist/src/review/review-precheck.js +66 -23
- package/dist/src/review/review-run.js +395 -0
- package/dist/src/review/review-verdict.js +2 -2
- package/dist/src/review/review.js +155 -360
- package/dist/src/review/secret-leaks.js +36 -16
- package/dist/src/review/suite-rerun.js +0 -1
- package/dist/src/roles/legacy-role-migration.js +80 -7
- package/dist/src/roles/role-catalog.js +69 -12
- package/dist/src/roles/role-guidance.js +55 -20
- package/dist/src/roles/role-labels.js +1 -2
- package/dist/src/roles/role-render.js +67 -50
- package/dist/src/roles/role-view.js +59 -47
- package/dist/src/roles/roles.js +31 -31
- package/dist/src/roles/runner-ids.js +97 -0
- package/dist/src/run/acceptance-greps.js +119 -0
- package/dist/src/run/feedback-filings.js +51 -0
- package/dist/src/{tick → run}/qa-coverage.js +9 -27
- package/dist/src/{tick/tick-apply.js → run/run-apply.js} +95 -94
- package/dist/src/run/run-detail-data.js +179 -0
- package/dist/src/run/run-detail-render.js +98 -0
- package/dist/src/run/run-detail.js +168 -0
- package/dist/src/{tick/tick-finalize.js → run/run-finalize.js} +72 -60
- package/dist/src/{tick/tick-outcome.js → run/run-outcome.js} +6 -7
- package/dist/src/{tick/tick-prompt.js → run/run-prompt.js} +108 -73
- package/dist/src/{tick/tick-resume.js → run/run-resume.js} +55 -26
- package/dist/src/{tick/tick-stage.js → run/run-stage.js} +108 -50
- package/dist/src/{tick/tick-timing.js → run/run-timing.js} +43 -41
- package/dist/src/{tick/tick-usage.js → run/run-usage.js} +45 -37
- package/dist/src/{tick/tick-verdict.js → run/run-verdict.js} +91 -56
- package/dist/src/run/selfcheck-digest.js +40 -0
- package/dist/src/run/stage-backlog-checks.js +249 -0
- package/dist/src/run/stage-check.js +172 -0
- package/dist/src/run/stage-path-checks.js +730 -0
- package/dist/src/{loop → runner}/leftover.js +80 -25
- package/dist/src/{loop → runner}/model-fallback.js +12 -12
- package/dist/src/runner/revision.js +202 -0
- package/dist/src/{loop/loop-fallback.js → runner/runner-fallback.js} +8 -8
- package/dist/src/runner/runner-outcome.js +107 -0
- package/dist/src/{loop/loop-pi.js → runner/runner-pi.js} +140 -131
- package/dist/src/{loop/loop-recovery.js → runner/runner-recovery.js} +21 -15
- package/dist/src/{loop/loop-tick.js → runner/runner-run.js} +218 -240
- package/dist/src/{loop/loop-state.js → runner/runner-state-load.js} +61 -114
- package/dist/src/runner/runner-state.js +102 -0
- package/dist/src/{loop/loop.js → runner/runner.js} +123 -120
- package/dist/src/scheduling/backoff.js +38 -38
- package/dist/src/scheduling/claims.js +35 -22
- package/dist/src/scheduling/once-round.js +22 -22
- package/dist/src/scheduling/quiet-hours.js +5 -6
- package/dist/src/scheduling/scheduling.js +74 -64
- package/dist/src/scheduling/work-merged-cache.js +2 -2
- package/dist/src/status/status-budget.js +55 -47
- package/dist/src/status/status-data.js +43 -16
- package/dist/src/status/status-inbox.js +2 -2
- package/dist/src/status/status-install.js +0 -1
- package/dist/src/status/status-polls.js +28 -28
- package/dist/src/status/status-roles.js +39 -13
- package/dist/src/team/error-storm.js +8 -8
- package/dist/src/team/failure-spread.js +2 -2
- package/dist/src/team/orchestrator-info.js +15 -9
- package/dist/src/team/reclaim.js +5 -6
- package/dist/src/team/team-hold.js +7 -7
- package/dist/src/team/team-polls.js +91 -50
- package/dist/src/team/team-state.js +8 -2
- package/dist/src/text/datetime.js +63 -17
- package/dist/src/text/format.js +48 -11
- package/dist/src/text/markdown.js +8 -5
- package/dist/src/text/phrases.js +57 -23
- package/dist/src/text/suggest.js +1 -1
- package/dist/src/text/text.js +67 -13
- package/dist/src/ui/badges.js +65 -37
- package/dist/src/ui/gui/gui-client-backlog.js +292 -0
- package/dist/src/ui/gui/gui-client-boot.js +32 -26
- package/dist/src/ui/gui/gui-client-composer.js +8 -9
- package/dist/src/ui/gui/gui-client-drawer-config.js +212 -0
- package/dist/src/ui/gui/gui-client-drawer.js +126 -285
- package/dist/src/ui/gui/gui-client-feed.js +271 -0
- package/dist/src/ui/gui/gui-client-history.js +434 -67
- package/dist/src/ui/gui/gui-client-labels.js +1 -2
- package/dist/src/ui/gui/gui-client-markdown.js +1 -2
- package/dist/src/ui/gui/gui-client-model.js +27 -36
- package/dist/src/ui/gui/gui-client-operator.js +55 -51
- package/dist/src/ui/gui/gui-client-pending.js +227 -23
- package/dist/src/ui/gui/gui-client-report-chart.js +464 -0
- package/dist/src/ui/gui/gui-client-report.js +87 -427
- package/dist/src/ui/gui/{gui-client-loops.js → gui-client-roles.js} +43 -44
- package/dist/src/ui/gui/gui-client-settings.js +56 -4
- package/dist/src/ui/gui/gui-client-team.js +25 -465
- package/dist/src/ui/gui/gui-client.js +27 -25
- package/dist/src/ui/gui/gui-icons.js +0 -2
- package/dist/src/ui/gui/gui-page.js +9 -7
- package/dist/src/ui/gui/gui-styles.js +34 -34
- package/dist/src/ui/progress-data.js +9 -11
- package/dist/src/ui/{tick-progress-model.js → run-progress-model.js} +31 -31
- package/dist/src/ui/status-model.js +133 -125
- package/dist/src/ui/status-payload.js +136 -49
- package/dist/src/ui/status-render.js +101 -82
- package/dist/src/ui/team-alerts.js +248 -57
- package/dist/src/ui/tone.js +5 -6
- package/dist/src/ui/transcript-run.js +58 -0
- package/dist/src/ui/transcript-tail.js +28 -20
- package/dist/src/ui/transcript.js +63 -23
- package/dist/src/ui/tui/tui-app.js +0 -1
- package/dist/src/ui/tui/tui-backlog.js +51 -14
- package/dist/src/ui/tui/tui-editor-answer.js +27 -31
- package/dist/src/ui/tui/tui-editor-attach.js +3 -5
- package/dist/src/ui/tui/tui-editor-backends.js +132 -0
- package/dist/src/ui/tui/tui-editor-brief.js +10 -12
- package/dist/src/ui/tui/tui-editor-budget.js +35 -31
- package/dist/src/ui/tui/tui-editor-claude-reserve.js +24 -0
- package/dist/src/ui/tui/tui-editor-concurrency.js +24 -0
- package/dist/src/ui/tui/tui-editor-config.js +86 -0
- package/dist/src/ui/tui/tui-editor-entry.js +36 -47
- package/dist/src/ui/tui/tui-editor-fallback.js +31 -0
- package/dist/src/ui/tui/tui-editor-instances.js +37 -0
- package/dist/src/ui/tui/tui-editor-instructions.js +136 -0
- package/dist/src/ui/tui/tui-editor-interval.js +11 -9
- package/dist/src/ui/tui/tui-editor-model.js +29 -0
- package/dist/src/ui/tui/tui-editor-notes.js +3 -5
- package/dist/src/ui/tui/tui-editor-notify.js +25 -0
- package/dist/src/ui/tui/tui-editor-pause.js +48 -59
- package/dist/src/ui/tui/tui-editor-prompt.js +11 -16
- package/dist/src/ui/tui/tui-editor-provider-caps.js +27 -0
- package/dist/src/ui/tui/tui-editor-queued.js +5 -9
- package/dist/src/ui/tui/tui-editor-quiet.js +99 -35
- package/dist/src/ui/tui/tui-editor-retire.js +4 -6
- package/dist/src/ui/tui/tui-editor-role-key.js +76 -0
- package/dist/src/ui/tui/tui-editor-role-model.js +28 -0
- package/dist/src/ui/tui/tui-editor-search.js +45 -33
- package/dist/src/ui/tui/tui-editor-session.js +60 -34
- package/dist/src/ui/tui/tui-editor-slots.js +23 -0
- package/dist/src/ui/tui/tui-editors.js +35 -2
- package/dist/src/ui/tui/tui-frame.js +56 -11
- package/dist/src/ui/tui/tui-history.js +8 -9
- package/dist/src/ui/tui/tui-input.js +13 -11
- package/dist/src/ui/tui/tui-keymap.js +0 -1
- package/dist/src/ui/tui/tui-keys.js +24 -9
- package/dist/src/ui/tui/tui-pane-activity.js +14 -11
- package/dist/src/ui/tui/tui-pane-backlog.js +171 -126
- package/dist/src/ui/tui/tui-pane-brief.js +0 -1
- package/dist/src/ui/tui/tui-pane-ctx.js +2 -2
- package/dist/src/ui/tui/tui-pane-health.js +58 -8
- package/dist/src/ui/tui/tui-pane-history.js +402 -82
- package/dist/src/ui/tui/tui-pane-pending.js +308 -13
- package/dist/src/ui/tui/tui-pane-queued.js +71 -55
- package/dist/src/ui/tui/tui-pane-report.js +46 -14
- package/dist/src/ui/tui/tui-pane-session.js +25 -6
- package/dist/src/ui/tui/tui-pane-transcript.js +111 -37
- package/dist/src/ui/tui/tui-pane.js +80 -23
- package/dist/src/ui/tui/tui-panes.js +100 -30
- package/dist/src/ui/tui/tui.js +14 -14
- package/dist/src/verdict/fix-claim.js +82 -32
- package/dist/src/verdict/no-change.js +4 -4
- package/dist/src/verdict/refusal.js +40 -16
- package/dist/src/verdict/reply-contract.js +42 -31
- package/dist/src/version.js +0 -1
- package/package.json +2 -1
- package/dist/src/loop/revision.js +0 -70
- package/dist/src/roles/loop-ids.js +0 -77
- package/dist/src/tick/stage-check.js +0 -419
- package/dist/src/tick/telemetry-digest.js +0 -25
- package/dist/src/tick/tick-detail-data.js +0 -108
- package/dist/src/tick/tick-detail.js +0 -163
- package/dist/src/ui/gui/gui-client-sound.js +0 -53
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** The dashboard's browser-side twins of roleLabel and eventTypeLabel. The script is
|
|
3
2
|
* String.raw text and cannot import server modules, so the data is interpolated at module build
|
|
4
3
|
* and the few lines of logic are hand-kept copies, pinned against their TypeScript originals by
|
|
5
4
|
* test/gui-client-labels.test.ts. Spliced into gui-client.ts's script right after the format
|
|
6
5
|
* helpers, so every later client module can call the two functions. */
|
|
7
6
|
import { EVENT_TYPE_LABELS, RUN_RESULT_LABELS } from "../../events/event-labels.js";
|
|
8
|
-
import { INSTANCE_ID_SOURCE } from "../../roles/
|
|
7
|
+
import { INSTANCE_ID_SOURCE } from "../../roles/runner-ids.js";
|
|
9
8
|
export const GUI_CLIENT_LABELS_JS = String.raw ` // labels:start
|
|
10
9
|
const INSTANCE_ID = new RegExp(${JSON.stringify(INSTANCE_ID_SOURCE)});
|
|
11
10
|
const EVENT_TYPE_LABELS = ${JSON.stringify(EVENT_TYPE_LABELS)};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** A small, safe Markdown renderer for the dashboard, browser-side: the failure digest and the
|
|
3
|
-
* backlog entries (PLANS/BUGS/QUESTIONS.md bodies) are Markdown the
|
|
2
|
+
* backlog entries (PLANS/BUGS/QUESTIONS.md bodies) are Markdown the roles write, and reading
|
|
4
3
|
* them as rendered headings, lists, and tables beats a pre-formatted text blob. It covers what
|
|
5
4
|
* those files use — ATX headings, paragraphs, bullet and numbered lists (continuation lines
|
|
6
5
|
* folded in), pipe tables with right-aligned columns, fenced code, block quotes, and inline
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
/** The dashboard's view model, browser-side — the pure layer between the status payload and
|
|
3
|
-
* what the page shows, with no DOM of its own: each
|
|
4
|
-
* detail), its last result in words with the tone of its outcome, the
|
|
2
|
+
* what the page shows, with no DOM of its own: each role's phase pill (label, tone, live
|
|
3
|
+
* detail), its last result in words with the tone of its outcome, the role sort order and
|
|
5
4
|
* rank groups, the alerts list with the page's own offline entry, the activity feed's
|
|
6
5
|
* kind/tone classification, the backlog title's trailing "(planned …)" metadata, and the
|
|
7
6
|
* queued prompts in execution order. It is the browser twin of the rules status-model.ts
|
|
@@ -11,14 +10,14 @@
|
|
|
11
10
|
* ENTRY_STAMP_META_SOURCE — String.raw interpolates substitutions normally — so the
|
|
12
11
|
* browser regex cannot drift from the server twin the tests pin it against. */
|
|
13
12
|
import { ENTRY_STAMP_META_SOURCE } from "../../backlog/backlog-structure.js";
|
|
14
|
-
import { STALL_SOURCE } from "../
|
|
13
|
+
import { STALL_SOURCE } from "../run-progress-model.js";
|
|
15
14
|
import { PROBLEM_EVENTS, PROBLEM_RESULTS, ROUTINE_BUILD_RESULTS, ROUTINE_EVENTS } from "../tone.js";
|
|
16
|
-
import {
|
|
15
|
+
import { ROLE_RANK_RULES } from "../status-model.js";
|
|
17
16
|
export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
18
|
-
// How a
|
|
17
|
+
// How a role's phase label (status-model.ts rolePhase) reads here: a status word and tone for
|
|
19
18
|
// its pill, whether it is live work, and the detail the label carried after its first word.
|
|
20
19
|
function phaseInfo(phase) {
|
|
21
|
-
// status-model.ts
|
|
20
|
+
// status-model.ts rolePhase appends a " · no change ×N" streak suffix to a resting idle
|
|
22
21
|
// cell's label. Strip it so the exact/startsWith matches and the parsed detail see the
|
|
23
22
|
// plain phase; phaseDetailBase re-appends the streak once itself from the payload's
|
|
24
23
|
// noChangeStreak, so the GUI renders it exactly once.
|
|
@@ -49,6 +48,7 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
49
48
|
if (p === "waiting: daily cap spent") return { key: "cap", label: "Waiting", tone: "amber", live: false, detail: "daily cap" };
|
|
50
49
|
if (p === "waiting: low disk") return { key: "disk", label: "Waiting", tone: "amber", live: false, detail: "low disk" };
|
|
51
50
|
if (p === "waiting: bootstrap") return { key: "bootstrap", label: "Waiting", tone: "amber", live: false, detail: "bootstrap" };
|
|
51
|
+
if (p.startsWith("waiting: maintenance allowance spent")) return { key: "quota", label: "Waiting", tone: "amber", live: false, detail: "maintenance allowance spent this poll" };
|
|
52
52
|
if (p.startsWith("waiting: maintenance allowance used")) return { key: "quota", label: "Waiting", tone: "amber", live: false, detail: "maintenance " + after(35) };
|
|
53
53
|
if (p.startsWith("sleeping")) return { key: "sleeping", label: "Sleeping", tone: "gray", live: false, detail: "" };
|
|
54
54
|
if (p.startsWith("idle: ")) return { key: "idle", label: "Idle", tone: "gray", live: false, detail: p.slice(6) };
|
|
@@ -58,12 +58,12 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
58
58
|
if (p === "stopped") return { key: "stopped", label: "Stopped", tone: "gray", live: false, detail: "the team is not running" };
|
|
59
59
|
return { key: "other", label: p || "unknown", tone: "gray", live: false, detail: "" };
|
|
60
60
|
}
|
|
61
|
-
// A stalled tool call or a long silence, as the phase label names them (
|
|
62
|
-
// inFlightDetail) — the cue that a working
|
|
61
|
+
// A stalled tool call or a long silence, as the phase label names them (run-progress-model.ts's
|
|
62
|
+
// inFlightDetail) — the cue that a working role may be stuck. The pattern is that module's
|
|
63
63
|
// STALL_SOURCE (interpolated at module build), shared with team-alerts.ts's server-side
|
|
64
64
|
// matcher so the two cannot drift from the wording the cell renders.
|
|
65
65
|
const STALL = new RegExp(${JSON.stringify(STALL_SOURCE)});
|
|
66
|
-
// A
|
|
66
|
+
// A run result (run-outcome.ts RunResult) in words, with the tone of its outcome.
|
|
67
67
|
const RESULT_TONES = {
|
|
68
68
|
changed: "green",
|
|
69
69
|
queued: "indigo",
|
|
@@ -88,31 +88,31 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
88
88
|
// build (like STALL above) so the page cannot drift from the server's eventKind.
|
|
89
89
|
const PROBLEM_RESULTS = ${JSON.stringify(PROBLEM_RESULTS)};
|
|
90
90
|
const ROUTINE_BUILD_RESULTS = ${JSON.stringify(ROUTINE_BUILD_RESULTS)};
|
|
91
|
-
// What explains a
|
|
92
|
-
// last error the
|
|
91
|
+
// What explains a role's last result: its summary, or — for a problem that carries none — the
|
|
92
|
+
// last error the role recorded.
|
|
93
93
|
const resultWhy = (l) => l.lastSummary || (PROBLEM_RESULTS.includes(l.lastResult) || l.phase === "failing" ? l.lastError || "" : "");
|
|
94
|
-
//
|
|
95
|
-
//
|
|
94
|
+
// role-sort:start
|
|
95
|
+
// Role order — status-model.ts's roleRank/sortRolesByState, the TUI's order too: the running
|
|
96
96
|
// director first (its own live work, outside the maxConcurrent cap it bypasses — BUGS.md
|
|
97
97
|
// 2026-10-06), then live work (working, reviewing, merge), then work waiting in the pipe
|
|
98
|
-
// line (approved, awaiting a slot), then
|
|
99
|
-
// paused, then idle; within a rank the most recent
|
|
100
|
-
// by name. The phase → rank rules are status-model.ts's
|
|
98
|
+
// line (approved, awaiting a slot), then roles that need attention (failing, main red), then
|
|
99
|
+
// paused, then idle; within a rank the most recent run first, a never-ran role last, ties
|
|
100
|
+
// by name. The phase → rank rules are status-model.ts's ROLE_RANK_RULES (interpolated at
|
|
101
101
|
// module build, like STALL/PROBLEM_RESULTS above), so the literals cannot drift from the
|
|
102
102
|
// server's copy.
|
|
103
|
-
const
|
|
104
|
-
function
|
|
103
|
+
const ROLE_RANK_RULES = ${JSON.stringify(ROLE_RANK_RULES)};
|
|
104
|
+
function roleRank(phase) {
|
|
105
105
|
const p = String(phase || "");
|
|
106
|
-
for (const r of
|
|
106
|
+
for (const r of ROLE_RANK_RULES) {
|
|
107
107
|
if (r.active ? isActivePhase(p) : (r.phases || []).includes(p) || (r.prefixes || []).some((x) => p.startsWith(x)))
|
|
108
108
|
return r.rank;
|
|
109
109
|
}
|
|
110
110
|
return 4;
|
|
111
111
|
}
|
|
112
|
-
function
|
|
113
|
-
return
|
|
114
|
-
const ra =
|
|
115
|
-
const rb =
|
|
112
|
+
function sortRoles(roles) {
|
|
113
|
+
return roles.slice().sort((a, b) => {
|
|
114
|
+
const ra = roleRank(a.phase);
|
|
115
|
+
const rb = roleRank(b.phase);
|
|
116
116
|
if (ra !== rb) return ra - rb;
|
|
117
117
|
const ta = a.lastRunEndedAt ?? 0;
|
|
118
118
|
const tb = b.lastRunEndedAt ?? 0;
|
|
@@ -120,12 +120,12 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
120
120
|
return a.role.localeCompare(b.role);
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
-
//
|
|
123
|
+
// role-sort:end
|
|
124
124
|
// The team table's section for each rank. The running director has its own section so it
|
|
125
125
|
// does not join the In-progress rows an operator scans against maxConcurrent; the permit
|
|
126
126
|
// holders (rank 0) and the pipeline waiters (rank 1, labeled "Waiting to start") keep
|
|
127
127
|
// sharing In progress (BUGS.md 2026-10-06).
|
|
128
|
-
const
|
|
128
|
+
const ROLE_GROUPS = [["Director", -1], ["In progress", 0, 1], ["Needs attention", 2], ["Paused", 3], ["Idle", 4]];
|
|
129
129
|
// The payload's alerts (team-alerts.ts teamAlerts — the TUI's attention lines use the same
|
|
130
130
|
// list), plus the one only the page can know: that its server stopped answering.
|
|
131
131
|
const OFFLINE_ALERT = { key: "offline", tone: "red", title: "Lost contact with the dashboard server",
|
|
@@ -140,15 +140,6 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
140
140
|
// are information.
|
|
141
141
|
const NEEDS_YOU = (a) => a.tone === "red" || a.tone === "amber" || a.tone === "indigo";
|
|
142
142
|
const needsYou = (alerts) => alerts.filter(NEEDS_YOU).length;
|
|
143
|
-
// The needs-you alerts' keys — the set the sound cue diffs each poll against the last poll's.
|
|
144
|
-
const needsYouKeys = (alerts) => alerts.filter(NEEDS_YOU).map((a) => a.key);
|
|
145
|
-
// The needs-you keys of the given alerts that prevKeys (the previous poll's set, or null on
|
|
146
|
-
// the first poll) lacks — exactly the alerts a new cue should announce. A null prev yields
|
|
147
|
-
// every needs-you key, so a page opened onto an already-alerting team cues once.
|
|
148
|
-
const newNeedsYouKeys = (prevKeys, alerts) => {
|
|
149
|
-
const prior = new Set(prevKeys || []);
|
|
150
|
-
return needsYouKeys(alerts).filter((k) => !prior.has(k));
|
|
151
|
-
};
|
|
152
143
|
// needs-you:end
|
|
153
144
|
// An activity item's kind — its icon and tone, and whether the Notable filter keeps it.
|
|
154
145
|
const ROUTINE_EVENTS = ${JSON.stringify(ROUTINE_EVENTS)};
|
|
@@ -172,7 +163,7 @@ export const GUI_CLIENT_MODEL_JS = String.raw ` // view-model:start
|
|
|
172
163
|
const m = ENTRY_STAMP_RE.exec(String(t));
|
|
173
164
|
return m ? { title: String(t).slice(0, m.index), meta: m[1] } : { title: String(t), meta: "" };
|
|
174
165
|
}
|
|
175
|
-
// Queued prompts in execution order — the director's first, then each
|
|
166
|
+
// Queued prompts in execution order — the director's first, then each role's — each with the
|
|
176
167
|
// queue-file address its Cancel button sends (never a list position, so a stale frame can
|
|
177
168
|
// never cancel the wrong prompt).
|
|
178
169
|
function queuedPrompts(d) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// vocabulary: plain
|
|
2
1
|
import { PAUSE_REASON_MAX } from "../../team/team-state.js";
|
|
3
2
|
/** The dashboard's team-wide operator controls, browser-side, all living in the sidebar so
|
|
4
3
|
* they are in reach from every view: the daily spend badge — today's spend against the cap
|
|
@@ -6,16 +5,14 @@ import { PAUSE_REASON_MAX } from "../../team/team-state.js";
|
|
|
6
5
|
* setter as the TUI's Ctrl+B) — the pause control, a menu of timed pauses with an
|
|
7
6
|
* optional reason (POST /api/pause with `forSeconds` and `reason`, the CLI's
|
|
8
7
|
* `pause --for`/`--reason`) that turns into a Resume button with the countdown while the
|
|
9
|
-
* team is paused
|
|
10
|
-
* no server call). Neither keeps optimistic state: after a successful
|
|
8
|
+
* team is paused. Neither keeps optimistic state: after a successful
|
|
11
9
|
* POST the next status poll re-renders them from the server's answer, and a failed one toasts
|
|
12
10
|
* the error and leaves the editor open. Spliced into gui-client.ts's script, where it reaches
|
|
13
11
|
* the other sections' shared plumbing through that concatenation: the DOM and HTML helpers
|
|
14
12
|
* ($, esc, icon), the formatters (fmtUsd, fmtCap, humanSeconds), the slot painter and toast
|
|
15
13
|
* (paintPanel, showFlash), the POST helper (postJson), the click hook (onClick), the menu
|
|
16
14
|
* registry (closeMenus, openMenu), the poll re-render (refresh, hoisted from gui-client-boot.ts
|
|
17
|
-
* later in the join), the
|
|
18
|
-
* earlier in the join), and the shared page state it reads and invalidates (lastStatus,
|
|
15
|
+
* later in the join), and the shared page state it reads and invalidates (lastStatus,
|
|
19
16
|
* lastPaint). Its own two popovers share their scaffolding through openPopover (each
|
|
20
17
|
* supplies the html plus an onClosed that resets its flag and re-renders the slot), and
|
|
21
18
|
* its two POSTs share their send-toast-close-repaint tail through the core's postAction. */
|
|
@@ -68,8 +65,8 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
68
65
|
// The subscription usage window (plans/agent-backends.md §8, PLANS.md part 6d/7): the
|
|
69
66
|
// sidebar's spend card renders it beside the daily spend, or in its place for a
|
|
70
67
|
// subscription-only team. The label/status/clock rules mirror badges.ts's
|
|
71
|
-
//
|
|
72
|
-
// because the card lists EVERY window, not just the most constrained one.
|
|
68
|
+
// subscriptionWindowBadge — the preformatted header fragment the TUI uses cannot be reused here
|
|
69
|
+
// because the card lists EVERY window of EVERY block, not just the most constrained one.
|
|
73
70
|
function windowLabel(type) {
|
|
74
71
|
const m = /^(\w+)_(hour|day|week)$/.exec(String(type));
|
|
75
72
|
if (!m) return String(type).replace(/_/g, " ");
|
|
@@ -94,6 +91,12 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
94
91
|
if (hours < 24) return "resets in " + hours + "h " + (minutes % 60) + "m";
|
|
95
92
|
return "resets in " + Math.floor(hours / 24) + "d " + (hours % 24) + "h";
|
|
96
93
|
}
|
|
94
|
+
// A window's consumed fraction as a whole-number percent, the same shape as node-side
|
|
95
|
+
// utilizationPct - the browser script keeps its inline copy, so the text percentage and
|
|
96
|
+
// the meter width share this one home instead of each rounding w.utilization by hand.
|
|
97
|
+
function windowPct(w) {
|
|
98
|
+
return Math.round(w.utilization * 100);
|
|
99
|
+
}
|
|
97
100
|
function chainMoved(chain) {
|
|
98
101
|
return Object.values(chain || {}).some((t) => t.reason === "window" || t.reason === "reserve");
|
|
99
102
|
}
|
|
@@ -106,12 +109,12 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
106
109
|
return "<span class='side-card-value window-line'>" + esc(tier + " → " + t.pair + money + until) + "</span>";
|
|
107
110
|
}).join("");
|
|
108
111
|
}
|
|
109
|
-
function windowLine(w,
|
|
110
|
-
const parts = ["
|
|
112
|
+
function windowLine(w, block, chain) {
|
|
113
|
+
const parts = [block.label + " " + windowLabel(w.type)];
|
|
111
114
|
const word = windowWord(w.status);
|
|
112
|
-
parts.push(typeof w.utilization === "number" ?
|
|
115
|
+
parts.push(typeof w.utilization === "number" ? windowPct(w) + "%" : word === "ok" ? "ok · usage not reported" : word);
|
|
113
116
|
if (w.isUsingOverage) parts.push("overage");
|
|
114
|
-
if (w.status === "rejected" &&
|
|
117
|
+
if (w.status === "rejected" && block.heldUntil != null) parts.push((chainMoved(chain) ? "on fallback until " : block.label + " model jobs wait until ") + windowClock(block.heldUntil));
|
|
115
118
|
else if (w.status !== "reset" && typeof w.resetsAt === "number") parts.push(windowResets(w.resetsAt));
|
|
116
119
|
return parts.join(" · ");
|
|
117
120
|
}
|
|
@@ -120,35 +123,41 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
120
123
|
if (w.status === "allowed_warning") return " t-amber";
|
|
121
124
|
return "";
|
|
122
125
|
}
|
|
123
|
-
function windowLinesHtml(
|
|
124
|
-
if (!
|
|
125
|
-
//
|
|
126
|
-
// unlabelled type sorts last, then by type name. A copy,
|
|
126
|
+
function windowLinesHtml(blocks, only, chain) {
|
|
127
|
+
if (!blocks || blocks.length === 0) return chainLinesHtml(chain);
|
|
128
|
+
// One window line per block, its windows shortest-first (5h above 7d), whatever order
|
|
129
|
+
// the server ranks severity in; an unlabelled type sorts last, then by type name. A copy,
|
|
130
|
+
// so block.windows keeps its order.
|
|
131
|
+
return blocks.map((block) => blockLinesHtml(block, chain)).join("") + chainLinesHtml(chain);
|
|
132
|
+
}
|
|
133
|
+
function blockLinesHtml(block, chain) {
|
|
127
134
|
const hours = (w) => {
|
|
128
135
|
const m = /^(\d+)([hdw])$/.exec(windowLabel(w.type));
|
|
129
136
|
return m ? Number(m[1]) * (m[2] === "h" ? 1 : m[2] === "d" ? 24 : 168) : Infinity;
|
|
130
137
|
};
|
|
131
|
-
const shortestFirst =
|
|
138
|
+
const shortestFirst = block.windows.slice().sort((a, b) => (hours(a) === hours(b) ? (a.type < b.type ? -1 : a.type > b.type ? 1 : 0) : hours(a) < hours(b) ? -1 : 1));
|
|
132
139
|
return shortestFirst.map((w) => {
|
|
133
|
-
const line = "<span class='side-card-value window-line" + windowLineTone(w) + "'>" + esc(windowLine(w,
|
|
140
|
+
const line = "<span class='side-card-value window-line" + windowLineTone(w) + "'>" + esc(windowLine(w, block, chain)) + "</span>";
|
|
134
141
|
if (typeof w.utilization !== "number") return line;
|
|
135
|
-
const pct = Math.min(100,
|
|
142
|
+
const pct = Math.min(100, windowPct(w));
|
|
136
143
|
return line + meterBar(windowLineTone(w), pct);
|
|
137
|
-
}).join("")
|
|
144
|
+
}).join("");
|
|
138
145
|
}
|
|
139
146
|
// The sidebar's spend card for a payload's budget block: a plain card for an all-free team
|
|
140
147
|
// (no spend a cap could bind, so no editor), otherwise the button that opens the cap editor,
|
|
141
148
|
// with a meter while a cap is set.
|
|
142
|
-
function budgetCardHtml(b,
|
|
149
|
+
function budgetCardHtml(b, blocks, only, chain) {
|
|
143
150
|
// A subscription-only team has no priced spend for a cap to bind, so the window card
|
|
144
|
-
// stands in place of the spend card and carries no editor
|
|
145
|
-
|
|
151
|
+
// stands in place of the spend card and carries no editor — but only while a window block
|
|
152
|
+
// actually exists; an all-free subscription-only team (only and free, no windows) falls
|
|
153
|
+
// through to the "Free models" spend card below so it never renders an empty window card.
|
|
154
|
+
if (only && blocks && blocks.length > 0) {
|
|
146
155
|
return "<div class='side-card' title='Claude.ai subscription usage windows — a rejected window pauses claude model jobs until it resets'>" +
|
|
147
|
-
"<span class='side-card-label'>" + icon("clock") + "Claude window</span>" + windowLinesHtml(
|
|
156
|
+
"<span class='side-card-label'>" + icon("clock") + "Claude window</span>" + windowLinesHtml(blocks, only, chain) + "</div>";
|
|
148
157
|
}
|
|
149
158
|
if (b.free) {
|
|
150
159
|
return "<div class='side-card' title='Every model the team can use is cost n/a, so there is nothing to cap'>" +
|
|
151
|
-
"<span class='side-card-label'>" + icon("dollar") + "Spend</span><span class='side-card-value'>Free models</span>" + windowLinesHtml(
|
|
160
|
+
"<span class='side-card-label'>" + icon("dollar") + "Spend</span><span class='side-card-value'>Free models</span>" + windowLinesHtml(blocks, only, chain) + "</div>";
|
|
152
161
|
}
|
|
153
162
|
const capped = b.capUsd > 0;
|
|
154
163
|
const pct = capped ? Math.min(100, (b.spentUsd / b.capUsd) * 100) : 0;
|
|
@@ -157,12 +166,12 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
157
166
|
esc(capped ? "Today's spend against the daily cap — click to change the cap" : "No daily cap — click to set one") + "'>" +
|
|
158
167
|
"<span class='side-card-label'>" + icon("dollar") + "Spent today<span class='edit'>" + (capped ? "Edit cap" : "Set a cap") + "</span></span>" +
|
|
159
168
|
"<span class='side-card-value'>" + esc(fmtUsd(b.spentUsd)) + " <small>" + esc(capped ? "of " + fmtCap(b.capUsd) : "no daily cap") + "</small></span>" +
|
|
160
|
-
(capped ? meterBar(tone, pct.toFixed(1)) : "") + windowLinesHtml(
|
|
169
|
+
(capped ? meterBar(tone, pct.toFixed(1)) : "") + windowLinesHtml(blocks, only, chain) + "</button>";
|
|
161
170
|
}
|
|
162
171
|
function renderBudgetBadge(d) {
|
|
163
172
|
if (budgetEditing) return; // the open editor owns the slot until save or cancel
|
|
164
173
|
const b = d && d.budget;
|
|
165
|
-
paintPanel("budgetwrap", b ? budgetCardHtml(b, d && d.
|
|
174
|
+
paintPanel("budgetwrap", b ? budgetCardHtml(b, d && d.subscriptionWindows, d && d.subscriptionOnly, d && d.chain) : "");
|
|
166
175
|
}
|
|
167
176
|
function openBudgetEditor() {
|
|
168
177
|
const b = lastStatus && lastStatus.budget;
|
|
@@ -198,7 +207,19 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
198
207
|
const t = String(raw).trim();
|
|
199
208
|
if (t === "") return { ok: true, value: 0 };
|
|
200
209
|
const n = Number(t);
|
|
201
|
-
|
|
210
|
+
// The two rejections are genuinely different rules, so they name their own one, mirroring
|
|
211
|
+
// the TUI's parseBudgetInput: the shape rejection (a fine number like "1e2" or "0x10"
|
|
212
|
+
// that is within the bound but that no one means as USD) names the plain-decimal rule,
|
|
213
|
+
// while the bounds rejection names the bound because a 25-digit run IS "a number of 0 or
|
|
214
|
+
// more". A single message would mislead: "1e2" is rejected as shape, yet would be told
|
|
215
|
+
// it is not a number of 0 or more.
|
|
216
|
+
if (!/^\d*\.?\d+$/.test(t)) {
|
|
217
|
+
return {
|
|
218
|
+
ok: false,
|
|
219
|
+
error: "the cap must be a plain dollar amount like 25, 12.50, or .5 — no +/-, exponent, or hex notation — leave it empty for no cap",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (!Number.isFinite(n) || n < 0 || n > Number.MAX_SAFE_INTEGER) {
|
|
202
223
|
return {
|
|
203
224
|
ok: false,
|
|
204
225
|
error: "the cap must be a number of 0 or more, at most " + Number.MAX_SAFE_INTEGER + " — leave it empty for no cap",
|
|
@@ -223,8 +244,12 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
223
244
|
}
|
|
224
245
|
const value = parsed.value;
|
|
225
246
|
// A failure leaves the editor open so the value can be fixed.
|
|
226
|
-
await postAction("/api/budget", { maxDailyCostUsd: value },
|
|
227
|
-
|
|
247
|
+
await postAction("/api/budget", { maxDailyCostUsd: value }, (d) => {
|
|
248
|
+
if (d && d.unchanged) {
|
|
249
|
+
return "Daily cap is already " + (value > 0 ? fmtCap(value) : "removed") + " — nothing saved";
|
|
250
|
+
}
|
|
251
|
+
return value > 0 ? "Daily cap set to " + fmtCap(value) : "Daily cap removed";
|
|
252
|
+
});
|
|
228
253
|
}
|
|
229
254
|
onClick((t, ev) => {
|
|
230
255
|
if (t.closest("#budgetbadge")) {
|
|
@@ -370,25 +395,4 @@ export const GUI_CLIENT_OPERATOR_JS = String.raw ` // shared-operator:start
|
|
|
370
395
|
if (choice) postStopSchedule({ inSeconds: Number(choice.dataset.stopin) });
|
|
371
396
|
});
|
|
372
397
|
// stop-control:end
|
|
373
|
-
|
|
374
|
-
// sound-control:start
|
|
375
|
-
// The sidebar's sound control, beside the theme toggle: a speaker icon that flips between
|
|
376
|
-
// the unmuted and muted glyph. A per-browser preference (setSoundMuted stores it), not team
|
|
377
|
-
// state — no server call; the choice takes effect on the next cue.
|
|
378
|
-
function soundControlHtml() {
|
|
379
|
-
return "<button type='button' class='icon-btn' id='soundtoggle' title='" +
|
|
380
|
-
(soundMuted ? "Sound is muted — click to unmute the alert cue" : "Sound is on — click to mute the alert cue") +
|
|
381
|
-
"' aria-label='" + (soundMuted ? "Unmute" : "Mute") + " the alert cue'>" +
|
|
382
|
-
icon(soundMuted ? "mute" : "sound") + "</button>";
|
|
383
|
-
}
|
|
384
|
-
function renderSoundBadge() {
|
|
385
|
-
paintPanel("soundwrap", soundControlHtml());
|
|
386
|
-
}
|
|
387
|
-
function toggleSound() {
|
|
388
|
-
setSoundMuted(!soundMuted);
|
|
389
|
-
renderSoundBadge();
|
|
390
|
-
}
|
|
391
|
-
onClick((t) => {
|
|
392
|
-
if (t.closest("#soundtoggle")) toggleSound();
|
|
393
|
-
});
|
|
394
|
-
// sound-control:end`;
|
|
398
|
+
`;
|