@pellux/goodvibes-agent 1.4.4 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +52 -7
  3. package/dist/package/main.js +7491 -12253
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +1 -1
  6. package/docs/getting-started.md +2 -2
  7. package/docs/release-and-publishing.md +1 -1
  8. package/docs/tools-and-commands.md +5 -5
  9. package/package.json +4 -2
  10. package/release/live-verification/live-verification.json +13 -13
  11. package/release/live-verification/live-verification.md +15 -15
  12. package/release/performance-snapshot.json +2 -2
  13. package/release/release-notes.md +5 -7
  14. package/release/release-readiness.json +6 -6
  15. package/src/agent/behavior-discovery-summary.ts +4 -18
  16. package/src/agent/calendar-registry.ts +322 -0
  17. package/src/agent/competitive-feature-inventory.ts +268 -130
  18. package/src/agent/document-registry.ts +5 -1
  19. package/src/agent/email/email-service.ts +350 -0
  20. package/src/agent/email/imap-client.ts +596 -0
  21. package/src/agent/email/smtp-client.ts +453 -0
  22. package/src/agent/ics-calendar.ts +662 -0
  23. package/src/agent/ics-timezone.ts +172 -0
  24. package/src/agent/markdown-frontmatter.ts +31 -0
  25. package/src/agent/memory-safety.ts +1 -1
  26. package/src/agent/note-registry.ts +3 -9
  27. package/src/agent/persona-discovery.ts +3 -15
  28. package/src/agent/persona-registry.ts +1 -10
  29. package/src/agent/research-source-registry.ts +5 -1
  30. package/src/agent/routine-discovery.ts +3 -15
  31. package/src/agent/runtime-profile.ts +3 -0
  32. package/src/agent/skill-discovery.ts +3 -15
  33. package/src/agent/skill-draft-proposer.ts +203 -0
  34. package/src/agent/skill-draft-runner.ts +201 -0
  35. package/src/agent/skill-registry.ts +36 -1
  36. package/src/agent/skill-standard.ts +99 -0
  37. package/src/agent/vibe-file.ts +7 -22
  38. package/src/cli/completion.ts +1 -1
  39. package/src/cli/config-overrides.ts +10 -1
  40. package/src/cli/redaction.ts +17 -5
  41. package/src/config/provider-model.ts +2 -1
  42. package/src/config/secret-config.ts +13 -6
  43. package/src/core/activity-feed.ts +97 -0
  44. package/src/core/away-digest.ts +161 -0
  45. package/src/core/conversation-rendering.ts +7 -3
  46. package/src/core/conversation.ts +22 -15
  47. package/src/core/hardware-profile.ts +362 -0
  48. package/src/core/last-seen-store.ts +78 -0
  49. package/src/core/plain-language.ts +52 -0
  50. package/src/core/setup-incomplete-hint.ts +90 -0
  51. package/src/core/system-message-router.ts +38 -87
  52. package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
  53. package/src/input/agent-workspace-basic-command-editors.ts +39 -141
  54. package/src/input/agent-workspace-categories.ts +40 -125
  55. package/src/input/agent-workspace-command-editor.ts +4 -0
  56. package/src/input/agent-workspace-host-category.ts +0 -5
  57. package/src/input/agent-workspace-local-editor-submission.ts +3 -1
  58. package/src/input/agent-workspace-navigation.ts +10 -3
  59. package/src/input/agent-workspace-onboarding-actions.ts +132 -0
  60. package/src/input/agent-workspace-onboarding-categories.ts +29 -26
  61. package/src/input/agent-workspace-onboarding-finish.ts +11 -4
  62. package/src/input/agent-workspace-onboarding-state.ts +111 -0
  63. package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
  64. package/src/input/agent-workspace-profile-editors.ts +155 -0
  65. package/src/input/agent-workspace-subscription-editor.ts +7 -0
  66. package/src/input/agent-workspace-types.ts +5 -1
  67. package/src/input/agent-workspace.ts +65 -39
  68. package/src/input/command-registry.ts +18 -5
  69. package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
  70. package/src/input/commands/agent-skills-runtime.ts +60 -3
  71. package/src/input/commands/calendar-runtime.ts +209 -0
  72. package/src/input/commands/channels-runtime.ts +1 -0
  73. package/src/input/commands/command-error.ts +9 -0
  74. package/src/input/commands/compat-runtime.ts +1 -0
  75. package/src/input/commands/config.ts +1 -0
  76. package/src/input/commands/conversation-runtime.ts +1 -1
  77. package/src/input/commands/delegation-runtime.ts +5 -6
  78. package/src/input/commands/email-runtime.ts +387 -0
  79. package/src/input/commands/experience-runtime.ts +17 -4
  80. package/src/input/commands/guidance-runtime.ts +1 -1
  81. package/src/input/commands/health-runtime.ts +6 -1
  82. package/src/input/commands/knowledge-format.ts +73 -0
  83. package/src/input/commands/knowledge.ts +9 -74
  84. package/src/input/commands/local-provider-runtime.ts +2 -1
  85. package/src/input/commands/local-runtime.ts +10 -4
  86. package/src/input/commands/mcp-runtime.ts +7 -0
  87. package/src/input/commands/notify-runtime.ts +17 -1
  88. package/src/input/commands/onboarding-runtime.ts +1 -0
  89. package/src/input/commands/operator-actions-runtime.ts +1 -0
  90. package/src/input/commands/operator-runtime.ts +3 -0
  91. package/src/input/commands/personas-runtime.ts +1 -0
  92. package/src/input/commands/platform-access-runtime.ts +40 -17
  93. package/src/input/commands/product-runtime.ts +6 -1
  94. package/src/input/commands/provider-accounts-runtime.ts +3 -2
  95. package/src/input/commands/qrcode-runtime.ts +1 -0
  96. package/src/input/commands/routines-runtime.ts +1 -0
  97. package/src/input/commands/runtime-services.ts +0 -13
  98. package/src/input/commands/security-runtime.ts +1 -0
  99. package/src/input/commands/session-content.ts +1 -0
  100. package/src/input/commands/shell-core.ts +5 -2
  101. package/src/input/commands/subscription-runtime.ts +33 -9
  102. package/src/input/commands/support-bundle-runtime.ts +8 -1
  103. package/src/input/commands/tasks-runtime.ts +1 -0
  104. package/src/input/commands/tts-runtime.ts +1 -0
  105. package/src/input/commands/vibe-runtime.ts +1 -0
  106. package/src/input/commands.ts +4 -0
  107. package/src/input/feed-context-factory.ts +3 -12
  108. package/src/input/handler-command-route.ts +7 -60
  109. package/src/input/handler-feed-routes.ts +0 -194
  110. package/src/input/handler-feed.ts +2 -54
  111. package/src/input/handler-interactions.ts +0 -2
  112. package/src/input/handler-modal-stack.ts +0 -9
  113. package/src/input/handler-picker-routes.ts +24 -1
  114. package/src/input/handler-shortcuts.ts +11 -40
  115. package/src/input/handler-ui-state.ts +13 -0
  116. package/src/input/handler.ts +8 -35
  117. package/src/input/keybindings.ts +40 -17
  118. package/src/input/model-picker-local-fit.ts +130 -0
  119. package/src/input/shell-passthrough.ts +58 -0
  120. package/src/input/submission-router.ts +0 -5
  121. package/src/main.ts +129 -90
  122. package/src/renderer/activity-sidebar.ts +186 -0
  123. package/src/renderer/agent-workspace-context-lines.ts +5 -48
  124. package/src/renderer/agent-workspace-style.ts +1 -1
  125. package/src/renderer/agent-workspace.ts +14 -2
  126. package/src/renderer/compositor.ts +37 -125
  127. package/src/renderer/conversation-overlays.ts +3 -3
  128. package/src/renderer/help-overlay.ts +7 -5
  129. package/src/renderer/model-workspace.ts +101 -86
  130. package/src/{panels → renderer}/polish.ts +3 -3
  131. package/src/renderer/shell-surface.ts +4 -5
  132. package/src/renderer/status-token.ts +31 -11
  133. package/src/renderer/tab-strip.ts +1 -1
  134. package/src/renderer/tool-call.ts +7 -8
  135. package/src/renderer/tool-labels.ts +92 -0
  136. package/src/renderer/ui-factory.ts +48 -96
  137. package/src/runtime/bootstrap-command-context.ts +0 -5
  138. package/src/runtime/bootstrap-command-parts.ts +6 -15
  139. package/src/runtime/bootstrap-core.ts +34 -13
  140. package/src/runtime/bootstrap-hook-bridge.ts +3 -1
  141. package/src/runtime/bootstrap-shell.ts +3 -50
  142. package/src/runtime/bootstrap.ts +3 -4
  143. package/src/runtime/context.ts +1 -1
  144. package/src/runtime/diagnostics/panels/index.ts +0 -1
  145. package/src/runtime/diagnostics/panels/policy.ts +1 -1
  146. package/src/runtime/execution-ledger.ts +16 -1
  147. package/src/runtime/index.ts +6 -1
  148. package/src/runtime/onboarding/index.ts +1 -0
  149. package/src/runtime/onboarding/onboarding-state.ts +200 -0
  150. package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
  151. package/src/runtime/services.ts +16 -4
  152. package/src/runtime/terminal-output-guard.ts +7 -0
  153. package/src/runtime/tool-permission-safety.ts +1 -1
  154. package/src/runtime/ui/model-picker/data-provider.ts +1 -1
  155. package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
  156. package/src/runtime/ui/model-picker/types.ts +2 -2
  157. package/src/runtime/ui/provider-health/data-provider.ts +3 -3
  158. package/src/runtime/ui/provider-health/types.ts +2 -2
  159. package/src/runtime/ui-services.ts +0 -2
  160. package/src/shell/agent-workspace-fullscreen.ts +0 -1
  161. package/src/shell/autonomy-surfacing.ts +272 -0
  162. package/src/shell/session-continuity-hints.ts +0 -6
  163. package/src/shell/startup-wiring.ts +221 -0
  164. package/src/shell/ui-openers.ts +18 -29
  165. package/src/tools/agent-context-policy.ts +1 -1
  166. package/src/tools/agent-harness-background-processes.ts +4 -4
  167. package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
  168. package/src/tools/agent-harness-command-runner.ts +6 -1
  169. package/src/tools/agent-harness-document-ops.ts +26 -53
  170. package/src/tools/agent-harness-execution-history.ts +1 -13
  171. package/src/tools/agent-harness-execution-posture.ts +0 -15
  172. package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
  173. package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
  174. package/src/tools/agent-harness-metadata.ts +16 -0
  175. package/src/tools/agent-harness-mode-catalog.ts +2 -9
  176. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  177. package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
  178. package/src/tools/agent-harness-tool-schema.ts +13 -14
  179. package/src/tools/agent-harness-tool.ts +27 -23
  180. package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
  181. package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
  182. package/src/tools/agent-workspace-tool.ts +2 -33
  183. package/src/utils/terminal-width.ts +9 -3
  184. package/src/version.ts +1 -1
  185. package/src/input/agent-workspace-panel-route.ts +0 -44
  186. package/src/input/panel-integration-actions.ts +0 -26
  187. package/src/panels/approval-panel.ts +0 -149
  188. package/src/panels/automation-control-panel.ts +0 -212
  189. package/src/panels/base-panel.ts +0 -254
  190. package/src/panels/builtin/agent.ts +0 -58
  191. package/src/panels/builtin/knowledge.ts +0 -26
  192. package/src/panels/builtin/operations.ts +0 -121
  193. package/src/panels/builtin/session.ts +0 -138
  194. package/src/panels/builtin/shared.ts +0 -275
  195. package/src/panels/builtin/usage.ts +0 -21
  196. package/src/panels/builtin-panels.ts +0 -23
  197. package/src/panels/confirm-state.ts +0 -61
  198. package/src/panels/context-visualizer-panel.ts +0 -204
  199. package/src/panels/cost-tracker-panel.ts +0 -444
  200. package/src/panels/docs-panel.ts +0 -285
  201. package/src/panels/index.ts +0 -25
  202. package/src/panels/knowledge-panel.ts +0 -417
  203. package/src/panels/memory-panel.ts +0 -226
  204. package/src/panels/panel-list-panel.ts +0 -464
  205. package/src/panels/panel-manager.ts +0 -570
  206. package/src/panels/provider-accounts-panel.ts +0 -233
  207. package/src/panels/provider-health-domains.ts +0 -208
  208. package/src/panels/provider-health-panel.ts +0 -720
  209. package/src/panels/provider-health-tracker.ts +0 -115
  210. package/src/panels/provider-stats-panel.ts +0 -366
  211. package/src/panels/qr-panel.ts +0 -207
  212. package/src/panels/schedule-panel.ts +0 -321
  213. package/src/panels/scrollable-list-panel.ts +0 -491
  214. package/src/panels/search-focus.ts +0 -32
  215. package/src/panels/security-panel.ts +0 -295
  216. package/src/panels/session-browser-panel.ts +0 -395
  217. package/src/panels/session-maintenance.ts +0 -125
  218. package/src/panels/subscription-panel.ts +0 -263
  219. package/src/panels/system-messages-panel.ts +0 -230
  220. package/src/panels/tasks-panel.ts +0 -344
  221. package/src/panels/thinking-panel.ts +0 -304
  222. package/src/panels/token-budget-panel.ts +0 -475
  223. package/src/panels/tool-inspector-panel.ts +0 -436
  224. package/src/panels/types.ts +0 -54
  225. package/src/renderer/panel-composite.ts +0 -158
  226. package/src/renderer/panel-tab-bar.ts +0 -69
  227. package/src/renderer/panel-workspace-bar.ts +0 -42
  228. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  229. package/src/tools/agent-harness-panel-metadata.ts +0 -211
  230. /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
- const inspection = await inspectProviderAuth(provider, {
116
- serviceRegistry: services,
117
- subscriptionManager: manager,
118
- secretsManager: requireSecretsManager(ctx),
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
- const token = await exchangeOpenAICodexCode(code, pending.verifier);
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
- const record = await manager.completeOAuthLogin(provider, activeConfig, code);
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
- ctx.print(inspectBundle(targetPath));
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] [--manual] --yes|login <provider> finish <code-or-url> --yes|logout <provider> --yes|bundle export <path> --yes|bundle inspect <path>]');
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
- const result = await handleBundleCommand(runtime);
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();
@@ -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`, `panelFocused`, `indicatorFocused` — focus-mode flags
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
- * - `panelManager`, `keybindingsManager` — from uiServices, stable
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
- * - `panelFocused` — whether the active panel owns keyboard focus
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 { PanelManager } from '../panels/panel-manager.ts';
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 = withPanelFocusSync(state.commandContext, state);
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
  }