@pellux/goodvibes-tui 2.0.21 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -1
- package/README.md +30 -29
- package/docs/README.md +8 -5
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +28 -19
- package/src/cli/management.ts +5 -2
- package/src/cli/tui-startup.ts +34 -39
- package/src/core/agent-view-render.ts +157 -0
- package/src/core/approval-alert.ts +49 -11
- package/src/core/bookmark-navigation.ts +7 -1
- package/src/core/budget-breach-notifier.ts +27 -8
- package/src/core/compaction-receipt.ts +1 -1
- package/src/core/context-usage.ts +1 -1
- package/src/core/conversation-compaction-render.ts +3 -3
- package/src/core/conversation-display-only.ts +86 -0
- package/src/core/conversation-event-navigation.ts +27 -0
- package/src/core/conversation-line-cache.ts +216 -447
- package/src/core/conversation-render-context.ts +20 -27
- package/src/core/conversation-rendering.ts +157 -575
- package/src/core/conversation-splash-state.ts +6 -1
- package/src/core/conversation-types.ts +35 -0
- package/src/core/conversation-usage.ts +12 -0
- package/src/core/conversation.ts +130 -131
- package/src/core/long-task-notifier.ts +100 -31
- package/src/core/notices.ts +75 -0
- package/src/core/pairing-tailscale-gateway.ts +1 -1
- package/src/core/process-output-log.ts +143 -0
- package/src/core/rewind-receipt.ts +1 -1
- package/src/core/session-focus.ts +190 -0
- package/src/core/session-resume-core.ts +23 -81
- package/src/core/stream-event-wiring.ts +31 -5
- package/src/core/system-message-noise.ts +2 -2
- package/src/core/system-message-router.ts +16 -18
- package/src/core/turn-event-wiring.ts +272 -33
- package/src/core/work-tree-focus.ts +290 -0
- package/src/core/work-tree-fold-store.ts +143 -0
- package/src/core/work-tree-model.ts +799 -0
- package/src/core/work-tree-render.ts +384 -0
- package/src/core/work-tree-sources.ts +184 -0
- package/src/core/work-tree-wiring.ts +176 -0
- package/src/core/workstream-notification.ts +36 -6
- package/src/core/wrfc-notice-titles.ts +37 -0
- package/src/input/agents-modal-text.ts +119 -0
- package/src/input/agents-modal.ts +699 -0
- package/src/input/bookmark-modal.ts +33 -9
- package/src/input/changes-git.ts +251 -0
- package/src/input/changes-modal.ts +629 -0
- package/src/input/changes-model.ts +125 -0
- package/src/input/command-palette-types.ts +41 -0
- package/src/input/command-palette.ts +272 -0
- package/src/input/command-reference.ts +2 -2
- package/src/input/command-registry.ts +77 -35
- package/src/input/commands/acp-runtime.ts +19 -9
- package/src/input/commands/channel-runtime.ts +2 -2
- package/src/input/commands/ci-runtime.ts +1 -1
- package/src/input/commands/codebase-runtime.ts +1 -1
- package/src/input/commands/config.ts +7 -1
- package/src/input/commands/context-window.ts +25 -19
- package/src/input/commands/control-room-runtime.ts +18 -18
- package/src/input/commands/conversation-runtime.ts +0 -1
- package/src/input/commands/cost-runtime.ts +29 -20
- package/src/input/commands/diff-runtime.ts +35 -181
- package/src/input/commands/eval.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -7
- package/src/input/commands/fresh-conversation.ts +86 -0
- package/src/input/commands/git-runtime.ts +5 -22
- package/src/input/commands/graph-runtime.ts +1 -1
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +8 -9
- package/src/input/commands/hooks-runtime.ts +2 -2
- package/src/input/commands/hosted-runtime.ts +3 -3
- package/src/input/commands/incident-runtime.ts +3 -3
- package/src/input/commands/intelligence-runtime.ts +6 -9
- package/src/input/commands/knowledge.ts +2 -2
- package/src/input/commands/legacy-panel-command.ts +57 -0
- package/src/input/commands/local-auth-runtime.ts +8 -9
- package/src/input/commands/local-provider-runtime.ts +7 -4
- package/src/input/commands/local-runtime.ts +12 -15
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup.ts +13 -19
- package/src/input/commands/memory.ts +1 -1
- package/src/input/commands/notify-runtime.ts +9 -0
- package/src/input/commands/operator-runtime.ts +10 -12
- package/src/input/commands/permissions-provenance.ts +3 -3
- package/src/input/commands/planning-runtime.ts +7 -7
- package/src/input/commands/platform-sandbox-runtime.ts +2 -2
- package/src/input/commands/platform-services-runtime.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +2 -2
- package/src/input/commands/policy.ts +3 -3
- package/src/input/commands/provider.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/review-runtime.ts +39 -94
- package/src/input/commands/rewind-runtime.ts +81 -108
- package/src/input/commands/runtime-services.ts +15 -17
- package/src/input/commands/services-runtime.ts +2 -2
- package/src/input/commands/session-content.ts +21 -5
- package/src/input/commands/session-workflow.ts +13 -38
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/shell-core.ts +19 -4
- package/src/input/commands/skills-runtime.ts +2 -2
- package/src/input/commands/status-runtime.ts +13 -0
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +2 -8
- package/src/input/commands/work-plan-runtime.ts +4 -4
- package/src/input/commands/workstream-attempts.ts +24 -47
- package/src/input/commands/workstream-runtime.ts +2 -2
- package/src/input/commands/worktree-runtime.ts +3 -3
- package/src/input/commands.ts +3 -1
- package/src/input/composer-editor.ts +44 -0
- package/src/input/concealed-input.ts +1 -1
- package/src/input/config-modal-types.ts +20 -8
- package/src/input/config-modal.ts +106 -105
- package/src/input/confirm-dialog-types.ts +28 -0
- package/src/input/confirm-dialog.ts +70 -0
- package/src/input/delete-key-policy.ts +3 -3
- package/src/input/feed-context-factory.ts +15 -16
- package/src/input/handler-command-route.ts +7 -42
- package/src/input/handler-content-actions.ts +16 -15
- package/src/input/handler-feed-routes.ts +26 -211
- package/src/input/handler-feed.ts +68 -95
- package/src/input/handler-interactions.ts +5 -3
- package/src/input/handler-modal-routes.ts +215 -216
- package/src/input/handler-modal-stack.ts +81 -11
- package/src/input/handler-modal-token-routes.ts +4 -0
- package/src/input/handler-onboarding.ts +0 -1
- package/src/input/handler-picker-routes.ts +65 -107
- package/src/input/handler-session-view-route.ts +149 -0
- package/src/input/handler-shortcuts.ts +16 -154
- package/src/input/handler-types.ts +4 -2
- package/src/input/handler-ui-state.ts +45 -15
- package/src/input/handler-work-tree-route.ts +123 -0
- package/src/input/handler.ts +25 -70
- package/src/input/keybindings.ts +16 -71
- package/src/input/masked-entry-modal.ts +117 -0
- package/src/input/mcp-workspace.ts +48 -17
- package/src/input/model-picker-filter.ts +8 -0
- package/src/input/model-picker-open.ts +99 -0
- package/src/input/model-picker-types.ts +1 -1
- package/src/input/model-picker.ts +92 -9
- package/src/input/notifications-modal.ts +123 -0
- package/src/input/overlay-filter.ts +26 -0
- package/src/input/profile-picker-modal.ts +37 -8
- package/src/input/search.ts +3 -3
- package/src/input/selection-modal-queue.ts +2 -0
- package/src/input/selection-modal.ts +28 -16
- package/src/input/session-picker-modal.ts +33 -8
- package/src/input/settings-modal-activation.ts +7 -2
- package/src/input/settings-modal-data.ts +11 -6
- package/src/input/settings-modal-types.ts +1 -1
- package/src/input/settings-modal.ts +20 -20
- package/src/input/submission-intent.ts +1 -1
- package/src/input/submission-router.ts +4 -9
- package/src/input/surface-modal-host.ts +110 -0
- package/src/input/theme-settings-actions.ts +82 -0
- package/src/input/usage-modal.ts +183 -0
- package/src/input/views.ts +97 -0
- package/src/main.ts +175 -165
- package/src/permissions/hunk-selection.ts +1 -1
- package/src/permissions/prompt-card.ts +511 -0
- package/src/permissions/prompt.ts +59 -622
- package/src/renderer/agents-modal.ts +310 -0
- package/src/renderer/autocomplete-overlay.ts +42 -220
- package/src/renderer/back-to-bottom.ts +80 -0
- package/src/renderer/block-actions-overlay.ts +30 -48
- package/src/renderer/bookmark-modal.ts +48 -79
- package/src/renderer/changes-modal.ts +325 -0
- package/src/renderer/code-block.ts +184 -106
- package/src/renderer/command-palette.ts +93 -0
- package/src/renderer/composer-fragments.ts +4 -4
- package/src/renderer/composer.ts +146 -0
- package/src/renderer/compositor.ts +26 -160
- package/src/renderer/config-modal.ts +185 -81
- package/src/renderer/confirm-dialog.ts +50 -0
- package/src/renderer/context-inspector.ts +116 -154
- package/src/renderer/context-status-hint.ts +4 -4
- package/src/renderer/conversation-layout.ts +20 -0
- package/src/renderer/conversation-overlays.ts +94 -84
- package/src/renderer/conversation-surface.ts +19 -38
- package/src/renderer/diff-tint.ts +98 -0
- package/src/renderer/file-picker-overlay.ts +63 -90
- package/src/renderer/footer-targets.ts +38 -0
- package/src/renderer/git-status.ts +3 -4
- package/src/renderer/header-line.ts +140 -117
- package/src/renderer/help-overlay.ts +133 -219
- package/src/renderer/history-search-overlay.ts +15 -12
- package/src/renderer/lane-graph/bead.ts +800 -0
- package/src/renderer/lane-graph/glyphs.ts +134 -0
- package/src/renderer/lane-graph/layout.ts +248 -0
- package/src/renderer/lane-graph/paint.ts +537 -0
- package/src/renderer/lane-graph/semantic-memo.ts +77 -0
- package/src/renderer/layout-engine.ts +2 -57
- package/src/renderer/layout.ts +7 -13
- package/src/renderer/markdown-inline.ts +2 -1
- package/src/renderer/markdown-table.ts +17 -12
- package/src/renderer/markdown.ts +92 -34
- package/src/renderer/masked-entry-modal.ts +78 -0
- package/src/renderer/mcp-workspace.ts +166 -203
- package/src/renderer/model-workspace.ts +381 -436
- package/src/renderer/notifications-modal.ts +116 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +178 -588
- package/src/renderer/process-view.ts +192 -0
- package/src/renderer/profile-picker-modal.ts +58 -110
- package/src/renderer/search-overlay.ts +6 -3
- package/src/renderer/selection-modal-overlay.ts +87 -327
- package/src/renderer/semantic-diff.ts +2 -2
- package/src/renderer/session-chips.ts +102 -0
- package/src/renderer/session-picker-modal.ts +177 -297
- package/src/renderer/settings-modal-connections.ts +14 -23
- package/src/renderer/settings-modal-context.ts +367 -0
- package/src/renderer/settings-modal-helpers.ts +6 -11
- package/src/renderer/settings-modal.ts +322 -726
- package/src/renderer/shell-surface.ts +277 -175
- package/src/renderer/shortcuts-overlay.ts +217 -0
- package/src/renderer/status-line.ts +475 -0
- package/src/renderer/surface-compose.ts +174 -0
- package/src/renderer/surface-kit-extra.ts +303 -0
- package/src/renderer/surface-kit-list.ts +366 -0
- package/src/renderer/surface-kit-parts.ts +360 -0
- package/src/renderer/surface-kit.ts +568 -0
- package/src/renderer/syntax-highlighter.ts +280 -197
- package/src/renderer/syntax-theme.ts +51 -0
- package/src/renderer/system-message.ts +0 -1
- package/src/renderer/term-caps.ts +42 -1
- package/src/renderer/terminal-bg-probe.ts +116 -19
- package/src/renderer/terminal-palette-probe.ts +322 -0
- package/src/renderer/terminal-palette-reader.ts +183 -0
- package/src/renderer/terminal-palette.ts +58 -0
- package/src/renderer/theme-mode-config.ts +16 -1
- package/src/renderer/theme.ts +234 -207
- package/src/renderer/thinking.ts +0 -1
- package/src/renderer/throbber.ts +188 -0
- package/src/renderer/toast-center.ts +119 -0
- package/src/renderer/ui-factory.ts +39 -602
- package/src/renderer/ui-primitives.ts +8 -25
- package/src/renderer/usage-modal.ts +353 -0
- package/src/renderer/user-message.ts +58 -0
- package/src/renderer/voice-capture-chip.ts +53 -0
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +38 -89
- package/src/runtime/bootstrap-core.ts +13 -15
- package/src/runtime/bootstrap-hook-bridge.ts +12 -21
- package/src/runtime/bootstrap-notifier-sync.ts +17 -1
- package/src/runtime/bootstrap-shell.ts +16 -50
- package/src/runtime/bootstrap.ts +14 -14
- package/src/runtime/client/fleet-union.ts +5 -5
- package/src/runtime/client/hosted-exit.ts +2 -2
- package/src/runtime/client/hosted-sessions.ts +1 -1
- package/src/runtime/client/spine-adoption.ts +1 -1
- package/src/runtime/context-accounting-source.ts +5 -4
- package/src/runtime/index.ts +1 -0
- package/src/runtime/notification-dispatch.ts +102 -29
- package/src/runtime/recovery-offer-wiring.ts +4 -1
- package/src/runtime/recovery-prompt.ts +31 -15
- package/src/runtime/runtime-services-types.ts +10 -6
- package/src/runtime/services.ts +17 -12
- package/src/runtime/session-continuity-hints.ts +2 -5
- package/src/runtime/session-inbound-inputs.ts +1 -1
- package/src/runtime/session-resume-liveness-confirm.ts +14 -2
- package/src/runtime/startup-typeahead-gate.ts +103 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +0 -1
- package/src/runtime/store/domains/index.ts +0 -8
- package/src/runtime/store/selectors/index.ts +0 -28
- package/src/runtime/store/state.ts +0 -8
- package/src/runtime/ui-services.ts +4 -6
- package/src/runtime/usage-tracker.ts +348 -0
- package/src/runtime/wrfc-persistence.ts +4 -4
- package/src/shell/blocking-input.ts +92 -2
- package/src/shell/recovery-input-helpers.ts +1 -1
- package/src/shell/session-views.ts +539 -0
- package/src/shell/status-report.ts +86 -0
- package/src/shell/transcript-scroll.ts +68 -0
- package/src/shell/ui-openers.ts +84 -172
- package/src/shell/view-openers.ts +205 -0
- package/src/tools/wrfc-agent-guard.ts +22 -2
- package/src/utils/format-duration.ts +4 -8
- package/src/utils/splash-lines.ts +9 -1
- package/src/utils/terminal-width.ts +56 -0
- package/src/verification/live-verifier.ts +0 -10
- package/src/version.ts +1 -1
- package/src/{panels → views}/agent-inspector-shared.ts +2 -2
- package/src/{panels → views}/builtin-modals.ts +22 -21
- package/src/views/builtin-views.ts +135 -0
- package/src/{panels → views}/confirm-state.ts +9 -9
- package/src/{panels → views}/diff-review-model.ts +10 -3
- package/src/{panels → views}/eval-registry.ts +1 -1
- package/src/{panels → views}/fleet-acts.ts +49 -85
- package/src/{panels/fleet-panel-format.ts → views/fleet-format.ts} +40 -40
- package/src/{panels → views}/fleet-gateway.ts +5 -5
- package/src/{panels → views}/fleet-observed-render.ts +16 -16
- package/src/{panels → views}/fleet-read-model.ts +9 -9
- package/src/{panels/fleet-tabs.ts → views/fleet-session-tabs.ts} +13 -13
- package/src/{panels → views}/fleet-spawn.ts +33 -49
- package/src/{panels → views}/fleet-steer.ts +12 -12
- package/src/{panels → views}/fleet-stop.ts +4 -4
- package/src/{panels → views}/fleet-transcript.ts +26 -27
- package/src/{panels/fleet-panel-worktree-detail.ts → views/fleet-worktree-detail.ts} +7 -7
- package/src/{panels → views}/hosted-session-feed.ts +6 -6
- package/src/views/modal-surface-registry.ts +41 -0
- package/src/{panels → views}/modals/devices-modal.ts +2 -2
- package/src/{panels → views}/modals/hooks-modal.ts +13 -13
- package/src/{panels → views}/modals/keybindings-modal.ts +19 -27
- package/src/{panels → views}/modals/knowledge-modal.ts +6 -5
- package/src/{panels → views}/modals/local-auth-modal.ts +22 -21
- package/src/{panels → views}/modals/marketplace-modal.ts +11 -11
- package/src/{panels → views}/modals/memory-modal.ts +8 -8
- package/src/{panels → views}/modals/modal-surface-helpers.ts +15 -5
- package/src/{panels → views}/modals/pairing-modal.ts +9 -9
- package/src/{panels → views}/modals/planning-modal.ts +15 -20
- package/src/{panels → views}/modals/plugins-modal.ts +6 -6
- package/src/{panels → views}/modals/policy-modal.ts +13 -5
- package/src/{panels → views}/modals/provider-health-modal.ts +4 -4
- package/src/{panels → views}/modals/remote-modal.ts +3 -3
- package/src/{panels → views}/modals/sandbox-modal.ts +4 -4
- package/src/{panels → views}/modals/security-modal.ts +22 -16
- package/src/{panels → views}/modals/services-modal.ts +3 -3
- package/src/{panels → views}/modals/settings-sync-modal.ts +4 -4
- package/src/{panels → views}/modals/skills-modal.ts +9 -9
- package/src/{panels → views}/modals/subscription-modal.ts +3 -3
- package/src/{panels → views}/modals/work-plan-modal.ts +10 -13
- package/src/views/notifications-feed.ts +314 -0
- package/src/{panels → views}/polish-core.ts +38 -36
- package/src/{panels → views}/polish-tables.ts +35 -26
- package/src/{panels → views}/polish.ts +101 -95
- package/src/{panels → views}/project-planning-answer-actions.ts +3 -3
- package/src/{panels → views}/provider-health-routes.ts +14 -14
- package/src/{panels → views}/search-focus.ts +8 -8
- package/src/{panels → views}/session-maintenance.ts +11 -11
- package/src/views/skills-discovery.ts +159 -0
- package/src/views/view-deps.ts +80 -0
- package/src/views/view-panel-adapter.ts +53 -0
- package/src/{panels → views}/workstream-graph-render.ts +1 -1
- package/src/core/conversation-fold.ts +0 -101
- package/src/core/conversation-turn-structure.ts +0 -464
- package/src/core/conversation-user-receipts.ts +0 -42
- package/src/input/commands/operator-panel-runtime.ts +0 -186
- package/src/input/panel-integration-actions.ts +0 -33
- package/src/input/panel-mouse-geometry.ts +0 -97
- package/src/input/panel-paste-flood-guard.ts +0 -86
- package/src/panels/base-panel.ts +0 -301
- package/src/panels/builtin/agent.ts +0 -27
- package/src/panels/builtin/development.ts +0 -92
- package/src/panels/builtin/knowledge.ts +0 -12
- package/src/panels/builtin/operations.ts +0 -177
- package/src/panels/builtin/session.ts +0 -81
- package/src/panels/builtin/shared.ts +0 -357
- package/src/panels/builtin-panels.ts +0 -28
- package/src/panels/cost-tracker-panel.ts +0 -746
- package/src/panels/diff-panel.ts +0 -797
- package/src/panels/diff-review-panel.ts +0 -395
- package/src/panels/expandable-list-panel.ts +0 -189
- package/src/panels/fleet-deep-link.ts +0 -31
- package/src/panels/fleet-panel.ts +0 -799
- package/src/panels/git-panel.ts +0 -800
- package/src/panels/hosted-session-panel.ts +0 -221
- package/src/panels/index.ts +0 -21
- package/src/panels/local-auth-panel.ts +0 -478
- package/src/panels/notifications-feed.ts +0 -127
- package/src/panels/notifications-panel.ts +0 -160
- package/src/panels/panel-confirm-overlay.ts +0 -72
- package/src/panels/panel-manager.ts +0 -791
- package/src/panels/plugins-panel.ts +0 -371
- package/src/panels/scrollable-list-panel.ts +0 -498
- package/src/panels/skills-panel.ts +0 -454
- package/src/panels/token-budget-panel.ts +0 -688
- package/src/panels/types.ts +0 -191
- package/src/panels/wrfc-panel-format.ts +0 -133
- package/src/renderer/diff-view.ts +0 -134
- package/src/renderer/fleet-tab-strip.ts +0 -56
- package/src/renderer/footer-tips.ts +0 -53
- package/src/renderer/fullscreen-primitives.ts +0 -146
- package/src/renderer/fullscreen-workspace.ts +0 -194
- package/src/renderer/hint-grammar.ts +0 -52
- package/src/renderer/modal-factory.ts +0 -480
- package/src/renderer/overlay-box.ts +0 -154
- package/src/renderer/overlay-viewport.ts +0 -104
- package/src/renderer/panel-composite.ts +0 -145
- package/src/renderer/panel-workspace-bar.ts +0 -54
- package/src/renderer/process-indicator.ts +0 -163
- package/src/renderer/tab-strip.ts +0 -222
- package/src/renderer/text-layout.ts +0 -31
- package/src/renderer/tool-call.ts +0 -276
- package/src/renderer/tool-result-expanded-lines.ts +0 -48
- package/src/renderer/tool-result-summary.ts +0 -219
- package/src/runtime/diagnostics/panels/index.ts +0 -21
- package/src/runtime/diagnostics/panels/ops.ts +0 -156
- package/src/runtime/perf/panel-contracts.ts +0 -32
- package/src/runtime/store/domains/panels.ts +0 -117
- package/src/verification/verification-ledger.ts +0 -707
- /package/src/{panels → views}/memory-consolidation-gateway.ts +0 -0
- /package/src/{panels → views}/modals/modal-theme.ts +0 -0
- /package/src/{panels → views}/provider-health-domains.ts +0 -0
|
@@ -1,98 +1,136 @@
|
|
|
1
1
|
import type { Line } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
-
import {
|
|
2
|
+
import { calcSessionCost, isModelPriced } from '@pellux/goodvibes-sdk/platform/providers';
|
|
3
3
|
import { UIFactory } from './ui-factory.ts';
|
|
4
4
|
import { voiceCaptureRowVisible, type VoiceCaptureIndicatorState } from '../core/voice-capture-status.ts';
|
|
5
|
+
import { activeTokens, activeUiTones } from './theme.ts';
|
|
6
|
+
import { permissionModeLabel } from '../core/permission-mode.ts';
|
|
7
|
+
import { SLEEP_DISABLED_CHIP } from '../core/power-status.ts';
|
|
8
|
+
import { renderComposer, COMPOSER_FIXED_ROWS } from './composer.ts';
|
|
9
|
+
import { renderStatusLine, type StatusChip } from './status-line.ts';
|
|
10
|
+
import { renderThrobberLine, type ThrobberState } from './throbber.ts';
|
|
11
|
+
import { renderBackToBottomPill, type BackToBottomState } from './back-to-bottom.ts';
|
|
12
|
+
import { voiceCaptureChip } from './voice-capture-chip.ts';
|
|
13
|
+
import { tagFooterLine } from './footer-targets.ts';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* shell-surface.ts, everything under the transcript, top to bottom:
|
|
17
|
+
*
|
|
18
|
+
* blank row one full empty row under the transcript, drawn only when a
|
|
19
|
+
* text row follows (a half row cannot be drawn between two
|
|
20
|
+
* rows of plain text). An agent or process view's body
|
|
21
|
+
* already ends with one, so views skip it.
|
|
22
|
+
* hint rows the retry affordance, context pressure, the scriptable
|
|
23
|
+
* status line, when they have something to say
|
|
24
|
+
* throbber what main is doing right now, only while it works
|
|
25
|
+
* (throbber.ts)
|
|
26
|
+
* back to bottom the pill, centered, only while the output is scrolled
|
|
27
|
+
* away from its live bottom (back-to-bottom.ts); a fill row,
|
|
28
|
+
* so a full empty row keeps it off the text above it
|
|
29
|
+
* input area ▄ cap, padding, text, padding, ▀ cap (composer.ts): the
|
|
30
|
+
* caps are the half rows between the input area and the rows
|
|
31
|
+
* above and below it
|
|
32
|
+
* status line one row of session state
|
|
33
|
+
*
|
|
34
|
+
* At rest that is 6 rows (input area 5 + status 1), and with the header the
|
|
35
|
+
* resting chrome is 7. While main works, 2 more: the blank row and the
|
|
36
|
+
* throbber; while the output is scrolled back, 2 more: an empty row and the
|
|
37
|
+
* back-to-bottom pill. The input area holds only input (its placeholder,
|
|
38
|
+
* even while the keyboard is in the work tree). Token totals, the per-turn
|
|
39
|
+
* history, tool count, notification mode, the session spine and the web
|
|
40
|
+
* surface address live in the Usage modal and /status, not on the main
|
|
41
|
+
* screen. What stays always visible is safety: the approval mode and the
|
|
42
|
+
* auto-approve warning, the live microphone and the sleep-disabled chip (the
|
|
43
|
+
* left end of the status line), the failover marker (the header, after the
|
|
44
|
+
* model) and the compaction-pressure hint (a hint row above the input area).
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The work tree's keys, shown on the status line while the keyboard is in it.
|
|
49
|
+
* Esc leads: the way back to typing is never dropped for lack of room; the
|
|
50
|
+
* other keys give way from the end (status-line.ts keeps whole keys in order).
|
|
51
|
+
*/
|
|
52
|
+
const WORK_TREE_KEYS: ReadonlyArray<readonly [string, string]> = [
|
|
53
|
+
['esc', 'back to typing'], ['↑↓', 'move between beads'], ['←→', 'fold / unfold'], ['enter', 'open'], ['y', 'copy'],
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/** What an agent or process view changes under the transcript. */
|
|
57
|
+
export interface ShellFooterView {
|
|
58
|
+
/** The composer bar: the agent's lane color, or the process color. */
|
|
59
|
+
readonly barColor: string;
|
|
60
|
+
readonly placeholder?: string;
|
|
61
|
+
/** The composer takes no input; this says why. */
|
|
62
|
+
readonly disabledReason?: string;
|
|
63
|
+
/** The view's keys on the status line (esc back to main, ctrl+x stop, …). */
|
|
64
|
+
readonly keys: ReadonlyArray<readonly [string, string]>;
|
|
65
|
+
/** After the keys: main kept in sight (◐ main · working). */
|
|
66
|
+
readonly trail?: { readonly text: string; readonly fg: string } | null;
|
|
67
|
+
/** A notice in place of the keys (press ctrl+x again to stop). */
|
|
68
|
+
readonly notice?: { readonly text: string; readonly tone: 'error' | 'info' } | null;
|
|
69
|
+
/** The process view shows no context bar or cost. */
|
|
70
|
+
readonly noContext?: boolean;
|
|
71
|
+
/** The cost this view states instead of the session's (an agent's own, when priced). */
|
|
72
|
+
readonly cost?: string | null;
|
|
73
|
+
}
|
|
5
74
|
|
|
6
75
|
export interface ShellFooterBuildOptions {
|
|
7
76
|
readonly width: number;
|
|
77
|
+
/** The keyboard is in the conversation work tree: the status line shows its keys. */
|
|
78
|
+
readonly workTreeFocused?: boolean;
|
|
8
79
|
readonly promptText: string;
|
|
9
80
|
readonly promptLineCount: number;
|
|
10
81
|
readonly promptCursorPos?: number;
|
|
11
82
|
readonly promptFocused?: boolean;
|
|
12
|
-
|
|
13
|
-
* True when the panel workspace owns keyboard focus. Only consulted as a
|
|
14
|
-
* fallback when `promptFocused` is not supplied, see buildShellFooter's
|
|
15
|
-
* default expression. Callers that already compute `promptFocused`
|
|
16
|
-
* themselves (main.ts does) do not need to also pass this.
|
|
17
|
-
*/
|
|
18
|
-
readonly panelFocused?: boolean;
|
|
19
|
-
readonly usage: { up: number; down: number; fleetCostUsd?: number | null };
|
|
83
|
+
readonly usage: { up: number; down: number; cacheRead?: number; cacheWrite?: number; fleetCostUsd?: number | null };
|
|
20
84
|
readonly showExitNotice: boolean;
|
|
21
85
|
readonly lastCopyTime: number;
|
|
86
|
+
/** The model the session cost is priced against; not drawn (the header names the model). */
|
|
22
87
|
readonly model?: string;
|
|
23
|
-
/**
|
|
24
|
-
* Divergence marker appended to the model segment while the serving backend
|
|
25
|
-
* is not the user's configured selection (core/active-model-identity.ts),
|
|
26
|
-
* e.g. "failover from abacusai:route-llm". Absent/empty in the normal case,
|
|
27
|
-
* where the context-info line renders exactly as it always has.
|
|
28
|
-
*/
|
|
29
|
-
readonly modelNote?: string;
|
|
30
|
-
readonly toolCount?: number;
|
|
31
88
|
readonly workingDir?: string;
|
|
32
|
-
|
|
33
|
-
readonly
|
|
89
|
+
/** The home directory, drawn as ~ at the start of the working directory. */
|
|
90
|
+
readonly homeDirectory?: string;
|
|
91
|
+
/** An agent or process view is showing (session-focus.ts). */
|
|
92
|
+
readonly view?: ShellFooterView | null;
|
|
93
|
+
/** The current branch (and dirty marker), shown beside the directory at rest. */
|
|
94
|
+
readonly branch?: string;
|
|
95
|
+
/** The model's context window; null when it is unknown (the meter says "unknown"). */
|
|
96
|
+
readonly contextWindow?: number | null;
|
|
34
97
|
readonly compactThreshold?: number;
|
|
35
98
|
readonly dangerMode?: boolean;
|
|
36
99
|
readonly lastInputTokens?: number;
|
|
37
100
|
readonly commandArgsHint?: string;
|
|
38
|
-
readonly hitlMode?: string;
|
|
39
101
|
readonly runningAgentCount: number;
|
|
40
102
|
readonly runningProcessCount: number;
|
|
41
103
|
readonly indicatorFocused: boolean;
|
|
42
104
|
readonly runningAgentProgress?: string;
|
|
43
|
-
readonly composerMode?: string;
|
|
44
|
-
readonly composerStatus?: string;
|
|
45
105
|
readonly composerFlags?: readonly string[];
|
|
46
106
|
readonly composerPendingRisk?: 'none' | 'approval-wait' | 'shell' | 'command' | 'remote';
|
|
47
107
|
/**
|
|
48
108
|
* Current session permission mode (config value: 'prompt' | 'allow-all' |
|
|
49
|
-
* 'custom' | 'plan' | 'accept-edits').
|
|
50
|
-
*
|
|
109
|
+
* 'custom' | 'plan' | 'accept-edits'). Named by the status line's mode chip
|
|
110
|
+
* and colors the composer's bar. Cycled by Shift+Tab and toggled by /plan.
|
|
51
111
|
*/
|
|
52
112
|
readonly permissionMode?: string;
|
|
53
|
-
/**
|
|
54
|
-
* Passive context pressure hint from buildContextStatusHint.
|
|
55
|
-
* Rendered as a dim informational line above the prompt when non-null.
|
|
56
|
-
*/
|
|
113
|
+
/** Passive context pressure hint from buildContextStatusHint, a row above the composer. */
|
|
57
114
|
readonly contextStatusHint?: string | null;
|
|
58
|
-
/**
|
|
59
|
-
* Output of the user's scriptable status line (`statusline.command`).
|
|
60
|
-
* Rendered as a dim informational line above the prompt when non-null,
|
|
61
|
-
* below the context pressure hint.
|
|
62
|
-
*/
|
|
115
|
+
/** Output of the user's scriptable status line (`statusline.command`), a row above the composer. */
|
|
63
116
|
readonly scriptableStatusLine?: string | null;
|
|
64
|
-
/**
|
|
65
|
-
* The one-key retry/switch-model affordance's transient hint text (see
|
|
66
|
-
* retry-affordance.ts). Rendered as its own line ABOVE the context
|
|
67
|
-
* pressure hint while armed; present here only means "show it now", the
|
|
68
|
-
* caller is responsible for passing null the instant it disarms, so this
|
|
69
|
-
* is a time-bounded status line, never a lingering claim.
|
|
70
|
-
*/
|
|
117
|
+
/** The one-key retry/switch-model affordance's transient hint, topmost while armed. */
|
|
71
118
|
readonly retryHint?: string | null;
|
|
72
|
-
/**
|
|
73
|
-
* Compact footer posture for short terminals (~<30 rows). Collapses the
|
|
74
|
-
* footer to its essentials (prompt box + token/cost line + help) and drops
|
|
75
|
-
* the process indicator, context bar, context-info line and posture block.
|
|
76
|
-
*/
|
|
77
|
-
readonly compact?: boolean;
|
|
78
|
-
/**
|
|
79
|
-
* Cross-surface session-spine posture for the context-info segment.
|
|
80
|
-
* Set ONLY in adopted-daemon mode ('online'/'offline'); left undefined in
|
|
81
|
-
* local-only mode so no segment renders.
|
|
82
|
-
*/
|
|
83
|
-
readonly sessionSpineStatus?: 'online' | 'offline';
|
|
84
|
-
/** The web surface's reachable URL, when that surface is enabled; a persistent footer segment. */
|
|
85
|
-
readonly webSurfaceUrl?: string;
|
|
86
119
|
/** True while power.keepAwake holds, renders the always-visible "sleep disabled" chip. */
|
|
87
120
|
readonly powerKeepAwake?: boolean;
|
|
121
|
+
/** Live microphone state; a non-null visible state renders the microphone chip. */
|
|
122
|
+
readonly voiceCapture?: VoiceCaptureIndicatorState | null;
|
|
123
|
+
/** What main is doing while it works (a turn, a compaction): the throbber row. Null at rest. */
|
|
124
|
+
readonly throbber?: ThrobberState | null;
|
|
125
|
+
/** A main turn is running: the status line leads with what Esc does now (interrupt, or clear input). */
|
|
126
|
+
readonly turnRunning?: boolean;
|
|
88
127
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* with `voice.wake.indicator: off`) renders nothing.
|
|
128
|
+
* The output is scrolled away from its live bottom: the back-to-bottom pill
|
|
129
|
+
* shows above the input area, and a running turn's esc hint says "back to
|
|
130
|
+
* bottom" (Esc returns there and never interrupts while scrolled). Null or
|
|
131
|
+
* absent at the bottom.
|
|
94
132
|
*/
|
|
95
|
-
readonly
|
|
133
|
+
readonly backToBottom?: BackToBottomState | null;
|
|
96
134
|
}
|
|
97
135
|
|
|
98
136
|
export interface ShellFooterBuildResult {
|
|
@@ -100,35 +138,21 @@ export interface ShellFooterBuildResult {
|
|
|
100
138
|
readonly height: number;
|
|
101
139
|
}
|
|
102
140
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const VOICE_CAPTURE_ROWS = 1;
|
|
112
|
-
// Compact posture drops the context-info line (and never shows the context
|
|
113
|
-
// bar or process indicator), leaving just: prompt-box top border, bottom
|
|
114
|
-
// border, token-usage line, and the help/exit line.
|
|
115
|
-
const COMPACT_FOOTER_BASE_ROWS = 4;
|
|
116
|
-
|
|
117
|
-
// Dim slate foreground shared by the passive footer status lines (context
|
|
118
|
-
// pressure hint and the scriptable status line).
|
|
119
|
-
const DIM_STATUS_FG = '#64748b';
|
|
141
|
+
/** The status line under the composer. */
|
|
142
|
+
const STATUS_ROWS = 1;
|
|
143
|
+
|
|
144
|
+
function blankRow(width: number): Line {
|
|
145
|
+
const line = UIFactory.stringToLine('', width);
|
|
146
|
+
for (const cell of line) cell.bg = '';
|
|
147
|
+
return line;
|
|
148
|
+
}
|
|
120
149
|
|
|
121
150
|
/**
|
|
122
|
-
* Real height of the most recently rendered footer
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* context hint that the static formula cannot see. Reset to null before any
|
|
126
|
-
* footer has rendered (cold start), where the formula is exact for the
|
|
127
|
-
* common posture-free, hint-free case. The compact flag is part of the cache
|
|
128
|
-
* key: a cached non-compact height must never answer a compact query (and
|
|
129
|
-
* vice versa), since the two postures differ by several rows.
|
|
151
|
+
* Real height of the most recently rendered footer. estimateShellFooterHeight
|
|
152
|
+
* prefers it so the pre-render viewport math accounts for the hint rows the
|
|
153
|
+
* static formula cannot see. Null before any footer has rendered.
|
|
130
154
|
*/
|
|
131
|
-
let lastRenderedFooterHeight:
|
|
155
|
+
let lastRenderedFooterHeight: number | null = null;
|
|
132
156
|
|
|
133
157
|
/**
|
|
134
158
|
* The wrapped-prompt shape the composer reports each frame, the subset
|
|
@@ -142,13 +166,8 @@ export interface WrappedPromptCursorInfo {
|
|
|
142
166
|
|
|
143
167
|
/**
|
|
144
168
|
* Flatten a wrapped-prompt cursor position (line + column) into the single
|
|
145
|
-
* character offset
|
|
146
|
-
* per wrapped line.
|
|
147
|
-
* (scrolled out of the composer's window), which suppresses the cursor overlay
|
|
148
|
-
* rather than drawing it in the wrong place.
|
|
149
|
-
*
|
|
150
|
-
* Lives here rather than inline at the render site so main.ts (a composition
|
|
151
|
-
* root already at the source-line gate) stays a wiring file.
|
|
169
|
+
* character offset the composer's `cursorPos` expects, counting one separator
|
|
170
|
+
* per wrapped line. Undefined when the cursor is not on a visible line.
|
|
152
171
|
*/
|
|
153
172
|
export function promptCursorOffset(info: WrappedPromptCursorInfo): number | undefined {
|
|
154
173
|
if (info.visibleCursorLine < 0) return undefined;
|
|
@@ -158,92 +177,175 @@ export function promptCursorOffset(info: WrappedPromptCursorInfo): number | unde
|
|
|
158
177
|
return precedingChars + info.visibleCursorCol;
|
|
159
178
|
}
|
|
160
179
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
180
|
+
/** Rows the footer will take for this many prompt rows (exact when no hint rows show). */
|
|
181
|
+
export function estimateShellFooterHeight(promptLineCount: number): number {
|
|
182
|
+
if (lastRenderedFooterHeight !== null) return lastRenderedFooterHeight;
|
|
183
|
+
return COMPOSER_FIXED_ROWS + Math.max(1, promptLineCount) + STATUS_ROWS;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** The composer's bar color: the session mode, or shell while a shell command is typed. */
|
|
187
|
+
function composerBarColor(permissionMode: string | undefined, shell: boolean): string {
|
|
188
|
+
const t = activeTokens();
|
|
189
|
+
if (shell) return t.accent;
|
|
190
|
+
switch (permissionMode) {
|
|
191
|
+
case 'plan': return t.info;
|
|
192
|
+
case 'accept-edits':
|
|
193
|
+
case 'allow-all':
|
|
194
|
+
case 'custom':
|
|
195
|
+
return t.warning;
|
|
196
|
+
default:
|
|
197
|
+
return t.brand;
|
|
169
198
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The status line's mode chip: the approval mode (muted; plan in the info
|
|
203
|
+
* color), or "! auto-approve" in the error color while everything is
|
|
204
|
+
* auto-approved. While the warning shows, only plan keeps its name beside it
|
|
205
|
+
* (a read-only posture still worth knowing); "normal" or "auto" next to it
|
|
206
|
+
* would only repeat or contradict it.
|
|
207
|
+
*/
|
|
208
|
+
function modeChips(permissionMode: string | undefined, dangerMode: boolean): StatusChip[] {
|
|
209
|
+
const t = activeTokens();
|
|
210
|
+
const chips: StatusChip[] = [];
|
|
211
|
+
if (!dangerMode || permissionMode === 'plan') {
|
|
212
|
+
chips.push({ text: permissionModeLabel(permissionMode), fg: permissionMode === 'plan' ? t.info : t.textMuted, bold: permissionMode === 'plan', keep: true });
|
|
173
213
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
214
|
+
if (dangerMode) chips.push({ text: '! auto-approve', fg: t.error, bold: true, keep: true });
|
|
215
|
+
return chips;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** The chips no view hides: auto-approve, the live microphone, sleep disabled. */
|
|
219
|
+
function safetyChips(options: ShellFooterBuildOptions): StatusChip[] {
|
|
220
|
+
const t = activeTokens();
|
|
221
|
+
const chips: StatusChip[] = [];
|
|
222
|
+
if (options.dangerMode) chips.push({ text: '! auto-approve', fg: t.error, bold: true, keep: true });
|
|
223
|
+
const voice = options.voiceCapture ?? null;
|
|
224
|
+
if (voice && voiceCaptureRowVisible(voice)) chips.push(voiceCaptureChip(voice));
|
|
225
|
+
if (options.powerKeepAwake) chips.push({ text: SLEEP_DISABLED_CHIP, fg: t.warning, bold: true, keep: true });
|
|
226
|
+
return chips;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Format a USD amount with a precision that suits its magnitude. */
|
|
230
|
+
function fmtCost(usd: number): string {
|
|
231
|
+
if (!(usd > 0)) return '0.00';
|
|
232
|
+
if (usd < 0.01) return usd.toFixed(4);
|
|
233
|
+
if (usd < 1) return usd.toFixed(3);
|
|
234
|
+
return usd.toFixed(2);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** "~$0.246", or "you ~$0.25 · fleet ~$0.47" once delegated agents have cost something (estimates, hence the ~). */
|
|
238
|
+
export function statusCostText(usage: ShellFooterBuildOptions['usage'], model: string | undefined): string | null {
|
|
239
|
+
const inp = usage.up;
|
|
240
|
+
const out = usage.down;
|
|
241
|
+
const main = model && isModelPriced(model)
|
|
242
|
+
? `~$${fmtCost(calcSessionCost(inp, out, usage.cacheRead ?? 0, usage.cacheWrite ?? 0, model))}`
|
|
243
|
+
: null;
|
|
244
|
+
const fleet = usage.fleetCostUsd;
|
|
245
|
+
if (typeof fleet === 'number' && fleet > 0) return `you ${main ?? '~n/a'} · fleet ~$${fmtCost(fleet)}`;
|
|
246
|
+
return main;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function displayDirectory(workingDir: string | undefined, homeDirectory: string | undefined): string | undefined {
|
|
250
|
+
if (!workingDir) return undefined;
|
|
251
|
+
const home = homeDirectory ?? (typeof process !== 'undefined' ? process.env.HOME ?? '' : '');
|
|
252
|
+
if (!home) return workingDir;
|
|
253
|
+
if (workingDir === home) return '~';
|
|
254
|
+
return workingDir.startsWith(home.endsWith('/') ? home : `${home}/`) ? '~' + workingDir.slice(home.replace(/\/$/, '').length) : workingDir;
|
|
180
255
|
}
|
|
181
256
|
|
|
182
|
-
export function buildShellFooter(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
options.
|
|
197
|
-
options.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
options.
|
|
206
|
-
options.
|
|
207
|
-
options.
|
|
208
|
-
|
|
209
|
-
options.
|
|
210
|
-
options.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const retryLine = UIFactory.stringToLine(options.retryHint, options.width, { fg: DIM_STATUS_FG, bold: true });
|
|
244
|
-
lines.unshift(retryLine);
|
|
245
|
-
}
|
|
257
|
+
export function buildShellFooter(options: ShellFooterBuildOptions): ShellFooterBuildResult {
|
|
258
|
+
const t = activeTokens();
|
|
259
|
+
const lines: Line[] = [];
|
|
260
|
+
const view = options.view ?? null;
|
|
261
|
+
// Passive hint rows, topmost first: the retry affordance (actionable, time
|
|
262
|
+
// bounded), the context pressure hint, then the user's scriptable line.
|
|
263
|
+
const above: Line[] = [];
|
|
264
|
+
if (options.retryHint) above.push(UIFactory.stringToLine(` ${options.retryHint}`, options.width, { fg: t.textMuted, bold: true }));
|
|
265
|
+
if (options.contextStatusHint) above.push(UIFactory.stringToLine(` ${options.contextStatusHint}`, options.width, { fg: t.textMuted }));
|
|
266
|
+
if (options.scriptableStatusLine) above.push(UIFactory.stringToLine(` ${options.scriptableStatusLine}`, options.width, { fg: t.textMuted }));
|
|
267
|
+
// The throbber: main's activity, led by "main" inside a view.
|
|
268
|
+
if (options.throbber) above.push(renderThrobberLine(options.width, view ? { ...options.throbber, owner: 'main' } : options.throbber));
|
|
269
|
+
// The back-to-bottom pill is a fill row: a full empty row keeps it off any text row above it.
|
|
270
|
+
if (options.backToBottom) {
|
|
271
|
+
if (above.length > 0) above.push(blankRow(options.width));
|
|
272
|
+
above.push(renderBackToBottomPill(options.width, options.backToBottom));
|
|
273
|
+
}
|
|
274
|
+
// A full empty row keeps these rows off the transcript (a view's body ends with one already).
|
|
275
|
+
if (above.length > 0 && !view) lines.push(blankRow(options.width));
|
|
276
|
+
lines.push(...above);
|
|
277
|
+
|
|
278
|
+
const focused = options.promptFocused ?? !options.indicatorFocused;
|
|
279
|
+
lines.push(...renderComposer({
|
|
280
|
+
width: options.width,
|
|
281
|
+
promptText: options.promptText,
|
|
282
|
+
cursorPos: options.promptCursorPos,
|
|
283
|
+
focused,
|
|
284
|
+
argsHint: options.commandArgsHint,
|
|
285
|
+
modeColor: view ? view.barColor : composerBarColor(options.permissionMode, options.composerPendingRisk === 'shell'),
|
|
286
|
+
placeholder: view?.placeholder,
|
|
287
|
+
disabledReason: view?.disabledReason,
|
|
288
|
+
}));
|
|
289
|
+
|
|
290
|
+
// The left end of the status line: mode, auto-approve, microphone and
|
|
291
|
+
// sleep are kept at any width; the composer flags are dropped first.
|
|
292
|
+
const chips: StatusChip[] = modeChips(options.permissionMode, options.dangerMode === true);
|
|
293
|
+
const voice = options.voiceCapture ?? null;
|
|
294
|
+
if (voice && voiceCaptureRowVisible(voice)) chips.push(voiceCaptureChip(voice));
|
|
295
|
+
if (options.powerKeepAwake) chips.push({ text: SLEEP_DISABLED_CHIP, fg: t.warning, bold: true, keep: true });
|
|
296
|
+
for (const flag of options.composerFlags ?? []) {
|
|
297
|
+
if (flag === 'shell') continue; // the bar's accent color says shell
|
|
298
|
+
// An orchestration request leaves this terminal: its flag carries the remote color.
|
|
299
|
+
const remote = flag === 'orchestration' && options.composerPendingRisk === 'remote';
|
|
300
|
+
chips.push({ text: flag, fg: remote ? activeUiTones().chrome.remote : t.textFaint, bold: remote });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const copied = Date.now() - options.lastCopyTime < 2000;
|
|
304
|
+
if (view) {
|
|
305
|
+
// Inside an agent or process view: its keys (what Esc does first), then main kept in sight.
|
|
306
|
+
lines.push(tagFooterLine(renderStatusLine({
|
|
307
|
+
width: options.width,
|
|
308
|
+
chips: safetyChips(options),
|
|
309
|
+
notice: options.showExitNotice ? { text: 'Press Ctrl+C again to exit', tone: 'error' } : view.notice ?? (copied ? { text: 'Copied', tone: 'info' } : null),
|
|
310
|
+
keys: view.keys,
|
|
311
|
+
// While main works its throbber names what it does; the trail would only repeat "working".
|
|
312
|
+
trail: options.throbber ? null : view.trail ?? null,
|
|
313
|
+
cost: view.noContext ? null : view.cost ?? null,
|
|
314
|
+
context: null,
|
|
315
|
+
}), 'usage'));
|
|
316
|
+
lastRenderedFooterHeight = lines.length;
|
|
317
|
+
return { lines, height: lines.length };
|
|
246
318
|
}
|
|
247
|
-
|
|
319
|
+
// A click anywhere on the status line (the context bar, the cost) opens Usage.
|
|
320
|
+
lines.push(tagFooterLine(renderStatusLine({
|
|
321
|
+
width: options.width,
|
|
322
|
+
chips,
|
|
323
|
+
notice: options.showExitNotice
|
|
324
|
+
? { text: 'Press Ctrl+C again to exit', tone: 'error' }
|
|
325
|
+
: copied ? { text: 'Copied', tone: 'info' } : null,
|
|
326
|
+
// With text in the composer the next Esc clears it; scrolled back, it returns to the
|
|
327
|
+
// bottom; only an empty composer's Esc at the bottom interrupts.
|
|
328
|
+
busy: options.turnRunning ? { escAction: options.promptText.trim().length > 0 ? 'clear input' : options.backToBottom ? 'back to bottom' : undefined } : null,
|
|
329
|
+
keys: options.workTreeFocused ? WORK_TREE_KEYS : null,
|
|
330
|
+
directory: displayDirectory(options.workingDir, options.homeDirectory),
|
|
331
|
+
branch: options.branch,
|
|
332
|
+
background: {
|
|
333
|
+
agents: options.runningAgentCount,
|
|
334
|
+
processes: options.runningProcessCount,
|
|
335
|
+
focused: options.indicatorFocused,
|
|
336
|
+
progress: options.runningAgentProgress,
|
|
337
|
+
},
|
|
338
|
+
cost: statusCostText(options.usage, options.model),
|
|
339
|
+
// null: the model's window is unknown, and the meter says so; 0 or
|
|
340
|
+
// undefined: no meter (no model yet).
|
|
341
|
+
context: options.contextWindow === null || (options.contextWindow !== undefined && options.contextWindow > 0)
|
|
342
|
+
? {
|
|
343
|
+
usedTokens: options.lastInputTokens ?? 0,
|
|
344
|
+
windowTokens: options.contextWindow,
|
|
345
|
+
compactFraction: options.compactThreshold && options.compactThreshold > 0 ? options.compactThreshold : 0.85,
|
|
346
|
+
}
|
|
347
|
+
: null,
|
|
348
|
+
}), 'usage'));
|
|
349
|
+
lastRenderedFooterHeight = lines.length;
|
|
248
350
|
return { lines, height: lines.length };
|
|
249
351
|
}
|