@pellux/goodvibes-agent 1.5.5 → 1.5.6

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 (165) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +1 -1
  3. package/dist/package/main.js +94130 -79335
  4. package/docs/tools-and-commands.md +2 -1
  5. package/package.json +6 -3
  6. package/src/agent/autonomy-schedule-format.ts +1 -1
  7. package/src/agent/autonomy-schedule.ts +3 -3
  8. package/src/agent/calendar/calendar-oauth-service.ts +324 -0
  9. package/src/agent/calendar-subscription-registry.ts +497 -0
  10. package/src/agent/email/email-service.ts +57 -0
  11. package/src/agent/email/smtp-client.ts +30 -10
  12. package/src/agent/memory-prompt.ts +143 -12
  13. package/src/agent/operator-actions.ts +26 -22
  14. package/src/agent/prompt-context-receipts.ts +45 -18
  15. package/src/agent/reminder-schedule-format.ts +1 -1
  16. package/src/agent/reminder-schedule.ts +3 -3
  17. package/src/agent/routine-schedule-format.ts +2 -2
  18. package/src/agent/routine-schedule-promotion.ts +5 -5
  19. package/src/agent/routine-schedule-receipts.ts +2 -2
  20. package/src/agent/schedule-edit-format.ts +1 -1
  21. package/src/agent/schedule-edit.ts +5 -5
  22. package/src/agent/session-registration.ts +281 -0
  23. package/src/agent/vibe-file.ts +50 -0
  24. package/src/cli/local-library-command-shared.ts +146 -0
  25. package/src/cli/management.ts +2 -1
  26. package/src/cli/personas-command.ts +252 -0
  27. package/src/cli/resume-relaunch-notice.ts +151 -0
  28. package/src/cli/routines-command.ts +25 -2
  29. package/src/cli/service-posture.ts +3 -2
  30. package/src/cli/skill-bundle-command.ts +175 -0
  31. package/src/cli/skills-command.ts +309 -0
  32. package/src/cli/status.ts +43 -7
  33. package/src/cli/tui-startup.ts +24 -1
  34. package/src/config/agent-settings-policy.ts +0 -1
  35. package/src/config/secret-config.ts +4 -0
  36. package/src/core/conversation-rendering.ts +20 -11
  37. package/src/core/focus-tracker.ts +41 -0
  38. package/src/core/system-message-noise.ts +108 -0
  39. package/src/core/system-message-router.ts +54 -1
  40. package/src/core/thinking-overlay.ts +83 -0
  41. package/src/input/agent-workspace-access-command-editor-submission.ts +75 -108
  42. package/src/input/agent-workspace-access-command-editors.ts +108 -128
  43. package/src/input/agent-workspace-activation.ts +15 -0
  44. package/src/input/agent-workspace-basic-command-editor-submission.ts +292 -513
  45. package/src/input/agent-workspace-basic-command-editors.ts +433 -564
  46. package/src/input/agent-workspace-calendar-connect-editor.ts +116 -0
  47. package/src/input/agent-workspace-calendar-oauth-editor.ts +152 -0
  48. package/src/input/agent-workspace-calendar-subscribe-editor.ts +128 -0
  49. package/src/input/agent-workspace-categories.ts +7 -2
  50. package/src/input/agent-workspace-channel-command-editor-submission.ts +38 -52
  51. package/src/input/agent-workspace-channel-command-editors.ts +42 -46
  52. package/src/input/agent-workspace-command-editor-engine.ts +133 -0
  53. package/src/input/agent-workspace-command-editor.ts +4 -0
  54. package/src/input/agent-workspace-direct-editor-submission.ts +59 -0
  55. package/src/input/agent-workspace-email-connect-editor.ts +162 -0
  56. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +52 -81
  57. package/src/input/agent-workspace-knowledge-command-editors.ts +71 -71
  58. package/src/input/agent-workspace-library-command-editor-submission.ts +10 -28
  59. package/src/input/agent-workspace-library-command-editors.ts +16 -2
  60. package/src/input/agent-workspace-live-counters.ts +55 -0
  61. package/src/input/agent-workspace-mcp-command-editor-submission.ts +60 -82
  62. package/src/input/agent-workspace-mcp-command-editors.ts +52 -0
  63. package/src/input/agent-workspace-media-command-editor-submission.ts +12 -39
  64. package/src/input/agent-workspace-media-command-editors.ts +10 -8
  65. package/src/input/agent-workspace-memory-command-editor-submission.ts +76 -151
  66. package/src/input/agent-workspace-memory-command-editors.ts +116 -141
  67. package/src/input/agent-workspace-operations-command-editor-submission.ts +131 -184
  68. package/src/input/agent-workspace-operations-command-editors.ts +150 -162
  69. package/src/input/agent-workspace-provider-command-editor-submission.ts +60 -106
  70. package/src/input/agent-workspace-provider-command-editors.ts +58 -68
  71. package/src/input/agent-workspace-search.ts +8 -1
  72. package/src/input/agent-workspace-session-command-editor-submission.ts +104 -132
  73. package/src/input/agent-workspace-session-command-editors.ts +160 -195
  74. package/src/input/agent-workspace-settings.ts +40 -1
  75. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +55 -71
  76. package/src/input/agent-workspace-skill-bundle-command-editors.ts +65 -69
  77. package/src/input/agent-workspace-snapshot-builders.ts +431 -0
  78. package/src/input/agent-workspace-snapshot-config.ts +43 -0
  79. package/src/input/agent-workspace-snapshot.ts +198 -432
  80. package/src/input/agent-workspace-task-command-editor-submission.ts +34 -44
  81. package/src/input/agent-workspace-task-command-editors.ts +27 -28
  82. package/src/input/agent-workspace-types.ts +35 -1
  83. package/src/input/agent-workspace.ts +5 -14
  84. package/src/input/command-registry.ts +23 -1
  85. package/src/input/commands/calendar-connect-runtime.ts +226 -0
  86. package/src/input/commands/calendar-runtime.ts +110 -7
  87. package/src/input/commands/calendar-subscription-runtime.ts +225 -0
  88. package/src/input/commands/email-runtime.ts +100 -40
  89. package/src/input/commands/knowledge.ts +1 -1
  90. package/src/input/commands/network-scan-runtime.ts +75 -0
  91. package/src/input/commands/operator-actions-runtime.ts +9 -6
  92. package/src/input/commands/personas-runtime.ts +1 -1
  93. package/src/input/commands/schedule-runtime.ts +4 -4
  94. package/src/input/commands/session-content.ts +13 -1
  95. package/src/input/commands/session-workflow.ts +15 -20
  96. package/src/input/commands/session.ts +3 -1
  97. package/src/input/commands/shell-core.ts +20 -6
  98. package/src/input/commands.ts +2 -2
  99. package/src/input/delete-key-policy.ts +46 -0
  100. package/src/input/feed-context-factory.ts +10 -0
  101. package/src/input/handler-feed.ts +87 -0
  102. package/src/input/handler-modal-routes.ts +6 -1
  103. package/src/input/handler.ts +5 -0
  104. package/src/input/panel-paste-flood-guard.ts +94 -0
  105. package/src/input/settings-modal-types.ts +5 -3
  106. package/src/input/settings-modal.ts +21 -0
  107. package/src/main.ts +36 -36
  108. package/src/permissions/approval-posture.ts +141 -0
  109. package/src/renderer/agent-workspace-context-lines.ts +10 -2
  110. package/src/renderer/compositor.ts +27 -4
  111. package/src/renderer/diff.ts +61 -18
  112. package/src/renderer/fullscreen-primitives.ts +37 -18
  113. package/src/renderer/markdown.ts +20 -10
  114. package/src/renderer/modal-factory.ts +25 -15
  115. package/src/renderer/overlay-box.ts +23 -12
  116. package/src/renderer/process-indicator.ts +8 -3
  117. package/src/renderer/prompt-content-width.ts +16 -0
  118. package/src/renderer/settings-modal-helpers.ts +2 -0
  119. package/src/renderer/settings-modal.ts +2 -0
  120. package/src/renderer/startup-theme-probe.ts +35 -0
  121. package/src/renderer/status-glyphs.ts +11 -15
  122. package/src/renderer/system-message.ts +17 -2
  123. package/src/renderer/term-caps.ts +318 -0
  124. package/src/renderer/terminal-bg-probe.ts +373 -0
  125. package/src/renderer/terminal-escapes.ts +24 -0
  126. package/src/renderer/theme-mode-config.ts +87 -0
  127. package/src/renderer/theme.ts +241 -0
  128. package/src/renderer/thinking.ts +12 -3
  129. package/src/renderer/tool-call.ts +7 -3
  130. package/src/renderer/ui-factory.ts +92 -36
  131. package/src/renderer/ui-primitives.ts +33 -93
  132. package/src/runtime/bootstrap-core.ts +15 -0
  133. package/src/runtime/bootstrap-hook-bridge.ts +6 -0
  134. package/src/runtime/bootstrap-shell.ts +2 -0
  135. package/src/runtime/bootstrap.ts +68 -5
  136. package/src/runtime/calendar-boot-refresh.ts +105 -0
  137. package/src/runtime/lan-scan-consent.ts +253 -0
  138. package/src/runtime/services.ts +127 -2
  139. package/src/runtime/session-spine-rest-transport.ts +160 -0
  140. package/src/runtime/terminal-output-guard.ts +6 -1
  141. package/src/runtime/ui-services.ts +3 -0
  142. package/src/shell/agent-workspace-fullscreen.ts +5 -0
  143. package/src/shell/terminal-focus-mode.ts +120 -0
  144. package/src/shell/ui-openers.ts +13 -4
  145. package/src/tools/agent-harness-autonomy-intake.ts +5 -5
  146. package/src/tools/agent-harness-autonomy-queue.ts +1 -1
  147. package/src/tools/agent-harness-background-processes.ts +2 -1
  148. package/src/tools/agent-harness-metadata.ts +16 -8
  149. package/src/tools/agent-harness-operator-methods.ts +44 -8
  150. package/src/tools/agent-harness-personal-ops-discovery.ts +57 -10
  151. package/src/tools/agent-harness-personal-ops-lanes.ts +17 -5
  152. package/src/tools/agent-harness-personal-ops-operations.ts +7 -7
  153. package/src/tools/agent-harness-personal-ops-types.ts +6 -0
  154. package/src/tools/agent-harness-prompt-context.ts +26 -12
  155. package/src/tools/agent-harness-workspace-actions.ts +4 -0
  156. package/src/tools/agent-local-registry-args.ts +117 -0
  157. package/src/tools/agent-local-registry-memory.ts +227 -0
  158. package/src/tools/agent-local-registry-tool.ts +19 -237
  159. package/src/tools/agent-operator-briefing-tool.ts +2 -2
  160. package/src/tools/agent-operator-method-tool.ts +13 -0
  161. package/src/tools/agent-policy-explanation.ts +39 -4
  162. package/src/tools/agent-schedule-tool.ts +5 -5
  163. package/src/utils/terminal-width.ts +98 -1
  164. package/src/version.ts +1 -1
  165. package/src/cli/local-library-command.ts +0 -825
