@pellux/goodvibes-tui 2.0.20 → 2.1.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/CHANGELOG.md +70 -0
- package/README.md +16 -16
- package/docs/README.md +4 -4
- package/docs/foundation-artifacts/operator-contract.json +59 -4
- package/package.json +16 -6
- 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-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/verification-ledger.ts +18 -16
- 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/{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
|
@@ -21,11 +21,9 @@
|
|
|
21
21
|
// The undo/redo stacks stay TUI-side: the service reports how to reverse a
|
|
22
22
|
// rewind (its receipt's undo block), and this module performs the reversal.
|
|
23
23
|
//
|
|
24
|
-
// The confirm step
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// anchor, previews the change, and arms the panel's confirm overlay; the actual
|
|
28
|
-
// y/n handling lives in DiffPanel.handleInput().
|
|
24
|
+
// The confirm step is a question on a Changes preview (ctx.previewChanges):
|
|
25
|
+
// the handler resolves the anchor, shows exactly what changes, and waits for
|
|
26
|
+
// the answer; Esc or closing the preview answers no.
|
|
29
27
|
// ---------------------------------------------------------------------------
|
|
30
28
|
|
|
31
29
|
import {
|
|
@@ -44,7 +42,6 @@ import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
|
44
42
|
import { buildRewindReceiptBlock } from '../../core/rewind-receipt.ts';
|
|
45
43
|
import { getTurnAnchors, type TurnAnchor } from '@pellux/goodvibes-sdk/platform/rewind';
|
|
46
44
|
import { createConversationRewindPort, type ConversationRewindPort } from '../../runtime/conversation-rewind-port.ts';
|
|
47
|
-
import { requirePanelManager } from './runtime-services.ts';
|
|
48
45
|
import { shortId } from './checkpoint-runtime.ts';
|
|
49
46
|
|
|
50
47
|
export type RewindScope = SdkRewindScope;
|
|
@@ -239,7 +236,7 @@ function parseScope(token: string | undefined): RewindScope | null {
|
|
|
239
236
|
// dead-ending on "no completed turns" while /checkpoints and the boot notice
|
|
240
237
|
// both point back here, /rewind falls back to listing and restoring
|
|
241
238
|
// checkpoints directly, a FILES-ONLY restore (there is no turn anchor to
|
|
242
|
-
// join a conversation boundary against), reusing the same diff
|
|
239
|
+
// join a conversation boundary against), reusing the same diff
|
|
243
240
|
// preview/confirm idiom as the turn-anchored path above.
|
|
244
241
|
// ---------------------------------------------------------------------------
|
|
245
242
|
|
|
@@ -304,52 +301,42 @@ async function handleCheckpointOnlyRewind(args: string[], ctx: CommandContext):
|
|
|
304
301
|
}
|
|
305
302
|
const checkpoint = resolved;
|
|
306
303
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
let panel = pm.getAllOpen().find((p) => p.id === 'diff');
|
|
310
|
-
if (!panel) {
|
|
311
|
-
try { panel = pm.open('diff'); } catch { ctx.print('Could not open diff panel.'); return; }
|
|
312
|
-
}
|
|
313
|
-
pm.activateById('diff');
|
|
314
|
-
if (!pm.isVisible()) pm.show();
|
|
315
|
-
ctx.focusPanels?.();
|
|
316
|
-
const diffPanel = panel as InstanceType<typeof DiffPanel>;
|
|
317
|
-
|
|
304
|
+
let diff: string | undefined;
|
|
305
|
+
let note: string | undefined;
|
|
318
306
|
try {
|
|
319
|
-
const
|
|
320
|
-
if (
|
|
321
|
-
else
|
|
307
|
+
const result = await mgr.diff(checkpoint.id);
|
|
308
|
+
if (result.unifiedDiff.trim()) diff = result.unifiedDiff;
|
|
309
|
+
else note = 'The working tree already matches this checkpoint.';
|
|
322
310
|
} catch {
|
|
323
|
-
|
|
311
|
+
note = 'Could not load the checkpoint diff.';
|
|
312
|
+
}
|
|
313
|
+
if (!ctx.previewChanges) {
|
|
314
|
+
ctx.print('Previewing a restore needs the Changes view, which is not available in this session.');
|
|
315
|
+
return;
|
|
324
316
|
}
|
|
325
317
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
ctx.session.conversationManager.addTypedSystemMessage(
|
|
334
|
-
`[Rewind] Restored files from checkpoint ${shortId(checkpoint.id)} ("${checkpoint.label}"). Files only: no turn anchors exist this run, so conversation state is unchanged.`,
|
|
335
|
-
'operational',
|
|
336
|
-
);
|
|
337
|
-
pm.close('diff');
|
|
338
|
-
ctx.focusPrompt?.();
|
|
339
|
-
ctx.renderRequest();
|
|
340
|
-
} catch (err) {
|
|
341
|
-
ctx.print(`Checkpoint restore failed: ${summarizeError(err)}`);
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
onCancel: () => {
|
|
345
|
-
ctx.print('Restore cancelled: nothing changed.');
|
|
346
|
-
pm.close('diff');
|
|
347
|
-
ctx.focusPrompt?.();
|
|
348
|
-
ctx.renderRequest();
|
|
349
|
-
},
|
|
318
|
+
ctx.print(`Previewing checkpoint restore: "${checkpoint.label}" (files only; no conversation state this run). Enter or y restores, n or Esc cancels.`);
|
|
319
|
+
ctx.renderRequest();
|
|
320
|
+
const confirmed = await ctx.previewChanges({
|
|
321
|
+
title: checkpoint.label,
|
|
322
|
+
diff,
|
|
323
|
+
note,
|
|
324
|
+
question: { text: `Restore "${checkpoint.label}"? Files only: no conversation state this run.`, confirmLabel: 'Restore', tone: 'warning' },
|
|
350
325
|
});
|
|
351
|
-
|
|
352
|
-
|
|
326
|
+
if (!confirmed) {
|
|
327
|
+
ctx.print('Restore cancelled: nothing changed.');
|
|
328
|
+
ctx.renderRequest();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
await mgr.restore(checkpoint.id, { safetyCheckpoint: true });
|
|
333
|
+
ctx.session.conversationManager.addTypedSystemMessage(
|
|
334
|
+
`[Rewind] Restored files from checkpoint ${shortId(checkpoint.id)} ("${checkpoint.label}"). Files only: no turn anchors exist this run, so conversation state is unchanged.`,
|
|
335
|
+
'operational',
|
|
336
|
+
);
|
|
337
|
+
} catch (err) {
|
|
338
|
+
ctx.print(`Checkpoint restore failed: ${summarizeError(err)}`);
|
|
339
|
+
}
|
|
353
340
|
ctx.renderRequest();
|
|
354
341
|
}
|
|
355
342
|
|
|
@@ -412,82 +399,68 @@ export function registerRewindRuntimeCommands(registry: CommandRegistry): void {
|
|
|
412
399
|
return;
|
|
413
400
|
}
|
|
414
401
|
|
|
415
|
-
// Preview
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const pm = requirePanelManager(ctx);
|
|
419
|
-
let panel = pm.getAllOpen().find((p) => p.id === 'diff');
|
|
420
|
-
if (!panel) {
|
|
421
|
-
try { panel = pm.open('diff'); } catch { ctx.print('Could not open diff panel.'); return; }
|
|
422
|
-
}
|
|
423
|
-
pm.activateById('diff');
|
|
424
|
-
if (!pm.isVisible()) pm.show();
|
|
425
|
-
ctx.focusPanels?.();
|
|
426
|
-
const diffPanel = panel as InstanceType<typeof DiffPanel>;
|
|
427
|
-
|
|
402
|
+
// Preview what changes in Changes, with the question on it.
|
|
403
|
+
let diff: string | undefined;
|
|
404
|
+
let note: string | undefined;
|
|
428
405
|
const checkpointId = plan.files?.checkpointId ?? null;
|
|
429
406
|
if (filesAvailable && checkpointId && ctx.workspace.workspaceCheckpointManager) {
|
|
430
407
|
try {
|
|
431
|
-
const
|
|
432
|
-
if (
|
|
433
|
-
else
|
|
408
|
+
const result = await ctx.workspace.workspaceCheckpointManager.diff(checkpointId);
|
|
409
|
+
if (result.unifiedDiff.trim()) diff = result.unifiedDiff;
|
|
410
|
+
else note = 'The working tree already matches this checkpoint.';
|
|
434
411
|
} catch {
|
|
435
|
-
|
|
412
|
+
note = 'Could not load the checkpoint diff.';
|
|
436
413
|
}
|
|
437
414
|
} else {
|
|
438
415
|
const drop = plan.conversation?.messagesToDrop ?? 0;
|
|
439
416
|
const remaining = plan.conversation?.messagesRemaining ?? 0;
|
|
440
|
-
|
|
441
|
-
`Conversation rewind: drop ${drop} message(s)`,
|
|
442
|
-
`@@ rewind @@\n Keep ${remaining} message(s), drop ${drop} after this turn. No files change.`,
|
|
443
|
-
);
|
|
417
|
+
note = `Conversation rewind: keep ${remaining} message(s), drop ${drop} after this turn. No files change.`;
|
|
444
418
|
}
|
|
445
419
|
|
|
446
420
|
const summaryParts: string[] = [];
|
|
447
421
|
if (wants(scope, 'files')) summaryParts.push(filesAvailable ? `${plan.files?.affectedFileCount ?? 0} file(s)` : 'files: none');
|
|
448
422
|
if (wants(scope, 'conversation')) summaryParts.push(conversationAvailable ? `${plan.conversation?.messagesToDrop ?? 0} message(s)` : 'conversation: unavailable');
|
|
423
|
+
if (!ctx.previewChanges) {
|
|
424
|
+
ctx.print('Previewing a rewind needs the Changes view, which is not available in this session.');
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
449
427
|
|
|
450
|
-
|
|
451
|
-
id: anchor.turnId ?? sessionId,
|
|
452
|
-
label: `${resolved.label}: rewind ${scope} (${summaryParts.join(', ')})`,
|
|
453
|
-
verb: 'Rewind',
|
|
454
|
-
onConfirm: async () => {
|
|
455
|
-
try {
|
|
456
|
-
const result = await state.service.apply(anchor, scope, { confirmToken: plan.token });
|
|
457
|
-
const receipt = result.receipt;
|
|
458
|
-
if (!receipt) {
|
|
459
|
-
ctx.print(`Rewind not applied: ${result.refusal?.reason ?? 'confirmation was refused.'}`);
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
if (undoAvailable(receipt)) {
|
|
463
|
-
state.undo.push(receipt);
|
|
464
|
-
state.redo.length = 0; // a fresh apply invalidates the redo stack
|
|
465
|
-
}
|
|
466
|
-
// addTypedSystemMessage persists the receipt into real session
|
|
467
|
-
// history (indexed by getTranscriptEventIndex + save/load), and the
|
|
468
|
-
// [Rewind] prefix is force-surfaced inline (system-message-router.ts).
|
|
469
|
-
ctx.session.conversationManager.addTypedSystemMessage(
|
|
470
|
-
buildRewindReceiptBlock({ ...receipt, undoAvailable: undoAvailable(receipt) }),
|
|
471
|
-
'operational',
|
|
472
|
-
);
|
|
473
|
-
pm.close('diff');
|
|
474
|
-
ctx.focusPrompt?.();
|
|
475
|
-
ctx.renderRequest();
|
|
476
|
-
} catch (err) {
|
|
477
|
-
ctx.print(`Rewind failed: ${summarizeError(err)}`);
|
|
478
|
-
}
|
|
479
|
-
},
|
|
480
|
-
onCancel: () => {
|
|
481
|
-
ctx.print('Rewind cancelled: nothing changed.');
|
|
482
|
-
pm.close('diff');
|
|
483
|
-
ctx.focusPrompt?.();
|
|
484
|
-
ctx.renderRequest();
|
|
485
|
-
},
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
ctx.print(`Previewing rewind of turn "${resolved.label}" (${scope}: ${summaryParts.join(', ')}). Confirm in the diff panel: Enter/y to rewind, n/Esc to cancel.`);
|
|
428
|
+
ctx.print(`Previewing rewind of turn "${resolved.label}" (${scope}: ${summaryParts.join(', ')}). Enter or y rewinds, n or Esc cancels.`);
|
|
489
429
|
for (const w of plan.warnings) ctx.print(` note: ${w}`);
|
|
490
430
|
ctx.renderRequest();
|
|
431
|
+
const confirmed = await ctx.previewChanges({
|
|
432
|
+
title: `rewind ${resolved.label}`,
|
|
433
|
+
diff,
|
|
434
|
+
note,
|
|
435
|
+
question: { text: `Rewind ${scope} to "${resolved.label}"? (${summaryParts.join(', ')})`, confirmLabel: 'Rewind', tone: 'warning' },
|
|
436
|
+
});
|
|
437
|
+
if (!confirmed) {
|
|
438
|
+
ctx.print('Rewind cancelled: nothing changed.');
|
|
439
|
+
ctx.renderRequest();
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const result = await state.service.apply(anchor, scope, { confirmToken: plan.token });
|
|
444
|
+
const receipt = result.receipt;
|
|
445
|
+
if (!receipt) {
|
|
446
|
+
ctx.print(`Rewind not applied: ${result.refusal?.reason ?? 'confirmation was refused.'}`);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (undoAvailable(receipt)) {
|
|
450
|
+
state.undo.push(receipt);
|
|
451
|
+
state.redo.length = 0; // a fresh apply invalidates the redo stack
|
|
452
|
+
}
|
|
453
|
+
// addTypedSystemMessage persists the receipt into real session
|
|
454
|
+
// history (indexed by getTranscriptEventIndex + save/load), and the
|
|
455
|
+
// [Rewind] prefix is force-surfaced inline (system-message-router.ts).
|
|
456
|
+
ctx.session.conversationManager.addTypedSystemMessage(
|
|
457
|
+
buildRewindReceiptBlock({ ...receipt, undoAvailable: undoAvailable(receipt) }),
|
|
458
|
+
'operational',
|
|
459
|
+
);
|
|
460
|
+
ctx.renderRequest();
|
|
461
|
+
} catch (err) {
|
|
462
|
+
ctx.print(`Rewind failed: ${summarizeError(err)}`);
|
|
463
|
+
}
|
|
491
464
|
},
|
|
492
465
|
});
|
|
493
466
|
}
|
|
@@ -104,21 +104,21 @@ export function requirePluginPathOptions(
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Open the modal that holds a view, by its current or old name (views.ts):
|
|
109
|
+
* 'fleet' and 'worktrees' open Agents, 'cost' opens Usage, and so on.
|
|
110
|
+
*/
|
|
111
|
+
export function openCommandView(
|
|
112
|
+
context: Pick<CommandContext, 'openView' | 'print'>,
|
|
113
|
+
name: string,
|
|
111
114
|
): void {
|
|
112
|
-
const
|
|
113
|
-
|
|
115
|
+
const openView = requireContextValue(context.openView, 'openView');
|
|
116
|
+
if (!openView(name)) context.print(`Nothing holds "${name}" in this build.`);
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* "not available yet" implementation with real dispatch). Front-doors for
|
|
120
|
-
* panels that migrated to modals call this instead of openCommandPanel, the
|
|
121
|
-
* modal is the surface's new home. Stubbed in tests by setting ctx.openModal.
|
|
120
|
+
* Open a config-modal surface by name via the ctx.openModal seam (ui-openers
|
|
121
|
+
* wires it). Stubbed in tests by setting ctx.openModal.
|
|
122
122
|
*/
|
|
123
123
|
export function openModalCommand(
|
|
124
124
|
context: Pick<CommandContext, 'openModal'>,
|
|
@@ -145,10 +145,6 @@ export function requireProfileManager(context: CommandContext) {
|
|
|
145
145
|
return requireContextValue(context.workspace.profileManager, 'workspace.profileManager');
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
export function requirePanelManager(context: CommandContext) {
|
|
149
|
-
return requireContextValue(context.workspace.panelManager, 'workspace.panelManager');
|
|
150
|
-
}
|
|
151
|
-
|
|
152
148
|
export function requireBookmarkManager(context: CommandContext) {
|
|
153
149
|
return requireContextValue(context.workspace.bookmarkManager, 'workspace.bookmarkManager');
|
|
154
150
|
}
|
|
@@ -283,9 +279,11 @@ export async function compactConversation(context: CommandContext): Promise<Comp
|
|
|
283
279
|
// Resolve the live context window for the current model so manual /compact
|
|
284
280
|
// matches the auto-compaction path (which scales behaviour by window size)
|
|
285
281
|
// instead of passing a meaningless 0.
|
|
286
|
-
|
|
282
|
+
// 0 when the window is unknown (a guess, or disproven by a larger accepted
|
|
283
|
+
// request): an unknown window is never treated as a small one.
|
|
284
|
+
const contextWindow = providerRegistry.getKnownContextWindowForModel(
|
|
287
285
|
providerRegistry.getCurrentModel(),
|
|
288
|
-
);
|
|
286
|
+
) ?? 0;
|
|
289
287
|
|
|
290
288
|
// Small-window models lack room for the structured (multi-LLM) extraction
|
|
291
289
|
// pipeline, so mirror the SDK auto-compaction path and degrade to the
|
|
@@ -3,7 +3,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
3
3
|
import { atomicWriteFileSync } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
4
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
5
5
|
import type { SelectionAction, SelectionItem } from '../selection-modal.ts';
|
|
6
|
-
import {
|
|
6
|
+
import { requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
|
|
7
7
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
8
8
|
|
|
9
9
|
export function registerServicesRuntimeCommands(registry: CommandRegistry): void {
|
|
@@ -16,7 +16,7 @@ export function registerServicesRuntimeCommands(registry: CommandRegistry): void
|
|
|
16
16
|
const sub = args[0] ?? 'open';
|
|
17
17
|
const shellPaths = requireShellPaths(ctx);
|
|
18
18
|
if (sub === 'open' || sub === 'panel') {
|
|
19
|
-
ctx.openModal?.('services-modal'); // services
|
|
19
|
+
ctx.openModal?.('services-modal'); // services view -> config modal
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const svcRegistry = requireServiceRegistry(ctx);
|
|
@@ -280,15 +280,31 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
280
280
|
ctx.openSelection('Sessions', items, { allowSearch: true, customActions: deleteAction }, (result) => {
|
|
281
281
|
if (!result) return;
|
|
282
282
|
if (result.action === 'delete') {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
283
|
+
const sessionInfo = sessions.find(s => s.name === result.item.id);
|
|
284
|
+
if (!sessionInfo) return;
|
|
285
|
+
const remove = (): void => {
|
|
286
|
+
try {
|
|
286
287
|
unlinkSync(sessionInfo.filePath);
|
|
287
288
|
ctx.print(`Session deleted: ${result.item.id}`);
|
|
289
|
+
} catch (e) {
|
|
290
|
+
ctx.print(`Failed to delete session: ${summarizeError(e)}`);
|
|
288
291
|
}
|
|
289
|
-
|
|
290
|
-
|
|
292
|
+
ctx.renderRequest();
|
|
293
|
+
};
|
|
294
|
+
// Deleting is permanent, so it asks first where a confirm dialog exists.
|
|
295
|
+
if (!ctx.confirm) {
|
|
296
|
+
remove();
|
|
297
|
+
return;
|
|
291
298
|
}
|
|
299
|
+
void ctx.confirm({
|
|
300
|
+
title: 'Delete session?',
|
|
301
|
+
body: `This removes "${sessionInfo.name}" and its ${sessionInfo.messageCount} message${sessionInfo.messageCount === 1 ? '' : 's'} from this project.\nIt cannot be undone.`,
|
|
302
|
+
confirmLabel: 'Delete',
|
|
303
|
+
tone: 'danger',
|
|
304
|
+
}).then((confirmed) => {
|
|
305
|
+
if (confirmed) remove();
|
|
306
|
+
else ctx.renderRequest();
|
|
307
|
+
});
|
|
292
308
|
} else {
|
|
293
309
|
try {
|
|
294
310
|
const { meta, messages } = sessionManager.load(result.item.id);
|
|
@@ -5,9 +5,9 @@ import { type SessionMeta } from '@pellux/goodvibes-sdk/platform/sessions';
|
|
|
5
5
|
import type { TranscriptEventKind } from '@pellux/goodvibes-sdk/platform/core';
|
|
6
6
|
import type { ConversationTitleSource } from '../../core/conversation';
|
|
7
7
|
import type { SessionReturnContextSummary } from '@/runtime/index.ts';
|
|
8
|
-
import { formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
|
|
9
|
-
import {
|
|
10
|
-
import { resumeSessionCore
|
|
8
|
+
import { formatReturnContextForDisplay, getReturnContextMode, loadedReturnContext, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
|
|
9
|
+
import { requireProviderApi, requireSessionManager, requireSurface } from './runtime-services.ts';
|
|
10
|
+
import { resumeSessionCore } from '../../core/session-resume-core.ts';
|
|
11
11
|
import { checkSessionLiveness } from '@pellux/goodvibes-sdk/platform/runtime/operations';
|
|
12
12
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
13
13
|
|
|
@@ -80,24 +80,6 @@ function buildTranscriptReviewLines(
|
|
|
80
80
|
];
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// Exported (test-only concern) so the MIGRATE-TO-MODAL redirect-skip honesty
|
|
84
|
-
// (W6 review, finding 3: saved-layout restore with 'sessions' must not lie)
|
|
85
|
-
// can be unit-tested directly instead of through a full /resume harness.
|
|
86
|
-
// Delegates to the shared reopenPanelsWithModalSkip (core/session-resume-core.ts)
|
|
87
|
-
//, the same routine resumeSessionCore uses, so this standalone entry point
|
|
88
|
-
// and the canonical resume sequence can never diverge on panel-reopen behavior.
|
|
89
|
-
export function reopenPanelsFromReturnContext(ctx: CommandContext, summary: SessionReturnContextSummary | undefined): string[] {
|
|
90
|
-
if (!summary?.openPanels || summary.openPanels.length === 0) return [];
|
|
91
|
-
const panelManager = requirePanelManager(ctx);
|
|
92
|
-
const { reopened, movedToModal, notReopened } = reopenPanelsWithModalSkip(panelManager, summary.openPanels, DEFAULT_PANEL_REOPEN_LIMIT);
|
|
93
|
-
if (movedToModal.length > 0) {
|
|
94
|
-
ctx.print(`Note: ${movedToModal.join(', ')} moved to a modal; reopen via its command instead of as a panel.`);
|
|
95
|
-
}
|
|
96
|
-
if (notReopened.length > 0) {
|
|
97
|
-
ctx.print(` …and ${notReopened.length} more not reopened (/panels to open)`);
|
|
98
|
-
}
|
|
99
|
-
return [...reopened];
|
|
100
|
-
}
|
|
101
83
|
|
|
102
84
|
function printSessionExport(
|
|
103
85
|
ctx: { print: (text: string) => void },
|
|
@@ -181,14 +163,11 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
181
163
|
const model = session.model ? ` [${session.model}]` : '';
|
|
182
164
|
const active = session.name === ctx.session.runtime.sessionId ? ' ●' : ' ';
|
|
183
165
|
lines.push(`${active} ${session.name.padEnd(28)} ${name.slice(0, 22).padEnd(22)} ${date} ${session.messageCount} msgs${model}`);
|
|
184
|
-
if (session.returnContext?.activeTasks || session.returnContext?.blockedTasks || session.returnContext?.pendingApprovals
|
|
166
|
+
if (session.returnContext?.activeTasks || session.returnContext?.blockedTasks || session.returnContext?.pendingApprovals) {
|
|
185
167
|
const posture = [
|
|
186
168
|
session.returnContext.activeTasks ? `active=${session.returnContext.activeTasks}` : null,
|
|
187
169
|
session.returnContext.blockedTasks ? `blocked=${session.returnContext.blockedTasks}` : null,
|
|
188
170
|
session.returnContext.pendingApprovals ? `approvals=${session.returnContext.pendingApprovals}` : null,
|
|
189
|
-
session.returnContext.openPanels?.length
|
|
190
|
-
? `panels=${session.returnContext.openPanels.slice(0, 3).join(',')}${session.returnContext.openPanels.length > 3 ? ` (+${session.returnContext.openPanels.length - 3} more)` : ''}`
|
|
191
|
-
: null,
|
|
192
171
|
].filter(Boolean).join(' ');
|
|
193
172
|
if (posture) lines.push(` posture: ${posture}`);
|
|
194
173
|
}
|
|
@@ -270,11 +249,10 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
270
249
|
conversation: ctx.session.conversationManager,
|
|
271
250
|
runtime: ctx.session.runtime,
|
|
272
251
|
surface: requireSurface(ctx),
|
|
273
|
-
panelManager: requirePanelManager(ctx),
|
|
274
252
|
selectModel: (model) => providerApi.selectModel(model),
|
|
275
253
|
hydrateSessionUsage: ctx.session.hydrateSessionUsage,
|
|
276
254
|
});
|
|
277
|
-
const { meta, journalReplay, restoredAnchorCount, resumedMessageCount
|
|
255
|
+
const { meta, journalReplay, restoredAnchorCount, resumedMessageCount } = outcome;
|
|
278
256
|
|
|
279
257
|
ctx.renderRequest();
|
|
280
258
|
ctx.print(`Resumed session: ${found.name}\n Name: ${meta.title || '(untitled)'}\n Messages: ${resumedMessageCount}\n Model: ${meta.model || ctx.session.runtime.model}`);
|
|
@@ -289,20 +267,13 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
289
267
|
} else if (journalReplay.hadCorruptTail) {
|
|
290
268
|
ctx.print(' [Recovery] Journal tail was partially corrupt (quarantined). Replay stopped at last good record.');
|
|
291
269
|
}
|
|
292
|
-
if (panels.movedToModal.length > 0) {
|
|
293
|
-
ctx.print(`Note: ${panels.movedToModal.join(', ')} moved to a modal; reopen via its command instead of as a panel.`);
|
|
294
|
-
}
|
|
295
|
-
if (panels.notReopened.length > 0) {
|
|
296
|
-
ctx.print(` …and ${panels.notReopened.length} more not reopened (/panels to open)`);
|
|
297
|
-
}
|
|
298
270
|
const returnContextMode = getReturnContextMode(ctx.platform.configManager);
|
|
299
271
|
if (returnContextMode !== 'off' && meta.returnContext) {
|
|
272
|
+
// The SDK's session loader already dropped any legacy open-view list from a
|
|
273
|
+
// session saved by an older TUI, so the loaded return context is shown as-is.
|
|
300
274
|
for (const line of formatReturnContextForDisplay(meta.returnContext)) {
|
|
301
275
|
ctx.print(` ${line}`);
|
|
302
276
|
}
|
|
303
|
-
if (panels.reopened.length > 0) {
|
|
304
|
-
ctx.print(` Reopened panels: ${panels.reopened.join(', ')}`);
|
|
305
|
-
}
|
|
306
277
|
if ((meta.returnContext.remoteRunners?.length ?? 0) > 0) {
|
|
307
278
|
ctx.print(` Remote re-entry: /remote recover ${meta.returnContext.remoteRunners![0]}`);
|
|
308
279
|
}
|
|
@@ -336,7 +307,9 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
336
307
|
provider: ctx.session.runtime.provider,
|
|
337
308
|
timestamp: Date.now(),
|
|
338
309
|
titleSource: exportData.titleSource,
|
|
339
|
-
|
|
310
|
+
// Same shape a session file is read back in: a legacy open-view list
|
|
311
|
+
// (from an older session file) is never written again.
|
|
312
|
+
returnContext: loadedReturnContext(exportData.returnContext),
|
|
340
313
|
// The operator asked for this fork by name; it is not turn machinery.
|
|
341
314
|
saveSource: 'user',
|
|
342
315
|
};
|
|
@@ -362,7 +335,9 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
|
|
|
362
335
|
provider: ctx.session.runtime.provider,
|
|
363
336
|
timestamp: Date.now(),
|
|
364
337
|
titleSource: exportData.titleSource,
|
|
365
|
-
|
|
338
|
+
// Same shape a session file is read back in: a legacy open-view list
|
|
339
|
+
// (from an older session file) is never written again.
|
|
340
|
+
returnContext: loadedReturnContext(exportData.returnContext),
|
|
366
341
|
// The one unambiguous "keep this" act in the app. Marked so the
|
|
367
342
|
// session-conversations retention sweep never expires it, unlike the
|
|
368
343
|
// automatic per-turn snapshot (turn-event-wiring.ts, saveSource 'auto').
|
|
@@ -19,7 +19,7 @@ import { getProviderIdFromModel } from '@pellux/goodvibes-sdk/platform/providers
|
|
|
19
19
|
import { type ConfigKey } from '@pellux/goodvibes-sdk/platform/config';
|
|
20
20
|
import { CONFIG_KEYS } from '@pellux/goodvibes-sdk/platform/config';
|
|
21
21
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
22
|
-
import {
|
|
22
|
+
import { requireShellPaths } from './runtime-services.ts';
|
|
23
23
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
24
24
|
|
|
25
25
|
export function registerSettingsSyncRuntimeCommands(registry: CommandRegistry): void {
|
|
@@ -41,7 +41,7 @@ export function registerSettingsSyncRuntimeCommands(registry: CommandRegistry):
|
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
if (sub === 'panel' || sub === 'open') {
|
|
44
|
-
ctx.openModal?.('settings-sync-modal'); // settings-sync
|
|
44
|
+
ctx.openModal?.('settings-sync-modal'); // settings-sync view -> config modal
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
if (sub === 'report' || sub === 'review') {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
toEffortModel,
|
|
13
13
|
} from '../../providers/reasoning-effort-surface.ts';
|
|
14
14
|
import { executeWriteQuit } from './quit-shared.ts';
|
|
15
|
+
import { startFreshConversation, type FreshConversationResult } from './fresh-conversation.ts';
|
|
15
16
|
import { compactConversation, requireKeybindingsManager, requireProviderApi, requireSessionMemoryStore } from './runtime-services.ts';
|
|
16
17
|
import { buildCompactionPreview, buildCompactionAfterNotice, buildPinUsageText, buildPinSuccessText } from '../../renderer/compaction-preview.ts';
|
|
17
18
|
import { buildCompactionHistoryText } from '../../renderer/compaction-history-modal.ts';
|
|
@@ -242,9 +243,22 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
242
243
|
registry.register({
|
|
243
244
|
name: 'clear',
|
|
244
245
|
aliases: ['cls'],
|
|
245
|
-
description: '
|
|
246
|
+
description: 'Start a fresh conversation (the current one is saved as its own session)',
|
|
246
247
|
handler(_args, ctx) {
|
|
247
|
-
ctx.
|
|
248
|
+
if (ctx.isGenerating?.()) {
|
|
249
|
+
ctx.print('A turn is still running. Stop it with Esc or let it finish, then /clear.');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
let result: FreshConversationResult;
|
|
253
|
+
try {
|
|
254
|
+
result = startFreshConversation(ctx);
|
|
255
|
+
} catch (e) {
|
|
256
|
+
ctx.print(`Could not save the current conversation, so nothing was cleared: ${summarizeError(e)}`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (result.savedAs) {
|
|
260
|
+
ctx.showToast?.({ title: 'Fresh conversation', body: `The previous one is saved as ${result.savedAs}. /session resume ${result.savedAs} returns to it.`, tone: 'info' });
|
|
261
|
+
}
|
|
248
262
|
ctx.renderRequest();
|
|
249
263
|
},
|
|
250
264
|
});
|
|
@@ -274,9 +288,10 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
274
288
|
// its own behaviour by window size. Previously hardcoded to 0 here, which
|
|
275
289
|
// silently suppressed buildCompactionPreview()'s capacity-% clause even
|
|
276
290
|
// though the builder has always supported it.
|
|
277
|
-
|
|
291
|
+
// 0 when the window is unknown: the preview then leaves out the capacity clause.
|
|
292
|
+
const contextWindow = ctx.provider.providerRegistry.getKnownContextWindowForModel(
|
|
278
293
|
ctx.provider.providerRegistry.getCurrentModel(),
|
|
279
|
-
);
|
|
294
|
+
) ?? 0;
|
|
280
295
|
const memStore = ctx.session.sessionMemoryStore;
|
|
281
296
|
const pinnedMemoryCount = memStore ? memStore.list().length : 0;
|
|
282
297
|
// Pre-compact preview: honest estimate, clearly labelled.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
-
import { discoverSkills } from '../../
|
|
2
|
+
import { discoverSkills } from '../../views/skills-discovery.ts';
|
|
3
3
|
import {
|
|
4
4
|
installEcosystemCatalogEntry,
|
|
5
5
|
listInstalledEcosystemEntries,
|
|
@@ -169,7 +169,7 @@ export function registerSkillsRuntimeCommands(registry: CommandRegistry): void {
|
|
|
169
169
|
` source: ${entry.source}`,
|
|
170
170
|
` tags: ${entry.tags.join(', ') || '(none)'}`,
|
|
171
171
|
` trust notes: ${entry.trustNotes ?? '(none)'}`,
|
|
172
|
-
` install hint: ${entry.installHint ?? 'Place the skill pack under a configured skill directory and refresh the skills
|
|
172
|
+
` install hint: ${entry.installHint ?? 'Place the skill pack under a configured skill directory and refresh the skills modal.'}`,
|
|
173
173
|
].join('\n'));
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
|
|
3
|
+
/** /status, everything the footer used to carry, in one report (shell/status-report.ts). */
|
|
4
|
+
export function registerStatusRuntimeCommands(registry: CommandRegistry): void {
|
|
5
|
+
registry.register({
|
|
6
|
+
name: 'status',
|
|
7
|
+
aliases: [],
|
|
8
|
+
description: 'Show session status: model, tools, token totals and cost, context use, surfaces and safety states',
|
|
9
|
+
handler(_args, ctx) {
|
|
10
|
+
ctx.print(ctx.describeStatus ? ctx.describeStatus() : 'Status is not available in this runtime.');
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -80,7 +80,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
80
80
|
async handler(args, ctx) {
|
|
81
81
|
const shellPaths = requireShellPaths(ctx);
|
|
82
82
|
if (args.length === 0 && ctx.openModal) {
|
|
83
|
-
ctx.openModal('subscription-modal'); // subscription
|
|
83
|
+
ctx.openModal('subscription-modal'); // subscription view -> config modal
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
const sub = (args[0] ?? 'review').toLowerCase();
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import type { CommandRegistry, CommandContext } from '../command-registry.ts';
|
|
24
24
|
import type { RuntimeTask, TaskLifecycleState } from '@/runtime/index.ts';
|
|
25
25
|
import { reviewWorktreeAttachments } from '@/runtime/index.ts';
|
|
26
|
-
import { requireOperatorClient, requireOpsApi,
|
|
26
|
+
import { requireOperatorClient, requireOpsApi, requireShellPaths } from './runtime-services.ts';
|
|
27
27
|
import { createTasksClient, type TasksClient, type UnionTask } from '@pellux/goodvibes-sdk/platform/runtime/client';
|
|
28
28
|
import { createDaemonVerbCaller } from '../../runtime/client/operator-endpoint.ts';
|
|
29
29
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
@@ -85,13 +85,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
85
85
|
usage: '[list [status|kind] | show <taskId> | output <taskId> | create <kind> <owner> <title...> | update <taskId> <title|description|result> <value...> | complete <taskId> [result] | fail <taskId> <error...> | cancel <taskId> [note] | pause <taskId> [note] | resume <taskId> [note] | retry <taskId> [note]]',
|
|
86
86
|
async handler(args, ctx) {
|
|
87
87
|
if (args.length === 0) {
|
|
88
|
-
if (ctx.
|
|
89
|
-
else {
|
|
90
|
-
const panelManager = requirePanelManager(ctx);
|
|
91
|
-
panelManager.open('tasks');
|
|
92
|
-
panelManager.show();
|
|
93
|
-
ctx.renderRequest();
|
|
94
|
-
}
|
|
88
|
+
if (!ctx.openView?.('tasks')) ctx.print('The Agents view is not available in this session; /tasks list prints them.');
|
|
95
89
|
return;
|
|
96
90
|
}
|
|
97
91
|
|
|
@@ -24,7 +24,7 @@ function getStore(ctx: import('../command-registry.ts').CommandContext): WorkPla
|
|
|
24
24
|
return ctx.workspace.workPlanStore ?? null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function
|
|
27
|
+
function openWorkPlanModal(ctx: import('../command-registry.ts').CommandContext): void {
|
|
28
28
|
// work-plan migrated to the 'work-plan' modal, open it via the seam.
|
|
29
29
|
openModalCommand(ctx, 'work-plan-modal');
|
|
30
30
|
}
|
|
@@ -86,8 +86,8 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
86
86
|
const subcommand = (args[0] ?? 'panel').toLowerCase();
|
|
87
87
|
try {
|
|
88
88
|
if (subcommand === 'panel' || subcommand === 'open') {
|
|
89
|
-
|
|
90
|
-
ctx.print('Opened work plan
|
|
89
|
+
openWorkPlanModal(ctx);
|
|
90
|
+
ctx.print('Opened the work plan.');
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
if (subcommand === 'list') {
|
|
@@ -118,7 +118,7 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
118
118
|
...(parsed.notes ? { notes: parsed.notes } : {}),
|
|
119
119
|
};
|
|
120
120
|
const item = store.addItem(parsed.title, addOptions);
|
|
121
|
-
|
|
121
|
+
openWorkPlanModal(ctx);
|
|
122
122
|
ctx.print(`Added work plan item ${item.id}.`);
|
|
123
123
|
return;
|
|
124
124
|
}
|