@pellux/goodvibes-agent 1.4.3 → 1.5.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 +24 -0
- package/README.md +7 -7
- package/dist/package/main.js +7450 -12285
- package/docs/README.md +2 -2
- package/docs/channels-remote-and-api.md +1 -1
- package/docs/getting-started.md +2 -2
- package/docs/release-and-publishing.md +1 -1
- package/docs/tools-and-commands.md +5 -5
- package/package.json +4 -2
- package/release/performance-snapshot.json +2 -2
- package/release/release-notes.md +11 -7
- package/release/release-readiness.json +6 -6
- package/src/agent/behavior-discovery-summary.ts +4 -18
- package/src/agent/calendar-registry.ts +322 -0
- package/src/agent/competitive-feature-inventory.ts +268 -130
- package/src/agent/document-registry.ts +5 -1
- package/src/agent/email/email-service.ts +350 -0
- package/src/agent/email/imap-client.ts +596 -0
- package/src/agent/email/smtp-client.ts +453 -0
- package/src/agent/ics-calendar.ts +662 -0
- package/src/agent/ics-timezone.ts +172 -0
- package/src/agent/markdown-frontmatter.ts +31 -0
- package/src/agent/memory-safety.ts +1 -1
- package/src/agent/note-registry.ts +3 -9
- package/src/agent/persona-discovery.ts +3 -15
- package/src/agent/persona-registry.ts +1 -10
- package/src/agent/research-source-registry.ts +5 -1
- package/src/agent/routine-discovery.ts +3 -15
- package/src/agent/runtime-profile.ts +3 -0
- package/src/agent/skill-discovery.ts +3 -15
- package/src/agent/skill-draft-proposer.ts +203 -0
- package/src/agent/skill-draft-runner.ts +201 -0
- package/src/agent/skill-registry.ts +36 -1
- package/src/agent/skill-standard.ts +99 -0
- package/src/agent/vibe-file.ts +7 -22
- package/src/cli/completion.ts +1 -1
- package/src/cli/config-overrides.ts +10 -1
- package/src/cli/redaction.ts +17 -5
- package/src/config/provider-model.ts +2 -1
- package/src/config/secret-config.ts +13 -6
- package/src/core/activity-feed.ts +97 -0
- package/src/core/away-digest.ts +161 -0
- package/src/core/conversation-rendering.ts +7 -3
- package/src/core/conversation.ts +22 -15
- package/src/core/hardware-profile.ts +362 -0
- package/src/core/last-seen-store.ts +78 -0
- package/src/core/plain-language.ts +52 -0
- package/src/core/setup-incomplete-hint.ts +90 -0
- package/src/core/system-message-router.ts +38 -87
- package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
- package/src/input/agent-workspace-basic-command-editors.ts +39 -141
- package/src/input/agent-workspace-categories.ts +63 -158
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-host-category.ts +0 -5
- package/src/input/agent-workspace-local-editor-submission.ts +3 -1
- package/src/input/agent-workspace-navigation.ts +10 -3
- package/src/input/agent-workspace-onboarding-actions.ts +132 -0
- package/src/input/agent-workspace-onboarding-categories.ts +29 -26
- package/src/input/agent-workspace-onboarding-finish.ts +11 -4
- package/src/input/agent-workspace-onboarding-state.ts +111 -0
- package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
- package/src/input/agent-workspace-profile-editors.ts +155 -0
- package/src/input/agent-workspace-subscription-editor.ts +7 -0
- package/src/input/agent-workspace-types.ts +5 -1
- package/src/input/agent-workspace.ts +65 -39
- package/src/input/command-registry.ts +18 -5
- package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
- package/src/input/commands/agent-skills-runtime.ts +60 -3
- package/src/input/commands/calendar-runtime.ts +209 -0
- package/src/input/commands/channels-runtime.ts +1 -0
- package/src/input/commands/command-error.ts +9 -0
- package/src/input/commands/compat-runtime.ts +1 -0
- package/src/input/commands/config.ts +1 -0
- package/src/input/commands/conversation-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +5 -6
- package/src/input/commands/email-runtime.ts +387 -0
- package/src/input/commands/experience-runtime.ts +17 -4
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +6 -1
- package/src/input/commands/knowledge-format.ts +73 -0
- package/src/input/commands/knowledge.ts +9 -74
- package/src/input/commands/local-provider-runtime.ts +2 -1
- package/src/input/commands/local-runtime.ts +10 -4
- package/src/input/commands/mcp-runtime.ts +7 -0
- package/src/input/commands/notify-runtime.ts +17 -1
- package/src/input/commands/onboarding-runtime.ts +1 -0
- package/src/input/commands/operator-actions-runtime.ts +1 -0
- package/src/input/commands/operator-runtime.ts +3 -0
- package/src/input/commands/personas-runtime.ts +1 -0
- package/src/input/commands/platform-access-runtime.ts +40 -17
- package/src/input/commands/product-runtime.ts +6 -1
- package/src/input/commands/provider-accounts-runtime.ts +3 -2
- package/src/input/commands/qrcode-runtime.ts +1 -0
- package/src/input/commands/routines-runtime.ts +1 -0
- package/src/input/commands/runtime-services.ts +0 -13
- package/src/input/commands/security-runtime.ts +1 -0
- package/src/input/commands/session-content.ts +1 -0
- package/src/input/commands/shell-core.ts +5 -2
- package/src/input/commands/subscription-runtime.ts +33 -9
- package/src/input/commands/support-bundle-runtime.ts +8 -1
- package/src/input/commands/tasks-runtime.ts +1 -0
- package/src/input/commands/tts-runtime.ts +1 -0
- package/src/input/commands/vibe-runtime.ts +1 -0
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +3 -12
- package/src/input/handler-command-route.ts +7 -60
- package/src/input/handler-feed-routes.ts +0 -194
- package/src/input/handler-feed.ts +2 -54
- package/src/input/handler-interactions.ts +0 -2
- package/src/input/handler-modal-stack.ts +0 -9
- package/src/input/handler-picker-routes.ts +24 -1
- package/src/input/handler-shortcuts.ts +11 -40
- package/src/input/handler-ui-state.ts +13 -0
- package/src/input/handler.ts +8 -35
- package/src/input/keybindings.ts +40 -17
- package/src/input/model-picker-local-fit.ts +130 -0
- package/src/input/submission-router.ts +0 -5
- package/src/main.ts +111 -89
- package/src/renderer/activity-sidebar.ts +186 -0
- package/src/renderer/agent-workspace-context-lines.ts +5 -48
- package/src/renderer/agent-workspace-style.ts +1 -1
- package/src/renderer/agent-workspace.ts +14 -2
- package/src/renderer/compositor.ts +37 -125
- package/src/renderer/conversation-overlays.ts +3 -3
- package/src/renderer/help-overlay.ts +7 -5
- package/src/renderer/model-workspace.ts +101 -86
- package/src/{panels → renderer}/polish.ts +3 -3
- package/src/renderer/shell-surface.ts +4 -5
- package/src/renderer/status-token.ts +31 -11
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/tool-call.ts +7 -8
- package/src/renderer/tool-labels.ts +92 -0
- package/src/renderer/ui-factory.ts +48 -96
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +6 -15
- package/src/runtime/bootstrap-core.ts +34 -13
- package/src/runtime/bootstrap-hook-bridge.ts +3 -1
- package/src/runtime/bootstrap-shell.ts +3 -50
- package/src/runtime/bootstrap.ts +3 -4
- package/src/runtime/context.ts +1 -1
- package/src/runtime/diagnostics/panels/index.ts +0 -1
- package/src/runtime/diagnostics/panels/policy.ts +1 -1
- package/src/runtime/execution-ledger.ts +16 -1
- package/src/runtime/index.ts +6 -1
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/onboarding-state.ts +200 -0
- package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
- package/src/runtime/services.ts +16 -4
- package/src/runtime/terminal-output-guard.ts +7 -0
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/runtime/ui/model-picker/data-provider.ts +1 -1
- package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
- package/src/runtime/ui/model-picker/types.ts +2 -2
- package/src/runtime/ui/provider-health/data-provider.ts +3 -3
- package/src/runtime/ui/provider-health/types.ts +2 -2
- package/src/runtime/ui-services.ts +0 -2
- package/src/shell/agent-workspace-fullscreen.ts +0 -1
- package/src/shell/autonomy-surfacing.ts +272 -0
- package/src/shell/session-continuity-hints.ts +0 -6
- package/src/shell/startup-wiring.ts +221 -0
- package/src/shell/ui-openers.ts +18 -29
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +4 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
- package/src/tools/agent-harness-command-runner.ts +6 -1
- package/src/tools/agent-harness-document-ops.ts +26 -53
- package/src/tools/agent-harness-execution-history.ts +1 -13
- package/src/tools/agent-harness-execution-posture.ts +0 -15
- package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
- package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
- package/src/tools/agent-harness-metadata.ts +16 -0
- package/src/tools/agent-harness-mode-catalog.ts +2 -9
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
- package/src/tools/agent-harness-tool-schema.ts +13 -14
- package/src/tools/agent-harness-tool.ts +27 -23
- package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
- package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
- package/src/tools/agent-workspace-tool.ts +2 -33
- package/src/utils/terminal-width.ts +9 -3
- package/src/version.ts +1 -1
- package/src/input/agent-workspace-panel-route.ts +0 -44
- package/src/input/panel-integration-actions.ts +0 -26
- package/src/panels/approval-panel.ts +0 -149
- package/src/panels/automation-control-panel.ts +0 -212
- package/src/panels/base-panel.ts +0 -254
- package/src/panels/builtin/agent.ts +0 -58
- package/src/panels/builtin/knowledge.ts +0 -26
- package/src/panels/builtin/operations.ts +0 -121
- package/src/panels/builtin/session.ts +0 -138
- package/src/panels/builtin/shared.ts +0 -275
- package/src/panels/builtin/usage.ts +0 -21
- package/src/panels/builtin-panels.ts +0 -23
- package/src/panels/confirm-state.ts +0 -61
- package/src/panels/context-visualizer-panel.ts +0 -204
- package/src/panels/cost-tracker-panel.ts +0 -444
- package/src/panels/docs-panel.ts +0 -285
- package/src/panels/index.ts +0 -25
- package/src/panels/knowledge-panel.ts +0 -417
- package/src/panels/memory-panel.ts +0 -226
- package/src/panels/panel-list-panel.ts +0 -464
- package/src/panels/panel-manager.ts +0 -570
- package/src/panels/provider-accounts-panel.ts +0 -233
- package/src/panels/provider-health-domains.ts +0 -208
- package/src/panels/provider-health-panel.ts +0 -720
- package/src/panels/provider-health-tracker.ts +0 -115
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/qr-panel.ts +0 -207
- package/src/panels/schedule-panel.ts +0 -321
- package/src/panels/scrollable-list-panel.ts +0 -491
- package/src/panels/search-focus.ts +0 -32
- package/src/panels/security-panel.ts +0 -295
- package/src/panels/session-browser-panel.ts +0 -395
- package/src/panels/session-maintenance.ts +0 -125
- package/src/panels/subscription-panel.ts +0 -263
- package/src/panels/system-messages-panel.ts +0 -230
- package/src/panels/tasks-panel.ts +0 -344
- package/src/panels/thinking-panel.ts +0 -304
- package/src/panels/token-budget-panel.ts +0 -475
- package/src/panels/tool-inspector-panel.ts +0 -436
- package/src/panels/types.ts +0 -54
- package/src/renderer/panel-composite.ts +0 -158
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/renderer/panel-workspace-bar.ts +0 -42
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/tools/agent-harness-panel-metadata.ts +0 -211
- /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
|
@@ -90,15 +90,6 @@ export function requirePluginPathOptions(
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
export function openCommandPanel(
|
|
94
|
-
context: Pick<CommandContext, 'showPanel'>,
|
|
95
|
-
panelId: string,
|
|
96
|
-
pane?: 'top' | 'bottom',
|
|
97
|
-
): void {
|
|
98
|
-
const showPanel = requireContextValue(context.showPanel, 'showPanel');
|
|
99
|
-
showPanel(panelId, pane);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
93
|
export function requireKeybindingsManager(context: CommandContext) {
|
|
103
94
|
return requireContextValue(context.workspace.keybindingsManager, 'workspace.keybindingsManager');
|
|
104
95
|
}
|
|
@@ -107,10 +98,6 @@ export function requireProfileManager(context: CommandContext) {
|
|
|
107
98
|
return requireContextValue(context.workspace.profileManager, 'workspace.profileManager');
|
|
108
99
|
}
|
|
109
100
|
|
|
110
|
-
export function requirePanelManager(context: CommandContext) {
|
|
111
|
-
return requireContextValue(context.workspace.panelManager, 'workspace.panelManager');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
101
|
export function requireBookmarkManager(context: CommandContext) {
|
|
115
102
|
return requireContextValue(context.workspace.bookmarkManager, 'workspace.bookmarkManager');
|
|
116
103
|
}
|
|
@@ -8,6 +8,7 @@ export function registerSecurityRuntimeCommands(registry: CommandRegistry): void
|
|
|
8
8
|
name: 'security',
|
|
9
9
|
aliases: [],
|
|
10
10
|
description: 'Inspect security posture, attack paths, and review state',
|
|
11
|
+
hidden: true,
|
|
11
12
|
usage: '[review | attack-paths | tokens]',
|
|
12
13
|
handler(args, ctx) {
|
|
13
14
|
const subcommand = args[0]?.toLowerCase() ?? 'review';
|
|
@@ -250,6 +250,7 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
250
250
|
registry.register({
|
|
251
251
|
name: 'sessions',
|
|
252
252
|
description: 'List saved sessions',
|
|
253
|
+
hidden: true,
|
|
253
254
|
async handler(_args, ctx) {
|
|
254
255
|
const sessionManager = requireSessionManager(ctx);
|
|
255
256
|
const sessions = sessionManager.list();
|
|
@@ -105,7 +105,7 @@ function listRegisteredCommandItems(registry: CommandRegistry): SelectionItem[]
|
|
|
105
105
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
106
106
|
.map((command) => ({
|
|
107
107
|
id: `/${command.name}`,
|
|
108
|
-
label: `/${command.name}`,
|
|
108
|
+
label: command.hidden ? `/${command.name} (hidden)` : `/${command.name}`,
|
|
109
109
|
detail: commandDetail(command),
|
|
110
110
|
category: commandCategory(command.name),
|
|
111
111
|
primaryAction: 'select',
|
|
@@ -199,6 +199,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
199
199
|
name: 'shortcuts',
|
|
200
200
|
aliases: ['keys', 'keybinds'],
|
|
201
201
|
description: 'Show keyboard shortcuts reference',
|
|
202
|
+
hidden: true,
|
|
202
203
|
handler(_args, ctx) {
|
|
203
204
|
if (ctx.openShortcutsOverlay) {
|
|
204
205
|
ctx.openShortcutsOverlay();
|
|
@@ -212,6 +213,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
212
213
|
name: 'keybindings',
|
|
213
214
|
aliases: ['kb'],
|
|
214
215
|
description: 'List current keyboard bindings and their config file path',
|
|
216
|
+
hidden: true,
|
|
215
217
|
handler(_args, ctx) {
|
|
216
218
|
const km = requireKeybindingsManager(ctx);
|
|
217
219
|
const all = km.getAll();
|
|
@@ -275,6 +277,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
275
277
|
name: 'reset',
|
|
276
278
|
aliases: [],
|
|
277
279
|
description: 'Full reset: clear display and conversation context',
|
|
280
|
+
hidden: true,
|
|
278
281
|
handler(_args, ctx) {
|
|
279
282
|
ctx.session.conversationManager.resetAll();
|
|
280
283
|
if (ctx.reloadSystemPrompt) {
|
|
@@ -310,6 +313,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
310
313
|
name: 'effort',
|
|
311
314
|
aliases: ['e'],
|
|
312
315
|
description: 'Show or set reasoning effort level',
|
|
316
|
+
hidden: true,
|
|
313
317
|
usage: '[level]',
|
|
314
318
|
argsHint: '<instant|low|medium|high>',
|
|
315
319
|
async handler(args, ctx) {
|
|
@@ -326,7 +330,6 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
326
330
|
if (ctx.openSelection) {
|
|
327
331
|
const descriptions: Record<string, string> = {
|
|
328
332
|
...EFFORT_DESCRIPTIONS,
|
|
329
|
-
medium: 'Balanced speed and quality (default)',
|
|
330
333
|
};
|
|
331
334
|
const items: SelectionItem[] = validLevels.map((level) => ({
|
|
332
335
|
id: level,
|
|
@@ -73,6 +73,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
73
73
|
name: 'subscription',
|
|
74
74
|
aliases: ['subs'],
|
|
75
75
|
description: 'Manage provider subscription sessions and, when supported, let them override ambient API keys for matching providers',
|
|
76
|
+
hidden: true,
|
|
76
77
|
usage: '[review|list|providers|inspect <provider>|login <provider> start [--no-browser] --yes|login <provider> finish <code-or-url> --yes|logout <provider> --yes|bundle export <path> --yes|bundle inspect <path>]',
|
|
77
78
|
async handler(args, ctx) {
|
|
78
79
|
const parsed = stripYesFlag(args);
|
|
@@ -112,11 +113,17 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
112
113
|
ctx.print(`No stored or available subscription provider named ${provider}.`);
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
let inspection;
|
|
117
|
+
try {
|
|
118
|
+
inspection = await inspectProviderAuth(provider, {
|
|
119
|
+
serviceRegistry: services,
|
|
120
|
+
subscriptionManager: manager,
|
|
121
|
+
secretsManager: requireSecretsManager(ctx),
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
ctx.print(`Could not inspect provider auth for ${provider}: ${error instanceof Error ? error.message : String(error)}`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
120
127
|
ctx.print([
|
|
121
128
|
`Subscription ${provider}`,
|
|
122
129
|
` configured ${inspection.configured ? 'yes' : 'no'}`,
|
|
@@ -228,7 +235,13 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
228
235
|
ctx.print(`No pending OAuth login for ${provider}. Start with /subscription login ${provider} start --yes.`);
|
|
229
236
|
return;
|
|
230
237
|
}
|
|
231
|
-
|
|
238
|
+
let token;
|
|
239
|
+
try {
|
|
240
|
+
token = await exchangeOpenAICodexCode(code, pending.verifier);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
ctx.print(`Could not exchange authorization code for ${provider}: ${error instanceof Error ? error.message : String(error)}`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
232
245
|
const now = Date.now();
|
|
233
246
|
const record = manager.saveSubscription({
|
|
234
247
|
provider,
|
|
@@ -251,7 +264,13 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
251
264
|
return;
|
|
252
265
|
}
|
|
253
266
|
const activeConfig = resolveManualLoginConfig(resolved.oauth);
|
|
254
|
-
|
|
267
|
+
let record;
|
|
268
|
+
try {
|
|
269
|
+
record = await manager.completeOAuthLogin(provider, activeConfig, code);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
ctx.print(`Could not complete OAuth login for ${provider}: ${error instanceof Error ? error.message : String(error)}`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
255
274
|
ctx.print([
|
|
256
275
|
`Stored subscription session for ${provider}.`,
|
|
257
276
|
` token type ${record.tokenType}`,
|
|
@@ -302,17 +321,22 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
302
321
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
303
322
|
writeFileSync(targetPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
|
|
304
323
|
ctx.print(`Subscription bundle exported to ${targetPath}`);
|
|
324
|
+
ctx.print('This file contains active sign-in tokens. Keep it private and delete it after use.');
|
|
305
325
|
return;
|
|
306
326
|
}
|
|
307
327
|
if (mode === 'inspect') {
|
|
308
|
-
|
|
328
|
+
try {
|
|
329
|
+
ctx.print(inspectBundle(targetPath));
|
|
330
|
+
} catch (error) {
|
|
331
|
+
ctx.print(`Could not read that bundle file: ${error instanceof Error ? error.message : String(error)}`);
|
|
332
|
+
}
|
|
309
333
|
return;
|
|
310
334
|
}
|
|
311
335
|
ctx.print('Usage: /subscription bundle <export|inspect> <path>');
|
|
312
336
|
return;
|
|
313
337
|
}
|
|
314
338
|
|
|
315
|
-
ctx.print('Usage: /subscription [review|list|providers|inspect <provider>|login <provider> start [--no-browser]
|
|
339
|
+
ctx.print('Usage: /subscription [review|list|providers|inspect <provider>|login <provider> start [--no-browser] --yes|login <provider> finish <code-or-url> --yes|logout <provider> --yes|bundle export <path> --yes|bundle inspect <path>]');
|
|
316
340
|
},
|
|
317
341
|
});
|
|
318
342
|
}
|
|
@@ -22,6 +22,7 @@ export function registerSupportBundleRuntimeCommands(registry: CommandRegistry):
|
|
|
22
22
|
registry.register({
|
|
23
23
|
name: 'bundle',
|
|
24
24
|
description: 'Export, inspect, or import redacted Agent support bundles from the TUI',
|
|
25
|
+
hidden: true,
|
|
25
26
|
usage: '[export [path] --yes|inspect <path>|import <path> --yes]',
|
|
26
27
|
argsHint: 'export|inspect|import',
|
|
27
28
|
async handler(args, ctx) {
|
|
@@ -46,7 +47,13 @@ export function registerSupportBundleRuntimeCommands(registry: CommandRegistry):
|
|
|
46
47
|
workingDirectory: shellPaths.workingDirectory,
|
|
47
48
|
homeDirectory: shellPaths.homeDirectory,
|
|
48
49
|
};
|
|
49
|
-
|
|
50
|
+
let result;
|
|
51
|
+
try {
|
|
52
|
+
result = await handleBundleCommand(runtime);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
ctx.print(`Could not complete bundle operation: ${error instanceof Error ? error.message : String(error)}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
50
57
|
ctx.print(result.output);
|
|
51
58
|
},
|
|
52
59
|
});
|
|
@@ -52,6 +52,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
52
52
|
name: 'tasks',
|
|
53
53
|
aliases: ['task'],
|
|
54
54
|
description: 'Inspect connected-host tasks without starting or mutating local background work',
|
|
55
|
+
hidden: true,
|
|
55
56
|
usage: '[list [status|kind] | show <taskId> | output <taskId>]',
|
|
56
57
|
handler(args, ctx) {
|
|
57
58
|
const subcommand = args[0]?.toLowerCase() ?? 'list';
|
|
@@ -4,6 +4,7 @@ export function registerTtsRuntimeCommands(registry: CommandRegistry): void {
|
|
|
4
4
|
registry.register({
|
|
5
5
|
name: 'tts',
|
|
6
6
|
description: 'Submit a normal prompt and play the assistant response through live TTS',
|
|
7
|
+
hidden: true,
|
|
7
8
|
usage: '<prompt>|stop',
|
|
8
9
|
handler(args, ctx) {
|
|
9
10
|
const first = (args[0] ?? '').toLowerCase();
|
|
@@ -39,6 +39,7 @@ export function registerVibeRuntimeCommands(registry: CommandRegistry): void {
|
|
|
39
39
|
name: 'vibe',
|
|
40
40
|
aliases: ['vibes'],
|
|
41
41
|
description: 'Inspect, create, and import VIBE.md personality files',
|
|
42
|
+
hidden: true,
|
|
42
43
|
usage: '[status|init|show|import-persona]',
|
|
43
44
|
async handler(args, ctx) {
|
|
44
45
|
const sub = (args[0] ?? 'status').toLowerCase();
|
package/src/input/commands.ts
CHANGED
|
@@ -38,6 +38,8 @@ import { registerBriefRuntimeCommands } from './commands/brief-runtime.ts';
|
|
|
38
38
|
import { registerSupportBundleRuntimeCommands } from './commands/support-bundle-runtime.ts';
|
|
39
39
|
import { registerCompatRuntimeCommands } from './commands/compat-runtime.ts';
|
|
40
40
|
import { registerOperatorActionRuntimeCommands } from './commands/operator-actions-runtime.ts';
|
|
41
|
+
import { registerEmailRuntimeCommands } from './commands/email-runtime.ts';
|
|
42
|
+
import { registerCalendarRuntimeCommands } from './commands/calendar-runtime.ts';
|
|
41
43
|
|
|
42
44
|
function registerAgentMemoryCommand(registry: CommandRegistry): void {
|
|
43
45
|
registry.register({
|
|
@@ -63,12 +65,14 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
|
|
|
63
65
|
registerSupportBundleRuntimeCommands(registry);
|
|
64
66
|
registerCompatRuntimeCommands(registry);
|
|
65
67
|
registerOperatorActionRuntimeCommands(registry);
|
|
68
|
+
registerCalendarRuntimeCommands(registry);
|
|
66
69
|
registerAgentRuntimeProfileRuntimeCommands(registry);
|
|
67
70
|
registerVibeRuntimeCommands(registry);
|
|
68
71
|
registerPersonasRuntimeCommands(registry);
|
|
69
72
|
registerAgentSkillsRuntimeCommands(registry);
|
|
70
73
|
registerRoutinesRuntimeCommands(registry);
|
|
71
74
|
registerChannelsRuntimeCommands(registry);
|
|
75
|
+
registerEmailRuntimeCommands(registry);
|
|
72
76
|
registerDelegationRuntimeCommands(registry);
|
|
73
77
|
registerConfigCommand(registry);
|
|
74
78
|
registerOperatorRuntimeCommands(registry);
|
|
@@ -33,11 +33,8 @@ import type { AgentWorkspace } from './agent-workspace.ts';
|
|
|
33
33
|
import type { SessionPickerModal } from './session-picker-modal.ts';
|
|
34
34
|
import type { ProfilePickerModal } from './profile-picker-modal.ts';
|
|
35
35
|
import type { WrappedPromptInfo } from './handler-prompt-buffer.ts';
|
|
36
|
-
import type { Panel } from '../panels/types.ts';
|
|
37
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
38
36
|
import type { KeybindingsManager } from './keybindings.ts';
|
|
39
37
|
import type { ModelPickerTarget } from './model-picker.ts';
|
|
40
|
-
import type { PanelMouseLayout } from './handler-feed-routes.ts';
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
40
|
* Initial mutable scalar values for InputFeedContext.
|
|
@@ -45,7 +42,7 @@ import type { PanelMouseLayout } from './handler-feed-routes.ts';
|
|
|
45
42
|
* **Mutable fields** (synced per-feed via syncFeedContextMutableFields or inside
|
|
46
43
|
* action closures that call syncFeedContextMutableFields):
|
|
47
44
|
* - `prompt`, `cursorPos` — current text buffer state
|
|
48
|
-
* - `commandMode`, `
|
|
45
|
+
* - `commandMode`, `indicatorFocused` — focus-mode flags
|
|
49
46
|
* - `helpOverlayActive`, `helpScrollOffset` — help overlay state
|
|
50
47
|
* - `shortcutsOverlayActive`, `shortcutsScrollOffset` — shortcuts overlay state
|
|
51
48
|
* - `nextPasteId`, `nextImageId` — monotonically increasing ID counters
|
|
@@ -58,7 +55,6 @@ export interface FeedContextMutableInit {
|
|
|
58
55
|
cursorPos: number;
|
|
59
56
|
inputScrollTop: number;
|
|
60
57
|
commandMode: boolean;
|
|
61
|
-
panelFocused: boolean;
|
|
62
58
|
indicatorFocused: boolean;
|
|
63
59
|
helpOverlayActive: boolean;
|
|
64
60
|
helpScrollOffset: number;
|
|
@@ -69,7 +65,6 @@ export interface FeedContextMutableInit {
|
|
|
69
65
|
mouseDownRow: number;
|
|
70
66
|
mouseDownCol: number;
|
|
71
67
|
contentWidth: number;
|
|
72
|
-
panelMouseLayout: PanelMouseLayout | null;
|
|
73
68
|
selectionCallback: ((result: SelectionResult | null) => void) | null;
|
|
74
69
|
}
|
|
75
70
|
|
|
@@ -83,7 +78,7 @@ export interface FeedContextMutableInit {
|
|
|
83
78
|
* - `filePicker`, `modelPicker`, `processModal`, `liveTailModal`,
|
|
84
79
|
* `contextInspectorModal`, `blockActionsMenu`, `searchManager`, `historySearch` —
|
|
85
80
|
* service objects constructed once
|
|
86
|
-
* - `
|
|
81
|
+
* - `keybindingsManager` — from uiServices, stable
|
|
87
82
|
* - `modalStack` — reference to the handler's shared array
|
|
88
83
|
* - `getHistory`, `getViewportHeight`, `getScrollTop`, `scroll`, `exitApp` — callbacks
|
|
89
84
|
* - `commandRegistry`, `commandContext`, `autocomplete`, `inputHistory`,
|
|
@@ -120,7 +115,6 @@ export interface FeedContextStableRefs {
|
|
|
120
115
|
modalStack: string[];
|
|
121
116
|
inputHistory: InputHistory | null;
|
|
122
117
|
conversationManager: ConversationManager | null;
|
|
123
|
-
panelManager: PanelManager;
|
|
124
118
|
keybindingsManager: KeybindingsManager;
|
|
125
119
|
getHistory: () => InfiniteBuffer;
|
|
126
120
|
getViewportHeight: () => number;
|
|
@@ -147,7 +141,6 @@ export interface FeedContextClosures {
|
|
|
147
141
|
executeBlockAction: (id: string) => void;
|
|
148
142
|
cycleAgentWorkspaceCategory: (direction: 'next' | 'prev') => void;
|
|
149
143
|
dismissAgentWorkspace: () => boolean;
|
|
150
|
-
onPanelInputConsumed: (activePanel: Panel | null, key: string) => void;
|
|
151
144
|
getWrappedPromptInfo: (contentWidth: number) => WrappedPromptInfo;
|
|
152
145
|
moveCursorVertical: (direction: -1 | 1) => boolean;
|
|
153
146
|
handlePathCompletion: () => boolean;
|
|
@@ -198,7 +191,7 @@ export function buildInitialFeedContext(
|
|
|
198
191
|
* - `prompt` — current prompt text buffer
|
|
199
192
|
* - `cursorPos` — caret position within prompt
|
|
200
193
|
* - `commandMode` — whether command-mode prefix is active
|
|
201
|
-
|
|
194
|
+
|
|
202
195
|
* - `indicatorFocused` — whether the status indicator owns focus
|
|
203
196
|
* - `helpOverlayActive` / `helpScrollOffset` — help overlay visibility and scroll
|
|
204
197
|
* - `shortcutsOverlayActive` / `shortcutsScrollOffset` — shortcuts overlay state
|
|
@@ -233,7 +226,6 @@ export function syncFeedContextMutableFields(
|
|
|
233
226
|
ctx.cursorPos = fields.cursorPos;
|
|
234
227
|
ctx.inputScrollTop = fields.inputScrollTop;
|
|
235
228
|
ctx.commandMode = fields.commandMode;
|
|
236
|
-
ctx.panelFocused = fields.panelFocused;
|
|
237
229
|
ctx.indicatorFocused = fields.indicatorFocused;
|
|
238
230
|
ctx.helpOverlayActive = fields.helpOverlayActive;
|
|
239
231
|
ctx.helpScrollOffset = fields.helpScrollOffset;
|
|
@@ -245,5 +237,4 @@ export function syncFeedContextMutableFields(
|
|
|
245
237
|
ctx.mouseDownRow = fields.mouseDownRow;
|
|
246
238
|
ctx.mouseDownCol = fields.mouseDownCol;
|
|
247
239
|
ctx.contentWidth = fields.contentWidth;
|
|
248
|
-
ctx.panelMouseLayout = fields.panelMouseLayout;
|
|
249
240
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { loadSkillByTrigger } from '@pellux/goodvibes-sdk/platform/tools';
|
|
2
|
+
import { summarizeCommandError } from './commands/command-error.ts';
|
|
2
3
|
import type { CommandContext, CommandRegistry } from './command-registry.ts';
|
|
3
4
|
import type { AutocompleteEngine } from './autocomplete.ts';
|
|
4
5
|
import type { InputToken } from '@pellux/goodvibes-sdk/platform/core';
|
|
5
6
|
import type { ConversationManager } from '../core/conversation';
|
|
6
|
-
import type {
|
|
7
|
-
import { handleClipboardPaste, type ClipboardPasteSource } from './handler-content-actions.ts';
|
|
7
|
+
import type { ClipboardPasteSource } from './handler-content-actions.ts';
|
|
8
8
|
|
|
9
9
|
export type CommandModeRouteState = {
|
|
10
10
|
commandMode: boolean;
|
|
@@ -14,8 +14,6 @@ export type CommandModeRouteState = {
|
|
|
14
14
|
modalStack: string[];
|
|
15
15
|
commandRegistry: CommandRegistry | null;
|
|
16
16
|
commandContext?: CommandContext;
|
|
17
|
-
panelFocused: boolean;
|
|
18
|
-
panelManager: PanelManager;
|
|
19
17
|
conversationManager: ConversationManager | null;
|
|
20
18
|
requestRender: () => void;
|
|
21
19
|
handleEscape: () => void;
|
|
@@ -88,7 +86,7 @@ export function handleCommandModeToken(state: CommandModeRouteState, token: Inpu
|
|
|
88
86
|
const parts = raw.slice(1).trim().split(/\s+/);
|
|
89
87
|
const name = parts[0];
|
|
90
88
|
const args = parts.slice(1);
|
|
91
|
-
const ctx =
|
|
89
|
+
const ctx = state.commandContext;
|
|
92
90
|
const commandPromise = state.commandRegistry.get(name)
|
|
93
91
|
? state.commandRegistry.execute(name, args, ctx)
|
|
94
92
|
: (ctx.executeCommand?.(name, args) ?? Promise.resolve(false));
|
|
@@ -110,6 +108,10 @@ export function handleCommandModeToken(state: CommandModeRouteState, token: Inpu
|
|
|
110
108
|
state.requestRender();
|
|
111
109
|
}
|
|
112
110
|
}
|
|
111
|
+
}).catch((error: unknown) => {
|
|
112
|
+
const message = summarizeCommandError(error);
|
|
113
|
+
state.conversationManager?.log(message, { fg: '#ef4444' });
|
|
114
|
+
state.requestRender();
|
|
113
115
|
});
|
|
114
116
|
} else {
|
|
115
117
|
closeCommandMode();
|
|
@@ -120,58 +122,3 @@ export function handleCommandModeToken(state: CommandModeRouteState, token: Inpu
|
|
|
120
122
|
return token.logicalName !== 'left' && token.logicalName !== 'right';
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
function withPanelFocusSync(context: CommandContext, state: CommandModeRouteState): CommandContext {
|
|
124
|
-
return {
|
|
125
|
-
...context,
|
|
126
|
-
openPanelPicker: context.openPanelPicker
|
|
127
|
-
? () => {
|
|
128
|
-
context.openPanelPicker?.();
|
|
129
|
-
state.panelFocused = false;
|
|
130
|
-
}
|
|
131
|
-
: undefined,
|
|
132
|
-
showPanel: context.showPanel
|
|
133
|
-
? (panelId, pane) => {
|
|
134
|
-
context.showPanel?.(panelId, pane);
|
|
135
|
-
state.panelFocused = false;
|
|
136
|
-
}
|
|
137
|
-
: undefined,
|
|
138
|
-
focusPanels: context.focusPanels
|
|
139
|
-
? () => {
|
|
140
|
-
context.focusPanels?.();
|
|
141
|
-
state.panelFocused = false;
|
|
142
|
-
}
|
|
143
|
-
: undefined,
|
|
144
|
-
focusPrompt: context.focusPrompt
|
|
145
|
-
? () => {
|
|
146
|
-
context.focusPrompt?.();
|
|
147
|
-
state.panelFocused = false;
|
|
148
|
-
}
|
|
149
|
-
: undefined,
|
|
150
|
-
pasteFromClipboard: () => {
|
|
151
|
-
const result = handleClipboardPaste({
|
|
152
|
-
prompt: state.prompt,
|
|
153
|
-
cursorPos: state.cursorPos,
|
|
154
|
-
pasteRegistry: state.pasteRegistry,
|
|
155
|
-
nextPasteId: state.nextPasteId,
|
|
156
|
-
imageRegistry: state.imageRegistry,
|
|
157
|
-
nextImageId: state.nextImageId,
|
|
158
|
-
saveUndoState: state.saveUndoState,
|
|
159
|
-
ensureInputCursorVisible: state.ensureInputCursorVisible,
|
|
160
|
-
requestRender: state.requestRender,
|
|
161
|
-
}, context.workspace.shellPaths?.workingDirectory ?? state.projectRoot, state.clipboard);
|
|
162
|
-
state.prompt = result.prompt;
|
|
163
|
-
state.cursorPos = result.cursorPos;
|
|
164
|
-
state.nextImageId = result.nextImageId;
|
|
165
|
-
state.nextPasteId = result.nextPasteId;
|
|
166
|
-
return result;
|
|
167
|
-
},
|
|
168
|
-
executeCommand: async (name, args) => {
|
|
169
|
-
const wrapped = withPanelFocusSync(context, state);
|
|
170
|
-
const handled = state.commandRegistry?.get(name)
|
|
171
|
-
? await state.commandRegistry.execute(name, args, wrapped)
|
|
172
|
-
: false;
|
|
173
|
-
if (handled) return true;
|
|
174
|
-
return (await context.executeCommand?.(name, args)) ?? false;
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
}
|
|
@@ -12,129 +12,8 @@ import {
|
|
|
12
12
|
moveCursorVertical as computeCursorVerticalMove,
|
|
13
13
|
} from './handler-prompt-buffer.ts';
|
|
14
14
|
import { cleanupMarkerRegistry, expandPrompt, findMarkerAtPos, registerPaste } from './handler-content-actions.ts';
|
|
15
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
16
|
-
import type { KeybindingsManager } from './keybindings.ts';
|
|
17
15
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
18
16
|
|
|
19
|
-
export type PanelFocusRouteState = {
|
|
20
|
-
panelManager: PanelManager;
|
|
21
|
-
keybindingsManager: KeybindingsManager;
|
|
22
|
-
panelFocused: boolean;
|
|
23
|
-
commandMode: boolean;
|
|
24
|
-
searchActive: boolean;
|
|
25
|
-
autocompleteActive: boolean;
|
|
26
|
-
requestRender: () => void;
|
|
27
|
-
handlePathCompletion: () => boolean;
|
|
28
|
-
cycleAgentWorkspaceCategory: (direction: 'next' | 'prev') => void;
|
|
29
|
-
dismissAgentWorkspace: () => boolean;
|
|
30
|
-
onPanelInputConsumed?: (activePanel: import('../panels/types.ts').Panel | null, key: string) => void;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function handlePanelFocusToken(state: PanelFocusRouteState, token: InputToken): {
|
|
34
|
-
handled: boolean;
|
|
35
|
-
panelFocused: boolean;
|
|
36
|
-
} {
|
|
37
|
-
let panelFocused = state.panelFocused;
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
token.type === 'key' &&
|
|
41
|
-
token.logicalName === 'tab' &&
|
|
42
|
-
!state.commandMode &&
|
|
43
|
-
!state.searchActive &&
|
|
44
|
-
!state.autocompleteActive
|
|
45
|
-
) {
|
|
46
|
-
if (panelFocused) {
|
|
47
|
-
panelFocused = false;
|
|
48
|
-
state.requestRender();
|
|
49
|
-
return { handled: true, panelFocused };
|
|
50
|
-
}
|
|
51
|
-
if (state.handlePathCompletion()) {
|
|
52
|
-
state.requestRender();
|
|
53
|
-
return { handled: true, panelFocused };
|
|
54
|
-
}
|
|
55
|
-
return { handled: false, panelFocused };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (!panelFocused) {
|
|
59
|
-
return { handled: false, panelFocused };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (token.type === 'key') {
|
|
63
|
-
// I6: two-stage Escape — give the panel a chance to consume escape first
|
|
64
|
-
// (e.g. dismiss a confirm dialog or clear search). Only unfocus if the
|
|
65
|
-
// panel returns false (unconsumed) or there is no active panel.
|
|
66
|
-
if (token.logicalName === 'escape') {
|
|
67
|
-
const activePanel = state.panelManager.getActive();
|
|
68
|
-
const panelConsumedEscape = activePanel?.handleInput?.('escape') ?? false;
|
|
69
|
-
if (panelConsumedEscape) {
|
|
70
|
-
state.onPanelInputConsumed?.(activePanel!, 'escape');
|
|
71
|
-
state.requestRender();
|
|
72
|
-
return { handled: true, panelFocused };
|
|
73
|
-
}
|
|
74
|
-
panelFocused = false;
|
|
75
|
-
state.requestRender();
|
|
76
|
-
return { handled: true, panelFocused };
|
|
77
|
-
}
|
|
78
|
-
const kb = state.keybindingsManager;
|
|
79
|
-
if (kb.matches('panel-tab-next', token)) {
|
|
80
|
-
state.cycleAgentWorkspaceCategory('next');
|
|
81
|
-
return { handled: true, panelFocused: false };
|
|
82
|
-
}
|
|
83
|
-
if (kb.matches('panel-tab-prev', token)) {
|
|
84
|
-
state.cycleAgentWorkspaceCategory('prev');
|
|
85
|
-
return { handled: true, panelFocused: false };
|
|
86
|
-
}
|
|
87
|
-
if (kb.matches('panel-close-all', token)) {
|
|
88
|
-
if (state.dismissAgentWorkspace()) {
|
|
89
|
-
return { handled: true, panelFocused: false };
|
|
90
|
-
}
|
|
91
|
-
const pm = state.panelManager;
|
|
92
|
-
for (const p of pm.getAllOpen()) pm.close(p.id);
|
|
93
|
-
panelFocused = false;
|
|
94
|
-
state.requestRender();
|
|
95
|
-
return { handled: true, panelFocused };
|
|
96
|
-
}
|
|
97
|
-
if (kb.matches('panel-close', token)) {
|
|
98
|
-
if (state.dismissAgentWorkspace()) {
|
|
99
|
-
return { handled: true, panelFocused: false };
|
|
100
|
-
}
|
|
101
|
-
const pm = state.panelManager;
|
|
102
|
-
const active = pm.getActivePanel();
|
|
103
|
-
if (active) {
|
|
104
|
-
pm.close(active.id);
|
|
105
|
-
}
|
|
106
|
-
panelFocused = false;
|
|
107
|
-
state.requestRender();
|
|
108
|
-
return { handled: true, panelFocused };
|
|
109
|
-
}
|
|
110
|
-
if (token.ctrl || token.meta) {
|
|
111
|
-
return { handled: false, panelFocused };
|
|
112
|
-
}
|
|
113
|
-
const activePanel = state.panelManager.getActive();
|
|
114
|
-
if (activePanel?.handleInput) {
|
|
115
|
-
const consumed = activePanel.handleInput(token.logicalName);
|
|
116
|
-
if (consumed) {
|
|
117
|
-
state.onPanelInputConsumed?.(activePanel, token.logicalName);
|
|
118
|
-
state.requestRender();
|
|
119
|
-
return { handled: true, panelFocused };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (token.type === 'text' && token.value) {
|
|
125
|
-
const activePanel = state.panelManager.getActive();
|
|
126
|
-
if (activePanel?.handleInput) {
|
|
127
|
-
for (const ch of token.value) {
|
|
128
|
-
activePanel.handleInput(ch);
|
|
129
|
-
}
|
|
130
|
-
state.requestRender();
|
|
131
|
-
}
|
|
132
|
-
return { handled: true, panelFocused };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return { handled: true, panelFocused };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
17
|
export type IndicatorFocusRouteState = {
|
|
139
18
|
indicatorFocused: boolean;
|
|
140
19
|
modalOpened: (name: string) => void;
|
|
@@ -512,8 +391,6 @@ export function handlePromptKeyToken(state: KeyRouteState, token: InputToken): {
|
|
|
512
391
|
export type MouseRouteState = {
|
|
513
392
|
conversationManager: ConversationManager | null;
|
|
514
393
|
selection: SelectionManager;
|
|
515
|
-
panelManager: PanelManager;
|
|
516
|
-
panelMouseLayout: PanelMouseLayout | null;
|
|
517
394
|
mouseDownRow: number;
|
|
518
395
|
mouseDownCol: number;
|
|
519
396
|
scrollTop: number;
|
|
@@ -525,71 +402,6 @@ export type MouseRouteState = {
|
|
|
525
402
|
handleCopy: () => void;
|
|
526
403
|
};
|
|
527
404
|
|
|
528
|
-
export type PanelMouseLayout = {
|
|
529
|
-
x: number;
|
|
530
|
-
y: number;
|
|
531
|
-
width: number;
|
|
532
|
-
height: number;
|
|
533
|
-
hasBottomPane: boolean;
|
|
534
|
-
verticalSplitRatio: number;
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
function clampRatio(value: number): number {
|
|
538
|
-
return Math.max(0.2, Math.min(0.8, value));
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
function getActivePanelInPane(panelManager: PanelManager, pane: 'top' | 'bottom') {
|
|
542
|
-
const target = pane === 'top' ? panelManager.getTopPane() : panelManager.getBottomPane();
|
|
543
|
-
return target.panels[target.activeIndex] ?? null;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
function getPanelUnderMouse(
|
|
547
|
-
panelManager: PanelManager,
|
|
548
|
-
layout: PanelMouseLayout | null,
|
|
549
|
-
row: number,
|
|
550
|
-
col: number,
|
|
551
|
-
) {
|
|
552
|
-
if (
|
|
553
|
-
layout === null
|
|
554
|
-
|| !panelManager.isVisible()
|
|
555
|
-
|| panelManager.getAllOpen().length === 0
|
|
556
|
-
|| col < layout.x
|
|
557
|
-
|| col >= layout.x + layout.width
|
|
558
|
-
|| row < layout.y
|
|
559
|
-
|| row >= layout.y + layout.height
|
|
560
|
-
) {
|
|
561
|
-
return null;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const panelRow = row - layout.y;
|
|
565
|
-
if (!layout.hasBottomPane) {
|
|
566
|
-
return getActivePanelInPane(panelManager, 'top');
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const panelAreaRows = Math.max(0, layout.height - 1);
|
|
570
|
-
const contentRows = Math.max(0, panelAreaRows - 3);
|
|
571
|
-
const topContentRows = contentRows <= 1
|
|
572
|
-
? contentRows
|
|
573
|
-
: Math.max(1, Math.floor(contentRows * clampRatio(layout.verticalSplitRatio)));
|
|
574
|
-
const topLastRow = 2 + topContentRows;
|
|
575
|
-
|
|
576
|
-
return panelRow <= topLastRow
|
|
577
|
-
? getActivePanelInPane(panelManager, 'top')
|
|
578
|
-
: getActivePanelInPane(panelManager, 'bottom');
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
function scrollPanelUnderMouse(
|
|
582
|
-
state: MouseRouteState,
|
|
583
|
-
token: Extract<InputToken, { type: 'mouse' }>,
|
|
584
|
-
deltaRows: number,
|
|
585
|
-
): boolean {
|
|
586
|
-
const panel = getPanelUnderMouse(state.panelManager, state.panelMouseLayout, token.row, token.col);
|
|
587
|
-
if (!panel?.handleScroll) return false;
|
|
588
|
-
const consumed = panel.handleScroll(deltaRows);
|
|
589
|
-
if (consumed) state.requestRender();
|
|
590
|
-
return true;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
405
|
export function handleMouseToken(state: MouseRouteState, token: InputToken): {
|
|
594
406
|
handled: boolean;
|
|
595
407
|
mouseDownRow: number;
|
|
@@ -605,16 +417,10 @@ export function handleMouseToken(state: MouseRouteState, token: InputToken): {
|
|
|
605
417
|
const viewportRow = token.row - headerH;
|
|
606
418
|
|
|
607
419
|
if (token.button === 64) {
|
|
608
|
-
if (scrollPanelUnderMouse(state, token, -3)) {
|
|
609
|
-
return { handled: true, mouseDownRow, mouseDownCol };
|
|
610
|
-
}
|
|
611
420
|
state.scroll(-3);
|
|
612
421
|
return { handled: true, mouseDownRow, mouseDownCol };
|
|
613
422
|
}
|
|
614
423
|
if (token.button === 65) {
|
|
615
|
-
if (scrollPanelUnderMouse(state, token, 3)) {
|
|
616
|
-
return { handled: true, mouseDownRow, mouseDownCol };
|
|
617
|
-
}
|
|
618
424
|
state.scroll(3);
|
|
619
425
|
return { handled: true, mouseDownRow, mouseDownCol };
|
|
620
426
|
}
|