@@ -1,4 +1,6 @@
1
1
  import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import type { AgentWorkspaceEditorSpecEntry } from './agent-workspace-command-editor-engine.ts';
3
+ import { createAgentWorkspaceEditorFromTable } from './agent-workspace-command-editor-engine.ts';
2
4
 
3
5
  export type AgentWorkspaceProviderCommandEditorKind = Extract<
4
6
  AgentWorkspaceEditorKind,
@@ -14,73 +16,57 @@ export function isAgentWorkspaceProviderCommandEditorKind(kind: AgentWorkspaceEd
14
16
  || kind === 'provider-account-repair';
15
17
  }
16
18
 
17
- export function createAgentWorkspaceProviderCommandEditor(kind: AgentWorkspaceProviderCommandEditorKind): AgentWorkspaceLocalEditor {
18
- if (kind === 'provider-use') {
19
- return {
20
- kind,
21
- mode: 'create',
22
- title: 'Use Provider',
23
- selectedFieldIndex: 0,
24
- message: 'Switch the Agent chat provider through the TUI command router. Add a model id when you want an exact provider/model route.',
25
- fields: [
26
- { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id, such as openai-subscriber, openai, anthropic, or a custom provider.' },
27
- { id: 'model', label: 'Model id', value: '', required: false, multiline: false, hint: 'Optional model id or provider:model registry key. Blank uses the provider default selectable model.' },
28
- ],
29
- };
30
- }
31
- if (kind === 'provider-inspect') {
32
- return {
33
- kind,
34
- mode: 'create',
35
- title: 'Inspect Provider',
36
- selectedFieldIndex: 0,
37
- message: 'Inspect provider auth and setup routes from the Agent TUI without changing provider selection.',
38
- fields: [
39
- { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
40
- ],
41
- };
42
- }
43
- if (kind === 'provider-routes') {
44
- return {
45
- kind,
46
- mode: 'create',
47
- title: 'Inspect Provider Routes',
48
- selectedFieldIndex: 0,
49
- message: 'Inspect provider account routes from the Agent TUI without changing routing or auth.',
50
- fields: [
51
- { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
52
- ],
53
- };
54
- }
55
- if (kind === 'provider-account-repair') {
56
- return {
57
- kind,
58
- mode: 'create',
59
- title: 'Review Provider Account Repair',
60
- selectedFieldIndex: 0,
61
- message: 'Show provider account repair guidance from the Agent TUI without starting login or storing tokens.',
62
- fields: [
63
- { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
64
- ],
65
- };
66
- }
67
- if (kind === 'provider-add') {
68
- return {
69
- kind,
70
- mode: 'create',
71
- title: 'Add Custom Provider',
72
- selectedFieldIndex: 0,
73
- message: 'Add an OpenAI-compatible provider for Agent chat/model routing. Type yes on the final field to confirm.',
74
- fields: [
75
- { id: 'name', label: 'Provider name', value: '', required: true, multiline: false, hint: 'Letters, numbers, hyphens, and underscores only.' },
76
- { id: 'baseUrl', label: 'Base URL', value: '', required: true, multiline: false, hint: 'OpenAI-compatible base URL, such as http://127.0.0.1:8000/v1.' },
77
- { id: 'apiKey', label: 'API key', value: '', required: false, multiline: false, hint: 'Optional API key. Prefer a local provider or a secret-backed provider config when possible.', redact: true },
78
- { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /provider add with --yes.' },
79
- ],
80
- };
81
- }
82
- return {
83
- kind,
19
+ const PROVIDER_COMMAND_EDITOR_SPECS: Readonly<Record<AgentWorkspaceProviderCommandEditorKind, AgentWorkspaceEditorSpecEntry<AgentWorkspaceProviderCommandEditorKind>>> = {
20
+ 'provider-use': {
21
+ mode: 'create',
22
+ title: 'Use Provider',
23
+ selectedFieldIndex: 0,
24
+ message: 'Switch the Agent chat provider through the TUI command router. Add a model id when you want an exact provider/model route.',
25
+ fields: [
26
+ { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id, such as openai-subscriber, openai, anthropic, or a custom provider.' },
27
+ { id: 'model', label: 'Model id', value: '', required: false, multiline: false, hint: 'Optional model id or provider:model registry key. Blank uses the provider default selectable model.' },
28
+ ],
29
+ },
30
+ 'provider-inspect': {
31
+ mode: 'create',
32
+ title: 'Inspect Provider',
33
+ selectedFieldIndex: 0,
34
+ message: 'Inspect provider auth and setup routes from the Agent TUI without changing provider selection.',
35
+ fields: [
36
+ { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
37
+ ],
38
+ },
39
+ 'provider-routes': {
40
+ mode: 'create',
41
+ title: 'Inspect Provider Routes',
42
+ selectedFieldIndex: 0,
43
+ message: 'Inspect provider account routes from the Agent TUI without changing routing or auth.',
44
+ fields: [
45
+ { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
46
+ ],
47
+ },
48
+ 'provider-account-repair': {
49
+ mode: 'create',
50
+ title: 'Review Provider Account Repair',
51
+ selectedFieldIndex: 0,
52
+ message: 'Show provider account repair guidance from the Agent TUI without starting login or storing tokens.',
53
+ fields: [
54
+ { id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
55
+ ],
56
+ },
57
+ 'provider-add': {
58
+ mode: 'create',
59
+ title: 'Add Custom Provider',
60
+ selectedFieldIndex: 0,
61
+ message: 'Add an OpenAI-compatible provider for Agent chat/model routing. Type yes on the final field to confirm.',
62
+ fields: [
63
+ { id: 'name', label: 'Provider name', value: '', required: true, multiline: false, hint: 'Letters, numbers, hyphens, and underscores only.' },
64
+ { id: 'baseUrl', label: 'Base URL', value: '', required: true, multiline: false, hint: 'OpenAI-compatible base URL, such as http://127.0.0.1:8000/v1.' },
65
+ { id: 'apiKey', label: 'API key', value: '', required: false, multiline: false, hint: 'Optional API key. Prefer a local provider or a secret-backed provider config when possible.', redact: true },
66
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /provider add with --yes.' },
67
+ ],
68
+ },
69
+ 'provider-remove': {
84
70
  mode: 'delete',
85
71
  title: 'Remove Custom Provider',
86
72
  selectedFieldIndex: 0,
@@ -89,5 +75,9 @@ export function createAgentWorkspaceProviderCommandEditor(kind: AgentWorkspacePr
89
75
  { id: 'name', label: 'Provider name', value: '', required: true, multiline: false, hint: 'Existing custom provider name.' },
90
76
  { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /provider remove with --yes.' },
91
77
  ],
92
- };
78
+ },
79
+ };
80
+
81
+ export function createAgentWorkspaceProviderCommandEditor(kind: AgentWorkspaceProviderCommandEditorKind): AgentWorkspaceLocalEditor {
82
+ return createAgentWorkspaceEditorFromTable(kind, PROVIDER_COMMAND_EDITOR_SPECS);
93
83
  }
@@ -136,7 +136,14 @@ export function clearAgentWorkspaceActionSearch(host: AgentWorkspaceSearchHost):
136
136
  if (!host.actionSearchActive) return;
137
137
  host.actionSearchActive = false;
138
138
  host.actionSearchQuery = '';
139
- host.selectedActionIndex = Math.max(0, Math.min(host.selectedActionIndex, host.selectedCategory.actions.length - 1));
139
+ // selectedActionIndex was an index into the SEARCH RESULTS, which can span
140
+ // every category. Reinterpreting that number as an index into the
141
+ // originating category's own (unrelated) action list silently highlights
142
+ // an arbitrary, wrong action — the highlight desyncs from what the user
143
+ // was just looking at. There is no principled position to preserve across
144
+ // an arbitrary category switch, so return to the top of the list, same as
145
+ // beginning/typing/backspacing a search already does.
146
+ host.selectedActionIndex = 0;
140
147
  host.status = 'Action search cleared.';
141
148
  host.clampSelection();
142
149
  }
@@ -1,199 +1,171 @@
1
- import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
1
+ import type { AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
2
  import type { AgentWorkspaceSessionCommandEditorKind } from './agent-workspace-session-command-editors.ts';
3
3
  import { isAgentWorkspaceSessionCommandEditorKind } from './agent-workspace-session-command-editors.ts';
4
4
  import { quoteSlashCommandArg } from './slash-command-parser.ts';
5
+ import type { AgentWorkspaceCommandEditorSubmission, AgentWorkspaceCommandSubmissionHandler, AgentWorkspaceFieldReader } from './agent-workspace-command-editor-engine.ts';
6
+ import { buildCommandEditorSubmissionFromTable, dispatchCommandEditorSubmission, editorMessageSubmission, isAffirmative } from './agent-workspace-command-editor-engine.ts';
5
7
 
6
- type AgentWorkspaceFieldReader = (fieldId: string) => string;
7
-
8
- export type AgentWorkspaceSessionCommandEditorSubmission =
9
- | {
10
- readonly kind: 'editor';
11
- readonly editor: AgentWorkspaceLocalEditor;
12
- readonly status: string;
13
- readonly actionResult?: AgentWorkspaceActionResult;
14
- }
15
- | {
16
- readonly kind: 'dispatch';
17
- readonly command: string;
18
- readonly status: string;
19
- readonly actionResult: AgentWorkspaceActionResult;
20
- };
8
+ export type AgentWorkspaceSessionCommandEditorSubmission = AgentWorkspaceCommandEditorSubmission;
21
9
 
22
10
  export function isAgentWorkspaceSessionCommandSubmissionKind(kind: string): kind is AgentWorkspaceSessionCommandEditorKind {
23
11
  return isAgentWorkspaceSessionCommandEditorKind(kind as AgentWorkspaceSessionCommandEditorKind);
24
12
  }
25
13
 
26
- function isAffirmative(value: string): boolean {
27
- return /^(y|yes|true)$/i.test(value.trim());
28
- }
29
-
30
- function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceSessionCommandEditorSubmission {
31
- return {
32
- kind: 'editor',
33
- editor: { ...editor, message },
34
- status: message,
35
- };
36
- }
37
-
38
- function dispatch(command: string, title: string, detail: string, safety: AgentWorkspaceActionResult['safety']): AgentWorkspaceSessionCommandEditorSubmission {
39
- return {
40
- kind: 'dispatch',
41
- command,
42
- status: `${title}.`,
43
- actionResult: { kind: 'dispatched', title, detail, command, safety },
44
- };
14
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceCommandEditorSubmission {
15
+ return editorMessageSubmission(editor, message);
45
16
  }
46
17
 
47
- export function buildAgentWorkspaceSessionCommandEditorSubmission(
48
- editor: AgentWorkspaceLocalEditor,
49
- readField: AgentWorkspaceFieldReader,
50
- ): AgentWorkspaceSessionCommandEditorSubmission {
51
- if (editor.kind === 'conversation-export') {
18
+ const SESSION_COMMAND_SUBMISSION_HANDLERS: Readonly<Record<AgentWorkspaceSessionCommandEditorKind, AgentWorkspaceCommandSubmissionHandler>> = {
19
+ 'conversation-export': (editor, readField) => {
52
20
  if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Conversation export not confirmed. Type yes, then press Enter.');
53
- return dispatch(
21
+ return dispatchCommandEditorSubmission(
54
22
  `/export ${quoteSlashCommandArg(readField('format'))} ${quoteSlashCommandArg(readField('path'))} --yes`,
55
23
  'Opening conversation export',
56
24
  'The workspace handed a confirmed conversation export command to the shell-owned command router.',
57
25
  'safe',
58
26
  );
59
- }
60
- if (editor.kind === 'conversation-events' || editor.kind === 'conversation-groups') {
61
- const subcommand = editor.kind === 'conversation-groups' ? 'groups' : 'events';
62
- const eventKind = readField('kind');
63
- const command = eventKind.length > 0
64
- ? `/conversation ${subcommand} ${quoteSlashCommandArg(eventKind)}`
65
- : `/conversation ${subcommand}`;
66
- return dispatch(
67
- command,
68
- editor.kind === 'conversation-groups' ? 'Opening transcript groups' : 'Opening transcript events',
69
- 'The workspace handed read-only transcript structure inspection to the shell-owned command router.',
70
- 'read-only',
71
- );
72
- }
73
- if (editor.kind === 'conversation-find') {
27
+ },
28
+ 'conversation-events': (editor, readField) => conversationEventsOrGroups(editor, readField),
29
+ 'conversation-groups': (editor, readField) => conversationEventsOrGroups(editor, readField),
30
+ 'conversation-find': (_editor, readField) => {
74
31
  const kind = readField('kind');
75
32
  const command = kind.length > 0
76
33
  ? `/conversation find ${quoteSlashCommandArg(readField('query'))} ${quoteSlashCommandArg(kind)}`
77
34
  : `/conversation find ${quoteSlashCommandArg(readField('query'))}`;
78
- return dispatch(
35
+ return dispatchCommandEditorSubmission(
79
36
  command,
80
37
  'Opening transcript search',
81
38
  'The workspace handed read-only transcript search to the shell-owned command router.',
82
39
  'read-only',
83
40
  );
84
- }
85
- if (editor.kind === 'effort-level') {
86
- return dispatch(
87
- `/effort ${quoteSlashCommandArg(readField('level'))}`,
88
- 'Opening reasoning effort change',
89
- 'The workspace handed reasoning effort selection to the shell-owned command router.',
90
- 'safe',
91
- );
92
- }
93
- if (editor.kind === 'session-save') {
41
+ },
42
+ 'effort-level': (_editor, readField) => dispatchCommandEditorSubmission(
43
+ `/effort ${quoteSlashCommandArg(readField('level'))}`,
44
+ 'Opening reasoning effort change',
45
+ 'The workspace handed reasoning effort selection to the shell-owned command router.',
46
+ 'safe',
47
+ ),
48
+ 'session-save': (editor, readField) => {
94
49
  if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Session save not confirmed. Type yes, then press Enter.');
95
- return dispatch(
50
+ return dispatchCommandEditorSubmission(
96
51
  `/save ${quoteSlashCommandArg(readField('name'))}`,
97
52
  'Opening session save',
98
53
  'The workspace handed a confirmed session save command to the shell-owned command router.',
99
54
  'safe',
100
55
  );
101
- }
102
- if (editor.kind === 'session-load') {
56
+ },
57
+ 'session-load': (editor, readField) => {
103
58
  if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Session load not confirmed. Type yes, then press Enter.');
104
- return dispatch(
59
+ return dispatchCommandEditorSubmission(
105
60
  `/load ${quoteSlashCommandArg(readField('name'))}`,
106
61
  'Opening session load',
107
62
  'The workspace handed a confirmed session load command to the shell-owned command router.',
108
63
  'safe',
109
64
  );
110
- }
111
- if (editor.kind === 'session-rename') {
112
- return dispatch(
113
- `/session rename ${quoteSlashCommandArg(readField('name'))}`,
114
- 'Opening session rename',
115
- 'The workspace handed current-session rename to the shell-owned command router.',
116
- 'safe',
117
- );
118
- }
119
- if (editor.kind === 'session-resume') {
120
- return dispatch(
121
- `/session resume ${quoteSlashCommandArg(readField('target'))}`,
122
- 'Opening session resume',
123
- 'The workspace handed saved-session resume to the shell-owned command router.',
124
- 'safe',
125
- );
126
- }
127
- if (editor.kind === 'session-info') {
128
- return dispatch(
129
- `/session info ${quoteSlashCommandArg(readField('target'))}`,
130
- 'Opening session inspection',
131
- 'The workspace handed read-only saved-session inspection to the shell-owned command router.',
132
- 'read-only',
133
- );
134
- }
135
- if (editor.kind === 'session-export-saved') {
136
- return dispatch(
137
- `/session export ${quoteSlashCommandArg(readField('target'))} ${quoteSlashCommandArg(readField('format'))}`,
138
- 'Opening saved-session export',
139
- 'The workspace handed saved-session transcript export to the shell-owned command router.',
140
- 'read-only',
141
- );
142
- }
143
- if (editor.kind === 'session-search') {
144
- return dispatch(
145
- `/session search ${quoteSlashCommandArg(readField('query'))}`,
146
- 'Opening saved-session search',
147
- 'The workspace handed saved-session search to the shell-owned command router.',
148
- 'read-only',
149
- );
150
- }
151
- if (editor.kind === 'session-delete') {
65
+ },
66
+ 'session-rename': (_editor, readField) => dispatchCommandEditorSubmission(
67
+ `/session rename ${quoteSlashCommandArg(readField('name'))}`,
68
+ 'Opening session rename',
69
+ 'The workspace handed current-session rename to the shell-owned command router.',
70
+ 'safe',
71
+ ),
72
+ 'session-resume': (_editor, readField) => dispatchCommandEditorSubmission(
73
+ `/session resume ${quoteSlashCommandArg(readField('target'))}`,
74
+ 'Opening session resume',
75
+ 'The workspace handed saved-session resume to the shell-owned command router.',
76
+ 'safe',
77
+ ),
78
+ 'session-info': (_editor, readField) => dispatchCommandEditorSubmission(
79
+ `/session info ${quoteSlashCommandArg(readField('target'))}`,
80
+ 'Opening session inspection',
81
+ 'The workspace handed read-only saved-session inspection to the shell-owned command router.',
82
+ 'read-only',
83
+ ),
84
+ 'session-export-saved': (_editor, readField) => dispatchCommandEditorSubmission(
85
+ `/session export ${quoteSlashCommandArg(readField('target'))} ${quoteSlashCommandArg(readField('format'))}`,
86
+ 'Opening saved-session export',
87
+ 'The workspace handed saved-session transcript export to the shell-owned command router.',
88
+ 'read-only',
89
+ ),
90
+ 'session-search': (_editor, readField) => dispatchCommandEditorSubmission(
91
+ `/session search ${quoteSlashCommandArg(readField('query'))}`,
92
+ 'Opening saved-session search',
93
+ 'The workspace handed saved-session search to the shell-owned command router.',
94
+ 'read-only',
95
+ ),
96
+ 'session-delete': (editor, readField) => {
152
97
  if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Session delete not confirmed. Type yes, then press Enter.');
153
- return dispatch(
98
+ return dispatchCommandEditorSubmission(
154
99
  `/session delete ${quoteSlashCommandArg(readField('target'))} --yes`,
155
100
  'Opening saved-session delete',
156
101
  'The workspace handed confirmed saved-session deletion to the shell-owned command router.',
157
102
  'safe',
158
103
  );
159
- }
160
- if (editor.kind === 'session-fork') {
104
+ },
105
+ 'session-fork': (_editor, readField) => {
161
106
  const name = readField('name');
162
- return dispatch(
107
+ return dispatchCommandEditorSubmission(
163
108
  name.length > 0 ? `/session fork ${quoteSlashCommandArg(name)}` : '/session fork',
164
109
  'Opening session fork',
165
110
  'The workspace handed current-session fork to the shell-owned command router.',
166
111
  'safe',
167
112
  );
168
- }
169
- if (editor.kind === 'session-graph') {
113
+ },
114
+ 'session-graph': (_editor, readField) => {
170
115
  const sessionId = readField('sessionId');
171
116
  const format = readField('format');
172
117
  const parts = ['/session', 'graph'];
173
118
  if (sessionId.length > 0) parts.push('--session', quoteSlashCommandArg(sessionId));
174
119
  if (format.length > 0) parts.push('--format', quoteSlashCommandArg(format));
175
- const command = parts.join(' ');
176
- return dispatch(
177
- command,
120
+ return dispatchCommandEditorSubmission(
121
+ parts.join(' '),
178
122
  'Opening session graph',
179
123
  'The workspace handed read-only session graph inspection to the shell-owned command router.',
180
124
  'read-only',
181
125
  );
182
- }
183
- if (editor.kind === 'mode-preset') {
126
+ },
127
+ 'mode-preset': (editor, readField) => {
184
128
  if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Interaction mode change not confirmed. Type yes, then press Enter.');
185
- return dispatch(
129
+ return dispatchCommandEditorSubmission(
186
130
  `/mode ${quoteSlashCommandArg(readField('preset'))} --yes`,
187
131
  'Opening interaction mode change',
188
132
  'The workspace handed a confirmed interaction mode command to the shell-owned command router.',
189
133
  'safe',
190
134
  );
191
- }
192
- if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Domain verbosity change not confirmed. Type yes, then press Enter.');
193
- return dispatch(
194
- `/mode set-domain ${quoteSlashCommandArg(readField('domain'))} ${quoteSlashCommandArg(readField('verbosity'))} --yes`,
195
- 'Opening domain verbosity change',
196
- 'The workspace handed a confirmed domain verbosity command to the shell-owned command router.',
197
- 'safe',
135
+ },
136
+ 'mode-domain': (editor, readField) => {
137
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Domain verbosity change not confirmed. Type yes, then press Enter.');
138
+ return dispatchCommandEditorSubmission(
139
+ `/mode set-domain ${quoteSlashCommandArg(readField('domain'))} ${quoteSlashCommandArg(readField('verbosity'))} --yes`,
140
+ 'Opening domain verbosity change',
141
+ 'The workspace handed a confirmed domain verbosity command to the shell-owned command router.',
142
+ 'safe',
143
+ );
144
+ },
145
+ };
146
+
147
+ function conversationEventsOrGroups(editor: AgentWorkspaceLocalEditor, readField: AgentWorkspaceFieldReader): AgentWorkspaceCommandEditorSubmission {
148
+ const subcommand = editor.kind === 'conversation-groups' ? 'groups' : 'events';
149
+ const eventKind = readField('kind');
150
+ const command = eventKind.length > 0
151
+ ? `/conversation ${subcommand} ${quoteSlashCommandArg(eventKind)}`
152
+ : `/conversation ${subcommand}`;
153
+ return dispatchCommandEditorSubmission(
154
+ command,
155
+ editor.kind === 'conversation-groups' ? 'Opening transcript groups' : 'Opening transcript events',
156
+ 'The workspace handed read-only transcript structure inspection to the shell-owned command router.',
157
+ 'read-only',
158
+ );
159
+ }
160
+
161
+ export function buildAgentWorkspaceSessionCommandEditorSubmission(
162
+ editor: AgentWorkspaceLocalEditor,
163
+ readField: AgentWorkspaceFieldReader,
164
+ ): AgentWorkspaceCommandEditorSubmission {
165
+ return buildCommandEditorSubmissionFromTable(
166
+ editor.kind as AgentWorkspaceSessionCommandEditorKind,
167
+ editor,
168
+ readField,
169
+ SESSION_COMMAND_SUBMISSION_HANDLERS,
198
170
  );
199
171
  }