@pellux/goodvibes-tui 1.1.0 → 1.7.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 +85 -21
- package/README.md +20 -11
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +2 -2
- package/src/core/alert-gating.ts +67 -0
- package/src/core/approval-alert.ts +72 -0
- package/src/core/budget-breach-notifier.ts +106 -0
- package/src/core/conversation-rendering.ts +19 -0
- package/src/core/conversation.ts +18 -0
- package/src/core/focus-tracker.ts +41 -0
- package/src/core/long-task-notifier.ts +33 -6
- package/src/core/system-message-router.ts +37 -51
- package/src/core/turn-cancellation.ts +20 -0
- package/src/core/turn-event-wiring.ts +64 -3
- package/src/export/cost-utils.ts +36 -0
- package/src/input/command-registry.ts +38 -1
- package/src/input/commands/checkpoint-runtime.ts +280 -0
- package/src/input/commands/codebase-runtime.ts +192 -0
- package/src/input/commands/eval.ts +1 -1
- package/src/input/commands/health-runtime.ts +1 -1
- package/src/input/commands/image-runtime.ts +112 -0
- package/src/input/commands/intelligence-runtime.ts +11 -1
- package/src/input/commands/local-auth-runtime.ts +4 -1
- package/src/input/commands/local-runtime.ts +9 -3
- package/src/input/commands/marketplace-runtime.ts +2 -2
- package/src/input/commands/memory.ts +6 -1
- package/src/input/commands/operator-panel-runtime.ts +40 -24
- package/src/input/commands/planning-runtime.ts +26 -3
- package/src/input/commands/platform-sandbox-runtime.ts +1 -6
- package/src/input/commands/plugin-runtime.ts +2 -2
- package/src/input/commands/policy-dispatch.ts +21 -0
- package/src/input/commands/provider-accounts-runtime.ts +1 -1
- package/src/input/commands/qrcode-runtime.ts +3 -3
- package/src/input/commands/recall-review.ts +35 -0
- package/src/input/commands/remote-runtime.ts +3 -3
- package/src/input/commands/runtime-services.ts +54 -13
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +16 -1
- package/src/input/commands/settings-sync-runtime.ts +1 -1
- package/src/input/commands/shell-core.ts +15 -7
- package/src/input/commands/skills-runtime.ts +2 -8
- package/src/input/commands/subscription-runtime.ts +2 -2
- package/src/input/commands/test-runtime.ts +277 -0
- package/src/input/commands/websearch-runtime.ts +101 -0
- package/src/input/commands/work-plan-runtime.ts +36 -10
- package/src/input/commands/workstream-runtime.ts +338 -0
- package/src/input/commands.ts +12 -0
- package/src/input/config-modal-types.ts +161 -0
- package/src/input/config-modal.ts +377 -0
- package/src/input/feed-context-factory.ts +7 -8
- package/src/input/handler-command-route.ts +27 -17
- package/src/input/handler-feed-routes.ts +61 -23
- package/src/input/handler-feed.ts +47 -23
- package/src/input/handler-interactions.ts +1 -3
- package/src/input/handler-modal-routes.ts +65 -0
- package/src/input/handler-modal-stack.ts +3 -5
- package/src/input/handler-modal-token-routes.ts +16 -49
- package/src/input/handler-picker-routes.ts +11 -94
- package/src/input/handler-shortcuts.ts +24 -14
- package/src/input/handler-types.ts +2 -6
- package/src/input/handler-ui-state.ts +10 -22
- package/src/input/handler.ts +6 -28
- package/src/input/keybindings.ts +22 -8
- package/src/input/model-picker-types.ts +24 -6
- package/src/input/model-picker.ts +58 -0
- package/src/input/panel-integration-actions.ts +9 -170
- package/src/input/settings-modal-data.ts +95 -0
- package/src/input/settings-modal-mutations.ts +6 -4
- package/src/main.ts +24 -27
- package/src/panels/agent-inspector-shared.ts +2 -1
- package/src/panels/base-panel.ts +22 -1
- package/src/panels/builtin/agent.ts +21 -107
- package/src/panels/builtin/development.ts +15 -61
- package/src/panels/builtin/knowledge.ts +8 -32
- package/src/panels/builtin/operations.ts +84 -428
- package/src/panels/builtin/session.ts +21 -112
- package/src/panels/builtin/shared.ts +9 -43
- package/src/panels/builtin-modals.ts +218 -0
- package/src/panels/builtin-panels.ts +5 -0
- package/src/panels/cost-tracker-panel.ts +36 -10
- package/src/panels/diff-panel.ts +12 -43
- package/src/panels/eval-registry.ts +60 -0
- package/src/panels/fleet-panel.ts +800 -0
- package/src/panels/fleet-read-model.ts +477 -0
- package/src/panels/fleet-steer.ts +92 -0
- package/src/panels/fleet-stop.ts +125 -0
- package/src/panels/fleet-tabs.ts +230 -0
- package/src/panels/fleet-transcript.ts +356 -0
- package/src/panels/index.ts +7 -31
- package/src/panels/modals/hooks-modal.ts +187 -0
- package/src/panels/modals/keybindings-modal.ts +151 -0
- package/src/panels/modals/knowledge-modal.ts +158 -0
- package/src/panels/modals/local-auth-modal.ts +132 -0
- package/src/panels/modals/marketplace-modal.ts +218 -0
- package/src/panels/modals/memory-modal.ts +180 -0
- package/src/panels/modals/modal-surface-helpers.ts +54 -0
- package/src/panels/modals/modal-theme.ts +36 -0
- package/src/panels/modals/pairing-modal.ts +144 -0
- package/src/panels/modals/planning-modal.ts +282 -0
- package/src/panels/modals/plugins-modal.ts +174 -0
- package/src/panels/modals/policy-modal.ts +256 -0
- package/src/panels/modals/provider-health-modal.ts +136 -0
- package/src/panels/modals/remote-modal.ts +115 -0
- package/src/panels/modals/sandbox-modal.ts +150 -0
- package/src/panels/modals/security-modal.ts +217 -0
- package/src/panels/modals/services-modal.ts +179 -0
- package/src/panels/modals/settings-sync-modal.ts +142 -0
- package/src/panels/modals/skills-modal.ts +189 -0
- package/src/panels/modals/subscription-modal.ts +172 -0
- package/src/panels/modals/work-plan-modal.ts +149 -0
- package/src/panels/panel-confirm-overlay.ts +72 -0
- package/src/panels/panel-manager.ts +108 -5
- package/src/panels/project-planning-answer-actions.ts +4 -2
- package/src/panels/skills-panel.ts +7 -51
- package/src/panels/types.ts +13 -0
- package/src/permissions/hunk-selection.ts +179 -0
- package/src/permissions/prompt.ts +60 -4
- package/src/renderer/compaction-history-modal.ts +19 -3
- package/src/renderer/compaction-preview.ts +13 -2
- package/src/renderer/compaction-quality.ts +100 -0
- package/src/renderer/config-modal.ts +81 -0
- package/src/renderer/conversation-overlays.ts +10 -17
- package/src/renderer/fleet-tab-strip.ts +56 -0
- package/src/renderer/footer-tips.ts +10 -2
- package/src/renderer/git-status.ts +40 -0
- package/src/renderer/help-overlay.ts +2 -2
- package/src/renderer/model-workspace.ts +44 -1
- package/src/renderer/panel-workspace-bar.ts +8 -2
- package/src/renderer/turn-injection.ts +114 -0
- package/src/runtime/bootstrap-command-context.ts +21 -1
- package/src/runtime/bootstrap-command-parts.ts +34 -7
- package/src/runtime/bootstrap-core.ts +14 -4
- package/src/runtime/bootstrap-shell.ts +29 -16
- package/src/runtime/bootstrap.ts +11 -17
- package/src/runtime/code-index-services.ts +112 -0
- package/src/runtime/orchestrator-core-services.ts +49 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/services.ts +91 -43
- package/src/runtime/ui-services.ts +8 -0
- package/src/runtime/workstream-services.ts +195 -0
- package/src/shell/blocking-input.ts +22 -1
- package/src/shell/ui-openers.ts +129 -17
- package/src/utils/format-duration.ts +8 -18
- package/src/utils/splash-lines.ts +1 -1
- package/src/version.ts +1 -1
- package/src/panels/agent-inspector-panel.ts +0 -786
- package/src/panels/approval-panel.ts +0 -252
- package/src/panels/automation-control-panel.ts +0 -479
- package/src/panels/cockpit-panel.ts +0 -481
- package/src/panels/cockpit-read-model.ts +0 -238
- package/src/panels/communication-panel.ts +0 -256
- package/src/panels/control-plane-panel.ts +0 -470
- package/src/panels/debug-panel.ts +0 -615
- package/src/panels/docs-panel.ts +0 -384
- package/src/panels/eval-panel.ts +0 -627
- package/src/panels/file-explorer-panel.ts +0 -673
- package/src/panels/file-preview-panel.ts +0 -517
- package/src/panels/hooks-panel.ts +0 -401
- package/src/panels/incident-review-panel.ts +0 -406
- package/src/panels/intelligence-panel.ts +0 -383
- package/src/panels/knowledge-graph-panel.ts +0 -515
- package/src/panels/marketplace-panel.ts +0 -399
- package/src/panels/memory-panel.ts +0 -558
- package/src/panels/ops-control-panel.ts +0 -329
- package/src/panels/ops-strategy-panel.ts +0 -321
- package/src/panels/orchestration-panel.ts +0 -465
- package/src/panels/panel-list-panel.ts +0 -566
- package/src/panels/plan-dashboard-panel.ts +0 -707
- package/src/panels/policy-panel.ts +0 -517
- package/src/panels/project-planning-panel.ts +0 -731
- package/src/panels/provider-health-panel.ts +0 -678
- package/src/panels/provider-health-tracker.ts +0 -310
- package/src/panels/provider-health-views.ts +0 -567
- package/src/panels/qr-panel.ts +0 -280
- package/src/panels/remote-panel.ts +0 -534
- package/src/panels/routes-panel.ts +0 -241
- package/src/panels/sandbox-panel.ts +0 -456
- package/src/panels/security-panel.ts +0 -447
- package/src/panels/services-panel.ts +0 -329
- package/src/panels/session-browser-panel.ts +0 -496
- package/src/panels/settings-sync-panel.ts +0 -398
- package/src/panels/subscription-panel.ts +0 -342
- package/src/panels/symbol-outline-panel.ts +0 -619
- package/src/panels/system-messages-panel.ts +0 -364
- package/src/panels/tasks-panel.ts +0 -608
- package/src/panels/thinking-panel.ts +0 -333
- package/src/panels/tool-inspector-panel.ts +0 -537
- package/src/panels/work-plan-panel.ts +0 -540
- package/src/panels/worktree-panel.ts +0 -360
- package/src/panels/wrfc-panel.ts +0 -790
- package/src/renderer/agent-detail-modal.ts +0 -466
- package/src/renderer/live-tail-modal.ts +0 -156
- package/src/renderer/process-modal.ts +0 -671
- package/src/renderer/qr-renderer.ts +0 -120
|
@@ -55,14 +55,12 @@ export type ActiveModalState = {
|
|
|
55
55
|
helpOverlayActive: boolean;
|
|
56
56
|
shortcutsOverlayActive: boolean;
|
|
57
57
|
bookmarkModal: { active: boolean; close: () => void };
|
|
58
|
-
agentDetailModal: { active: boolean; close: () => void };
|
|
59
|
-
liveTailModal: { active: boolean; close: () => void };
|
|
60
58
|
settingsModal: { active: boolean; close: () => void };
|
|
61
59
|
mcpWorkspace?: { active: boolean; close: () => void; reopen: () => void };
|
|
62
60
|
sessionPickerModal: { active: boolean; close: () => void };
|
|
63
61
|
profilePickerModal: { active: boolean; close: () => void };
|
|
62
|
+
configModal: { active: boolean; close: () => void };
|
|
64
63
|
contextInspectorModal: { active: boolean; close: () => void };
|
|
65
|
-
processModal: { active: boolean; close: () => void };
|
|
66
64
|
modelPicker: { active: boolean; close: () => void };
|
|
67
65
|
filePicker: { active: boolean; close: () => void };
|
|
68
66
|
blockActionsMenu: { active: boolean; close: () => void };
|
|
@@ -75,14 +73,12 @@ export function getActiveModalName(state: ActiveModalState): string | null {
|
|
|
75
73
|
if (state.helpOverlayActive) return 'help';
|
|
76
74
|
if (state.shortcutsOverlayActive) return 'shortcuts';
|
|
77
75
|
if (state.bookmarkModal.active) return 'bookmark';
|
|
78
|
-
if (state.agentDetailModal.active) return 'agentDetail';
|
|
79
|
-
if (state.liveTailModal.active) return 'liveTail';
|
|
80
76
|
if (state.settingsModal.active) return 'settings';
|
|
81
77
|
if (state.mcpWorkspace?.active) return 'mcpWorkspace';
|
|
82
78
|
if (state.sessionPickerModal.active) return 'sessionPicker';
|
|
83
79
|
if (state.profilePickerModal.active) return 'profilePicker';
|
|
80
|
+
if (state.configModal.active) return 'config';
|
|
84
81
|
if (state.contextInspectorModal.active) return 'contextInspector';
|
|
85
|
-
if (state.processModal.active) return 'process';
|
|
86
82
|
if (state.modelPicker.active) return 'modelPicker';
|
|
87
83
|
if (state.filePicker.active) return 'filePicker';
|
|
88
84
|
if (state.blockActionsMenu.active) return 'blockActions';
|
|
@@ -96,14 +92,12 @@ export type ModalCloseOps = {
|
|
|
96
92
|
resetHelp: () => void;
|
|
97
93
|
resetShortcuts: () => void;
|
|
98
94
|
closeBookmark: () => void;
|
|
99
|
-
closeAgentDetail: () => void;
|
|
100
|
-
closeLiveTail: () => void;
|
|
101
95
|
closeSettings: () => void;
|
|
102
96
|
closeMcpWorkspace: () => void;
|
|
103
97
|
closeSessionPicker: () => void;
|
|
104
98
|
closeProfilePicker: () => void;
|
|
99
|
+
closeConfigModal: () => void;
|
|
105
100
|
closeContextInspector: () => void;
|
|
106
|
-
closeProcess: () => void;
|
|
107
101
|
closeModelPicker: () => void;
|
|
108
102
|
closeFilePicker: () => void;
|
|
109
103
|
closeBlockActions: () => void;
|
|
@@ -123,12 +117,6 @@ export function closeModalByName(name: string, ops: ModalCloseOps): void {
|
|
|
123
117
|
case 'bookmark':
|
|
124
118
|
ops.closeBookmark();
|
|
125
119
|
break;
|
|
126
|
-
case 'agentDetail':
|
|
127
|
-
ops.closeAgentDetail();
|
|
128
|
-
break;
|
|
129
|
-
case 'liveTail':
|
|
130
|
-
ops.closeLiveTail();
|
|
131
|
-
break;
|
|
132
120
|
case 'settings':
|
|
133
121
|
ops.closeSettings();
|
|
134
122
|
break;
|
|
@@ -141,12 +129,12 @@ export function closeModalByName(name: string, ops: ModalCloseOps): void {
|
|
|
141
129
|
case 'profilePicker':
|
|
142
130
|
ops.closeProfilePicker();
|
|
143
131
|
break;
|
|
132
|
+
case 'config':
|
|
133
|
+
ops.closeConfigModal();
|
|
134
|
+
break;
|
|
144
135
|
case 'contextInspector':
|
|
145
136
|
ops.closeContextInspector();
|
|
146
137
|
break;
|
|
147
|
-
case 'process':
|
|
148
|
-
ops.closeProcess();
|
|
149
|
-
break;
|
|
150
138
|
case 'modelPicker':
|
|
151
139
|
ops.closeModelPicker();
|
|
152
140
|
break;
|
|
@@ -172,10 +160,10 @@ export type ModalOpenOps = {
|
|
|
172
160
|
openHelp: () => void;
|
|
173
161
|
openShortcuts: () => void;
|
|
174
162
|
openBookmark: () => void;
|
|
175
|
-
openProcess: () => void;
|
|
176
163
|
openContextInspector: () => void;
|
|
177
164
|
openMcpWorkspace?: () => void;
|
|
178
165
|
openOnboarding?: () => void;
|
|
166
|
+
openConfigModal?: () => void;
|
|
179
167
|
openCommandMode: () => void;
|
|
180
168
|
};
|
|
181
169
|
|
|
@@ -190,15 +178,15 @@ export function reopenModalByName(name: string, ops: ModalOpenOps): void {
|
|
|
190
178
|
case 'bookmark':
|
|
191
179
|
ops.openBookmark();
|
|
192
180
|
break;
|
|
193
|
-
case 'process':
|
|
194
|
-
ops.openProcess();
|
|
195
|
-
break;
|
|
196
181
|
case 'contextInspector':
|
|
197
182
|
ops.openContextInspector();
|
|
198
183
|
break;
|
|
199
184
|
case 'mcpWorkspace':
|
|
200
185
|
ops.openMcpWorkspace?.();
|
|
201
186
|
break;
|
|
187
|
+
case 'config':
|
|
188
|
+
ops.openConfigModal?.();
|
|
189
|
+
break;
|
|
202
190
|
case 'onboarding':
|
|
203
191
|
ops.openOnboarding?.();
|
|
204
192
|
break;
|
package/src/input/handler.ts
CHANGED
|
@@ -19,15 +19,13 @@ import type { SelectionResult, SelectionAction } from './selection-modal.ts';
|
|
|
19
19
|
import { SearchManager } from './search.ts';
|
|
20
20
|
import { InputHistory, HistorySearch } from './input-history.ts';
|
|
21
21
|
import type { BlockMeta, ConversationManager } from '../core/conversation';
|
|
22
|
-
import { ProcessModal } from '../renderer/process-modal.ts';
|
|
23
|
-
import { LiveTailModal } from '../renderer/live-tail-modal.ts';
|
|
24
22
|
import { BlockActionsMenu } from '../renderer/block-actions.ts';
|
|
25
|
-
import { AgentDetailModal } from '../renderer/agent-detail-modal.ts';
|
|
26
23
|
import { ContextInspectorModal } from '../renderer/context-inspector.ts';
|
|
27
24
|
import { BookmarkModal } from './bookmark-modal.ts';
|
|
28
25
|
import { SettingsModal } from './settings-modal.ts';
|
|
29
26
|
import { McpWorkspace } from './mcp-workspace.ts';
|
|
30
27
|
import { SessionPickerModal } from './session-picker-modal.ts';
|
|
28
|
+
import { ConfigModal } from './config-modal.ts';
|
|
31
29
|
import { ProfilePickerModal } from './profile-picker-modal.ts';
|
|
32
30
|
import { OnboardingWizardController, type OnboardingWizardAction, type OnboardingWizardMode } from './onboarding/onboarding-wizard.ts';
|
|
33
31
|
import {
|
|
@@ -106,9 +104,7 @@ import {
|
|
|
106
104
|
handleBlockActionsToken,
|
|
107
105
|
handleEscapeOnlyModalToken,
|
|
108
106
|
handleFilePickerToken,
|
|
109
|
-
handleLiveTailToken,
|
|
110
107
|
handleModelPickerToken,
|
|
111
|
-
handleProcessModalToken,
|
|
112
108
|
} from './handler-picker-routes.ts';
|
|
113
109
|
import { handleGlobalShortcutToken } from './handler-shortcuts.ts';
|
|
114
110
|
import { feedInputTokens } from './handler-feed.ts';
|
|
@@ -184,13 +180,11 @@ export class InputHandler implements InputHandlerLike {
|
|
|
184
180
|
public modelPicker: ModelPickerModal;
|
|
185
181
|
public selectionModal = new SelectionModal();
|
|
186
182
|
public searchManager = new SearchManager();
|
|
187
|
-
public processModal: ProcessModal;
|
|
188
|
-
public liveTailModal: LiveTailModal;
|
|
189
|
-
public agentDetailModal: AgentDetailModal;
|
|
190
183
|
public contextInspectorModal = new ContextInspectorModal();
|
|
191
184
|
public bookmarkModal: BookmarkModal;
|
|
192
185
|
public blockActionsMenu = new BlockActionsMenu();
|
|
193
186
|
public settingsModal = new SettingsModal();
|
|
187
|
+
public configModal = new ConfigModal();
|
|
194
188
|
public mcpWorkspace = new McpWorkspace();
|
|
195
189
|
public onboardingWizard = new OnboardingWizardController();
|
|
196
190
|
public onboardingModelPickerCancelSnapshot: OnboardingWizardSnapshot | null = null;
|
|
@@ -272,23 +266,8 @@ export class InputHandler implements InputHandlerLike {
|
|
|
272
266
|
uiServices.providers.benchmarkStore,
|
|
273
267
|
uiServices.providers.providerRegistry,
|
|
274
268
|
);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
processManager: uiServices.shell.processManager,
|
|
278
|
-
wrfcController: uiServices.agents.wrfcController,
|
|
279
|
-
});
|
|
280
|
-
this.liveTailModal = new LiveTailModal({
|
|
281
|
-
agentManager: uiServices.agents.agentManager,
|
|
282
|
-
processManager: uiServices.shell.processManager,
|
|
283
|
-
});
|
|
284
|
-
this.agentDetailModal = new AgentDetailModal({
|
|
285
|
-
agentManager: uiServices.agents.agentManager,
|
|
286
|
-
agentMessageBus: uiServices.agents.agentMessageBus,
|
|
287
|
-
sessionLogPathResolver: (agentId) => uiServices.environment.shellPaths.resolveProjectPath('tui', 'sessions', `${agentId}.jsonl`),
|
|
288
|
-
// SDK 0.23.0: supply wrfcController so the modal can show constraint data
|
|
289
|
-
wrfcController: uiServices.agents.wrfcController,
|
|
290
|
-
cancelAgent: (agentId: string) => uiServices.agents.agentManager.cancel(agentId),
|
|
291
|
-
});
|
|
269
|
+
// W6.1 retirement: ProcessModal/LiveTailModal/AgentDetailModal were removed
|
|
270
|
+
// — F2 now opens the Fleet panel, which subsumes the live process tree.
|
|
292
271
|
this.bookmarkModal = new BookmarkModal(uiServices.shell.bookmarkManager);
|
|
293
272
|
this.sessionPickerModal = new SessionPickerModal(uiServices.sessions.sessionManager);
|
|
294
273
|
this.profilePickerModal = new ProfilePickerModal(uiServices.shell.profileManager);
|
|
@@ -322,6 +301,7 @@ export class InputHandler implements InputHandlerLike {
|
|
|
322
301
|
mcpWorkspace: this.mcpWorkspace,
|
|
323
302
|
sessionPickerModal: this.sessionPickerModal,
|
|
324
303
|
profilePickerModal: this.profilePickerModal,
|
|
304
|
+
configModal: this.configModal,
|
|
325
305
|
historySearch: this.historySearch,
|
|
326
306
|
commandRegistry: this.commandRegistry,
|
|
327
307
|
commandContext: this.commandContext,
|
|
@@ -329,9 +309,6 @@ export class InputHandler implements InputHandlerLike {
|
|
|
329
309
|
filePicker: this.filePicker,
|
|
330
310
|
modelPicker: this.modelPicker,
|
|
331
311
|
onboardingWizard: this.onboardingWizard,
|
|
332
|
-
processModal: this.processModal,
|
|
333
|
-
liveTailModal: this.liveTailModal,
|
|
334
|
-
agentDetailModal: this.agentDetailModal,
|
|
335
312
|
contextInspectorModal: this.contextInspectorModal,
|
|
336
313
|
blockActionsMenu: this.blockActionsMenu,
|
|
337
314
|
searchManager: this.searchManager,
|
|
@@ -341,6 +318,7 @@ export class InputHandler implements InputHandlerLike {
|
|
|
341
318
|
panelManager: this.uiServices.shell.panelManager,
|
|
342
319
|
keybindingsManager: this.uiServices.shell.keybindingsManager,
|
|
343
320
|
killRing: this.killRing,
|
|
321
|
+
focusTracker: this.uiServices.platform.focusTracker,
|
|
344
322
|
getHistory: this.getHistory,
|
|
345
323
|
getViewportHeight: this.getViewportHeight,
|
|
346
324
|
getScrollTop: this.getScrollTop,
|
package/src/input/keybindings.ts
CHANGED
|
@@ -88,7 +88,7 @@ export const ACTION_DESCRIPTIONS: Record<KeyAction, string> = {
|
|
|
88
88
|
'panel-tab-7': 'Jump to workspace panel tab 7',
|
|
89
89
|
'panel-tab-8': 'Jump to workspace panel tab 8',
|
|
90
90
|
'panel-tab-9': 'Jump to workspace panel tab 9',
|
|
91
|
-
'panel-ops': 'Open the
|
|
91
|
+
'panel-ops': 'Open and focus the Fleet panel',
|
|
92
92
|
'panel-focus-toggle': 'Switch keyboard focus between top and bottom pane',
|
|
93
93
|
'history-search': 'Reverse input history search',
|
|
94
94
|
'search': 'Toggle conversation search',
|
|
@@ -119,8 +119,14 @@ export const DEFAULT_KEYBINDINGS: Record<KeyAction, KeyCombo[]> = {
|
|
|
119
119
|
'panel-picker': [{ key: 'p', ctrl: true }],
|
|
120
120
|
'panel-close': [{ key: 'x', ctrl: true }],
|
|
121
121
|
'panel-close-all': [{ key: 'x', ctrl: true, shift: true }],
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// Ctrl+] stays the primary next-tab chord; Ctrl+PageDown is added as a second
|
|
123
|
+
// binding. Ctrl+[ was REMOVED as prev-tab: it is byte 0x1B (ESC), so the
|
|
124
|
+
// legacy tokenizer path emits it as 'escape' — the binding never matched on
|
|
125
|
+
// most terminals AND the key fired Escape (a split-brain chord). Ctrl+PageUp
|
|
126
|
+
// replaces it: Ctrl+PageUp/PageDown tokenize consistently (\x1b[5;5~ /
|
|
127
|
+
// \x1b[6;5~ -> pageup/pagedown ctrl:true) in both the legacy and CSI-u paths.
|
|
128
|
+
'panel-tab-next': [{ key: ']', ctrl: true }, { key: 'pagedown', ctrl: true }],
|
|
129
|
+
'panel-tab-prev': [{ key: 'pageup', ctrl: true }],
|
|
124
130
|
// Alt+1..9: jump directly to the Nth workspace panel tab (across both panes).
|
|
125
131
|
// The tokenizer delivers Alt as the token's `meta` modifier; comboMatches /
|
|
126
132
|
// lookup treat `meta` as an alias for `alt`, so these alt-combos route through
|
|
@@ -134,10 +140,10 @@ export const DEFAULT_KEYBINDINGS: Record<KeyAction, KeyCombo[]> = {
|
|
|
134
140
|
'panel-tab-7': [{ key: '7', alt: true }],
|
|
135
141
|
'panel-tab-8': [{ key: '8', alt: true }],
|
|
136
142
|
'panel-tab-9': [{ key: '9', alt: true }],
|
|
137
|
-
// Ctrl+O: open the Ops Control panel
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
143
|
+
// Ctrl+O: open and focus the Fleet panel. The former Ops Control panel was
|
|
144
|
+
// retired to an 'ops-control' -> 'fleet' alias (W6.1); the binding is KEPT
|
|
145
|
+
// (repointed, not removed) so the Ctrl+O muscle memory still lands somewhere
|
|
146
|
+
// useful. Routed globally in handleGlobalShortcutToken.
|
|
141
147
|
'panel-ops': [{ key: 'o', ctrl: true }],
|
|
142
148
|
// Ctrl+G: toggle keyboard focus between the top and bottom panes. Ctrl+G is
|
|
143
149
|
// otherwise unbound in the default table.
|
|
@@ -355,7 +361,15 @@ export class KeybindingsManager {
|
|
|
355
361
|
if (combo.ctrl) parts.push('Ctrl');
|
|
356
362
|
if (combo.alt) parts.push('Alt');
|
|
357
363
|
if (combo.shift) parts.push('Shift');
|
|
358
|
-
|
|
364
|
+
// Friendly display for named keys with a conventional abbreviation, so a
|
|
365
|
+
// chord like Ctrl+PageUp reads consistently with the "PageUp / PageDn"
|
|
366
|
+
// scroll help text. Single chars upper-case; other named keys pass through.
|
|
367
|
+
const KEY_DISPLAY: Record<string, string> = { pageup: 'PageUp', pagedown: 'PageDn' };
|
|
368
|
+
parts.push(
|
|
369
|
+
combo.key.length === 1
|
|
370
|
+
? combo.key.toUpperCase()
|
|
371
|
+
: KEY_DISPLAY[combo.key] ?? combo.key,
|
|
372
|
+
);
|
|
359
373
|
return parts.join('+');
|
|
360
374
|
}
|
|
361
375
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import type { ModelDefinition } from '@pellux/goodvibes-sdk/platform/providers';
|
|
2
2
|
|
|
3
|
-
export type PickerMode = 'model' | 'provider' | 'effort' | 'contextCap';
|
|
3
|
+
export type PickerMode = 'model' | 'provider' | 'effort' | 'contextCap' | 'embeddingProvider';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Which config keys the model picker writes to on commit.
|
|
7
|
-
* 'main'
|
|
8
|
-
* 'helper'
|
|
9
|
-
* 'tool'
|
|
10
|
-
* 'tts'
|
|
7
|
+
* 'main' -> provider.provider + provider.model (default)
|
|
8
|
+
* 'helper' -> helper.globalProvider + helper.globalModel (+ helper.enabled: true)
|
|
9
|
+
* 'tool' -> tools.llmProvider + tools.llmModel (+ tools.llmEnabled: true)
|
|
10
|
+
* 'tts' -> tts.llmProvider + tts.llmModel
|
|
11
|
+
* 'embeddings' -> provider.embeddingProvider, via MemoryEmbeddingProviderRegistry.setDefaultProvider()
|
|
12
|
+
* (not an LLM route — no model concept, see ModelPickerTargetInfo.configuredNote)
|
|
11
13
|
*/
|
|
12
|
-
export type ModelPickerTarget = 'main' | 'helper' | 'tool' | 'tts';
|
|
14
|
+
export type ModelPickerTarget = 'main' | 'helper' | 'tool' | 'tts' | 'embeddings';
|
|
13
15
|
|
|
14
16
|
export type ModelPickerFocusPane = 'targets' | 'items';
|
|
15
17
|
|
|
@@ -21,6 +23,22 @@ export interface ModelPickerTargetInfo {
|
|
|
21
23
|
readonly model: string;
|
|
22
24
|
readonly enabled: boolean;
|
|
23
25
|
readonly inherited: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Honest override for the "Current:" summary line. Used by the 'embeddings'
|
|
28
|
+
* target (which has no model concept — only a provider id + dimensions +
|
|
29
|
+
* configured state) so the renderer never prints a phantom "model:" value.
|
|
30
|
+
* When set, this replaces the computed provider:model route text.
|
|
31
|
+
*/
|
|
32
|
+
readonly configuredNote?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** One entry in the embedding-provider picker list (PickerMode 'embeddingProvider'). */
|
|
36
|
+
export interface EmbeddingProviderPickerEntry {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly label: string;
|
|
39
|
+
readonly dimensions: number;
|
|
40
|
+
readonly configured: boolean;
|
|
41
|
+
readonly detail?: string;
|
|
24
42
|
}
|
|
25
43
|
|
|
26
44
|
/**
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
BenchmarkSort,
|
|
8
8
|
CapabilityFilter,
|
|
9
9
|
CategoryFilter,
|
|
10
|
+
EmbeddingProviderPickerEntry,
|
|
10
11
|
FilteredModelsCache,
|
|
11
12
|
FilteredProvidersCache,
|
|
12
13
|
GroupByMode,
|
|
@@ -40,6 +41,7 @@ export type {
|
|
|
40
41
|
BenchmarkSort,
|
|
41
42
|
CapabilityFilter,
|
|
42
43
|
CategoryFilter,
|
|
44
|
+
EmbeddingProviderPickerEntry,
|
|
43
45
|
GroupByMode,
|
|
44
46
|
ModelFamily,
|
|
45
47
|
ModelPickerFocusPane,
|
|
@@ -86,6 +88,10 @@ export class ModelPickerModal {
|
|
|
86
88
|
public models: ModelDefinition[] = [];
|
|
87
89
|
public providers: string[] = [];
|
|
88
90
|
public effortLevels: string[] = [];
|
|
91
|
+
/** Entries for PickerMode 'embeddingProvider' — the 'embeddings' target's own tiny item list. */
|
|
92
|
+
public embeddingProviders: EmbeddingProviderPickerEntry[] = [];
|
|
93
|
+
/** Mode to restore when navigating the targets rail away from 'embeddings'. */
|
|
94
|
+
private nonEmbeddingMode: PickerMode = 'model';
|
|
89
95
|
/** The model chosen in model-mode, awaiting effort selection. */
|
|
90
96
|
public pendingModel: ModelDefinition | null = null;
|
|
91
97
|
/** The model awaiting context cap input (contextCap mode). */
|
|
@@ -148,9 +154,20 @@ export class ModelPickerModal {
|
|
|
148
154
|
}
|
|
149
155
|
|
|
150
156
|
setTarget(target: ModelPickerTarget): void {
|
|
157
|
+
const previousTarget = this.target;
|
|
151
158
|
this.target = target;
|
|
152
159
|
const idx = this.targetInfos.findIndex((entry) => entry.target === target);
|
|
153
160
|
this.targetIndex = idx >= 0 ? idx : this.targetIndex;
|
|
161
|
+
// The 'embeddings' target routes through its own tiny item-list mode
|
|
162
|
+
// (embedding providers are not ModelDefinition-shaped) rather than
|
|
163
|
+
// whatever LLM mode the picker session was already in. Remember the
|
|
164
|
+
// mode we came from so tabbing back to another target restores it.
|
|
165
|
+
if (target === 'embeddings' && this.mode !== 'embeddingProvider') {
|
|
166
|
+
this.nonEmbeddingMode = this.mode;
|
|
167
|
+
this.mode = 'embeddingProvider';
|
|
168
|
+
} else if (previousTarget === 'embeddings' && target !== 'embeddings' && this.mode === 'embeddingProvider') {
|
|
169
|
+
this.mode = this.nonEmbeddingMode;
|
|
170
|
+
}
|
|
154
171
|
this.alignSelectionToTarget();
|
|
155
172
|
}
|
|
156
173
|
|
|
@@ -171,6 +188,13 @@ export class ModelPickerModal {
|
|
|
171
188
|
this.selectedIndex = modelIdx >= 0 ? modelIdx : 0;
|
|
172
189
|
this.scrollOffset = 0;
|
|
173
190
|
this._scrollToSelection(20);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (this.mode === 'embeddingProvider') {
|
|
194
|
+
const providerIdx = this.embeddingProviders.findIndex((provider) => provider.id === info.provider);
|
|
195
|
+
this.selectedIndex = providerIdx >= 0 ? providerIdx : 0;
|
|
196
|
+
this.scrollOffset = 0;
|
|
197
|
+
this._scrollToSelection(20);
|
|
174
198
|
}
|
|
175
199
|
}
|
|
176
200
|
|
|
@@ -273,6 +297,27 @@ export class ModelPickerModal {
|
|
|
273
297
|
this.scrollOffset = 0;
|
|
274
298
|
}
|
|
275
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Open the embedding-provider list — entry point for the 'embeddings' target.
|
|
302
|
+
* Deliberately NOT routed through openAllModels (ModelDefinition-shaped) or
|
|
303
|
+
* openProviders (LLM-provider label resolution) — embedding providers are a
|
|
304
|
+
* flat {id, label, dimensions, configured} list with no model concept, and
|
|
305
|
+
* reusing either existing opener would mislabel or drop unrecognized ids.
|
|
306
|
+
*/
|
|
307
|
+
openEmbeddingProviders(providers: EmbeddingProviderPickerEntry[], currentId: string): void {
|
|
308
|
+
this.previousMode = null;
|
|
309
|
+
this.embeddingProviders = providers;
|
|
310
|
+
this.mode = 'embeddingProvider';
|
|
311
|
+
this.active = true;
|
|
312
|
+
this.pendingModel = null;
|
|
313
|
+
this.focusPane = 'items';
|
|
314
|
+
this.searchFocused = false;
|
|
315
|
+
this.query = '';
|
|
316
|
+
const idx = providers.findIndex((provider) => provider.id === currentId);
|
|
317
|
+
this.selectedIndex = idx >= 0 ? idx : 0;
|
|
318
|
+
this.scrollOffset = 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
276
321
|
/** Transition to model list filtered by provider (called from provider mode Enter). */
|
|
277
322
|
showModelsForProvider(models: ModelDefinition[], _provider: string): void {
|
|
278
323
|
this.previousMode = 'provider';
|
|
@@ -311,6 +356,8 @@ export class ModelPickerModal {
|
|
|
311
356
|
this.targetIndex = 0;
|
|
312
357
|
this.models = [];
|
|
313
358
|
this.providers = [];
|
|
359
|
+
this.embeddingProviders = [];
|
|
360
|
+
this.nonEmbeddingMode = 'model';
|
|
314
361
|
this.pendingModel = null;
|
|
315
362
|
this.contextCapPendingModel = null;
|
|
316
363
|
this.contextCapQuery = '';
|
|
@@ -473,6 +520,16 @@ export class ModelPickerModal {
|
|
|
473
520
|
this.providerItemsCache = cache;
|
|
474
521
|
return result;
|
|
475
522
|
}
|
|
523
|
+
if (this.mode === 'embeddingProvider') {
|
|
524
|
+
// Tiny list (typically 2-4 entries) — no caching infrastructure needed.
|
|
525
|
+
// Unconfigured providers are shown honestly (isConfigured: false), never hidden.
|
|
526
|
+
return this.embeddingProviders.map((provider) => ({
|
|
527
|
+
id: provider.id,
|
|
528
|
+
label: provider.label,
|
|
529
|
+
detail: `${provider.dimensions}d${provider.configured ? '' : ' · unconfigured'}`,
|
|
530
|
+
isConfigured: provider.configured,
|
|
531
|
+
}));
|
|
532
|
+
}
|
|
476
533
|
// effort mode
|
|
477
534
|
return buildEffortItems(this.effortLevels);
|
|
478
535
|
}
|
|
@@ -481,6 +538,7 @@ export class ModelPickerModal {
|
|
|
481
538
|
getItemCount(): number {
|
|
482
539
|
if (this.mode === 'model') return this.getFilteredModels().length;
|
|
483
540
|
if (this.mode === 'provider') return this.getFilteredProviders().length;
|
|
541
|
+
if (this.mode === 'embeddingProvider') return this.embeddingProviders.length;
|
|
484
542
|
return this.effortLevels.length;
|
|
485
543
|
}
|
|
486
544
|
|
|
@@ -1,64 +1,16 @@
|
|
|
1
1
|
import type { CommandContext } from './command-registry.ts';
|
|
2
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
3
2
|
import type { Panel } from '../panels/types.ts';
|
|
4
3
|
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
5
|
-
import { FileExplorerPanel } from '../panels/file-explorer-panel.ts';
|
|
6
|
-
import { FilePreviewPanel } from '../panels/file-preview-panel.ts';
|
|
7
|
-
import { SymbolOutlinePanel } from '../panels/symbol-outline-panel.ts';
|
|
8
|
-
import { ApprovalPanel } from '../panels/approval-panel.ts';
|
|
9
|
-
import { TasksPanel } from '../panels/tasks-panel.ts';
|
|
10
|
-
import { OrchestrationPanel } from '../panels/orchestration-panel.ts';
|
|
11
|
-
import { AgentInspectorPanel } from '../panels/agent-inspector-panel.ts';
|
|
12
|
-
import { DiffPanel } from '../panels/diff-panel.ts';
|
|
13
|
-
|
|
14
|
-
function ensurePreviewPanel(panelManager: PanelManager): FilePreviewPanel | null {
|
|
15
|
-
const existing = panelManager.getPanel('preview');
|
|
16
|
-
if (existing instanceof FilePreviewPanel) {
|
|
17
|
-
const pane = panelManager.getPaneOf('preview');
|
|
18
|
-
panelManager.activateById('preview');
|
|
19
|
-
if (pane) panelManager.focusPane(pane);
|
|
20
|
-
return existing;
|
|
21
|
-
}
|
|
22
|
-
const targetPane: 'top' | 'bottom' = panelManager.isBottomPaneVisible()
|
|
23
|
-
? (panelManager.getFocusedPane() === 'top' ? 'bottom' : 'top')
|
|
24
|
-
: 'bottom';
|
|
25
|
-
const opened = panelManager.open('preview', targetPane);
|
|
26
|
-
panelManager.show();
|
|
27
|
-
panelManager.focusPane(targetPane);
|
|
28
|
-
return opened instanceof FilePreviewPanel ? opened : null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// WO-133: shared by explorer's and preview's 'd' (diff) key — same
|
|
32
|
-
// open/focus bridge as ensurePreviewPanel above.
|
|
33
|
-
function ensureDiffPanel(panelManager: PanelManager): DiffPanel | null {
|
|
34
|
-
const existing = panelManager.getPanel('diff');
|
|
35
|
-
if (existing instanceof DiffPanel) {
|
|
36
|
-
const pane = panelManager.getPaneOf('diff');
|
|
37
|
-
panelManager.activateById('diff');
|
|
38
|
-
if (pane) panelManager.focusPane(pane);
|
|
39
|
-
return existing;
|
|
40
|
-
}
|
|
41
|
-
const targetPane: 'top' | 'bottom' = panelManager.isBottomPaneVisible()
|
|
42
|
-
? (panelManager.getFocusedPane() === 'top' ? 'bottom' : 'top')
|
|
43
|
-
: 'bottom';
|
|
44
|
-
const opened = panelManager.open('diff', targetPane);
|
|
45
|
-
panelManager.show();
|
|
46
|
-
panelManager.focusPane(targetPane);
|
|
47
|
-
return opened instanceof DiffPanel ? opened : null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Exported so a future preview-reload action (e.g. an explicit "r" reload
|
|
51
|
-
// key) can re-sync the outline against the same file without duplicating
|
|
52
|
-
// this lookup — the panel-integration wiring for that key lands separately.
|
|
53
|
-
export function syncSymbolOutlineFromPreview(panelManager: PanelManager, previewPanel: FilePreviewPanel): void {
|
|
54
|
-
const symbols = panelManager.getPanel('symbols');
|
|
55
|
-
const filePath = previewPanel.getCurrentFilePath();
|
|
56
|
-
const source = previewPanel.getSource();
|
|
57
|
-
if (symbols instanceof SymbolOutlinePanel && filePath && source !== null) {
|
|
58
|
-
symbols.loadFile(filePath, source);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
4
|
|
|
5
|
+
// W6.1 (the purge): every instanceof-routed branch this file used to carry
|
|
6
|
+
// (FileExplorerPanel/FilePreviewPanel/SymbolOutlinePanel — DELETE;
|
|
7
|
+
// ApprovalPanel/TasksPanel/OrchestrationPanel/AgentInspectorPanel —
|
|
8
|
+
// RETIRE-INTO-FLEET) targeted a panel class that no longer exists. Panels
|
|
9
|
+
// migrated onto the formal `Panel.handlePanelIntegrationAction` hook (the
|
|
10
|
+
// preferred seam — see the comment below) are unaffected; this function now
|
|
11
|
+
// only provides that passthrough. See
|
|
12
|
+
// .goodvibes/audit/2026-07-04-wave6-briefs.json (W6.1) for the disposition
|
|
13
|
+
// map.
|
|
62
14
|
export function handlePanelIntegrationAction(
|
|
63
15
|
panelManager: PanelManager,
|
|
64
16
|
activePanel: Panel | null,
|
|
@@ -77,118 +29,5 @@ export function handlePanelIntegrationAction(
|
|
|
77
29
|
if (consumed) return true;
|
|
78
30
|
}
|
|
79
31
|
|
|
80
|
-
if ((key === 'enter' || key === 'return' || key === 'right') && activePanel instanceof FileExplorerPanel) {
|
|
81
|
-
const filePath = activePanel.getFocusedFilePath();
|
|
82
|
-
if (!filePath) return false;
|
|
83
|
-
const previewPanel = ensurePreviewPanel(panelManager);
|
|
84
|
-
if (!previewPanel) return false;
|
|
85
|
-
previewPanel.openFile(filePath);
|
|
86
|
-
syncSymbolOutlineFromPreview(panelManager, previewPanel);
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// WO-133: 'd' on the explorer diffs the currently focused file, and 'd' on
|
|
91
|
-
// the preview diffs whatever file is currently open — both against HEAD,
|
|
92
|
-
// both via the same DiffPanel.showFileDiffs entry point.
|
|
93
|
-
if (key === 'd' && activePanel instanceof FileExplorerPanel) {
|
|
94
|
-
const filePath = activePanel.getFocusedFilePath();
|
|
95
|
-
if (!filePath) return false;
|
|
96
|
-
const diffPanel = ensureDiffPanel(panelManager);
|
|
97
|
-
if (!diffPanel) return false;
|
|
98
|
-
void diffPanel.showFileDiffs([filePath], 'HEAD').catch((err) => {
|
|
99
|
-
logger.debug('explorer diff dispatch failed', { err });
|
|
100
|
-
});
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (key === 'd' && activePanel instanceof FilePreviewPanel) {
|
|
105
|
-
const filePath = activePanel.getCurrentFilePath();
|
|
106
|
-
if (!filePath) return false;
|
|
107
|
-
const diffPanel = ensureDiffPanel(panelManager);
|
|
108
|
-
if (!diffPanel) return false;
|
|
109
|
-
void diffPanel.showFileDiffs([filePath], 'HEAD').catch((err) => {
|
|
110
|
-
logger.debug('preview diff dispatch failed', { err });
|
|
111
|
-
});
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// WO-133: 'r' on the preview reloads the open file from disk, then
|
|
116
|
-
// re-syncs the symbol outline against the refreshed content (WO-126's
|
|
117
|
-
// async tree-sitter loadFile via syncSymbolOutlineFromPreview above) once
|
|
118
|
-
// the reload actually settles.
|
|
119
|
-
if (key === 'r' && activePanel instanceof FilePreviewPanel) {
|
|
120
|
-
const reloaded = activePanel.consumePendingReload();
|
|
121
|
-
if (!reloaded) return false;
|
|
122
|
-
void reloaded.then(() => syncSymbolOutlineFromPreview(panelManager, activePanel)).catch((err) => {
|
|
123
|
-
logger.debug('preview reload dispatch failed', { err });
|
|
124
|
-
});
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if ((key === 'enter' || key === 'return') && activePanel instanceof SymbolOutlinePanel) {
|
|
129
|
-
const location = activePanel.getSelectedLocation();
|
|
130
|
-
if (!location) return false;
|
|
131
|
-
const previewPanel = ensurePreviewPanel(panelManager);
|
|
132
|
-
if (!previewPanel) return false;
|
|
133
|
-
if (previewPanel.getCurrentFilePath() !== location.path) {
|
|
134
|
-
previewPanel.openFile(location.path);
|
|
135
|
-
syncSymbolOutlineFromPreview(panelManager, previewPanel);
|
|
136
|
-
}
|
|
137
|
-
previewPanel.goToLine(location.line);
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if ((key === 'enter' || key === 'return') && activePanel instanceof ApprovalPanel) {
|
|
142
|
-
const command = activePanel.getSelectedCommand();
|
|
143
|
-
if (!command || !commandContext?.executeCommand) return false;
|
|
144
|
-
const parts = command.replace(/^\//, '').split(/\s+/).filter(Boolean);
|
|
145
|
-
const [name, ...args] = parts;
|
|
146
|
-
if (!name) return false;
|
|
147
|
-
void commandContext.executeCommand(name, args).catch((err) => { logger.debug('approval panel command dispatch failed', { err }); });
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// WO-131: Enter on a Tasks row — agent-kind tasks jump straight to the Agent
|
|
152
|
-
// Inspector (which owns the deep per-agent timeline); everything else's
|
|
153
|
-
// advertised worktree follow-up is dispatched for real via ctx.executeCommand
|
|
154
|
-
// instead of being printed as a static "/worktree task <task-id>" signpost.
|
|
155
|
-
// w dispatches the task-family posture review the header line advertises.
|
|
156
|
-
if ((key === 'enter' || key === 'return' || key === 'w') && activePanel instanceof TasksPanel) {
|
|
157
|
-
const followUp = activePanel.consumePendingFollowUp();
|
|
158
|
-
if (!followUp) return false;
|
|
159
|
-
if (followUp.kind === 'agent-jump') {
|
|
160
|
-
const inspector = panelManager.open('inspector');
|
|
161
|
-
if (!(inspector instanceof AgentInspectorPanel)) return false;
|
|
162
|
-
inspector.inspectAgent(followUp.agentId);
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
if (!commandContext?.executeCommand) return false;
|
|
166
|
-
if (followUp.kind === 'teamwork-review') {
|
|
167
|
-
void commandContext.executeCommand('teamwork', ['review']).catch((err) => {
|
|
168
|
-
logger.debug('tasks panel teamwork review dispatch failed', { err });
|
|
169
|
-
});
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
void commandContext.executeCommand('worktree', ['task', followUp.taskId]).catch((err) => {
|
|
173
|
-
logger.debug('tasks panel worktree review dispatch failed', { err });
|
|
174
|
-
});
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// WO-131: Enter on a node-focused Orchestration row jumps to the Agent
|
|
179
|
-
// Inspector (agent-backed nodes) or the Tasks panel (task-backed nodes).
|
|
180
|
-
if ((key === 'enter' || key === 'return') && activePanel instanceof OrchestrationPanel) {
|
|
181
|
-
const jump = activePanel.consumePendingNodeJump();
|
|
182
|
-
if (!jump) return false;
|
|
183
|
-
if (jump.kind === 'agent-jump') {
|
|
184
|
-
const inspector = panelManager.open('inspector');
|
|
185
|
-
if (!(inspector instanceof AgentInspectorPanel)) return false;
|
|
186
|
-
inspector.inspectAgent(jump.id);
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
panelManager.open('tasks');
|
|
190
|
-
return true;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
32
|
return false;
|
|
194
33
|
}
|