@pellux/goodvibes-agent 0.1.116 → 1.0.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.
Files changed (285) hide show
  1. package/CHANGELOG.md +48 -661
  2. package/README.md +64 -57
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +199180 -192185
  5. package/docs/README.md +15 -8
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +59 -0
  8. package/docs/getting-started.md +61 -50
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +48 -11
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +3 -6
  16. package/src/agent/behavior-discovery-summary.ts +1 -3
  17. package/src/agent/channel-delivery.ts +201 -0
  18. package/src/agent/media-generation.ts +159 -0
  19. package/src/agent/memory-prompt.ts +0 -1
  20. package/src/agent/note-registry.ts +329 -0
  21. package/src/agent/operator-actions.ts +343 -0
  22. package/src/agent/persona-discovery.ts +1 -3
  23. package/src/agent/persona-registry.ts +19 -16
  24. package/src/agent/record-labels.ts +107 -0
  25. package/src/agent/reminder-schedule-format.ts +33 -24
  26. package/src/agent/reminder-schedule.ts +27 -26
  27. package/src/agent/routine-registry.ts +54 -14
  28. package/src/agent/routine-schedule-args.ts +2 -1
  29. package/src/agent/routine-schedule-format.ts +77 -53
  30. package/src/agent/routine-schedule-promotion.ts +35 -33
  31. package/src/agent/routine-schedule-receipts.ts +29 -27
  32. package/src/agent/runtime-profile-starters.ts +5 -5
  33. package/src/agent/runtime-profile.ts +91 -12
  34. package/src/agent/skill-registry.ts +210 -32
  35. package/src/cli/agent-knowledge-args.ts +5 -1
  36. package/src/cli/agent-knowledge-command.ts +40 -34
  37. package/src/cli/agent-knowledge-format.ts +80 -67
  38. package/src/cli/agent-knowledge-methods.ts +1 -1
  39. package/src/cli/agent-knowledge-runtime.ts +32 -26
  40. package/src/cli/bundle-command.ts +14 -9
  41. package/src/cli/config-overrides.ts +37 -36
  42. package/src/cli/entrypoint.ts +16 -7
  43. package/src/cli/external-runtime.ts +10 -4
  44. package/src/cli/help.ts +54 -29
  45. package/src/cli/local-library-command.ts +203 -83
  46. package/src/cli/management-commands.ts +105 -68
  47. package/src/cli/management.ts +55 -74
  48. package/src/cli/memory-command.ts +66 -32
  49. package/src/cli/parser.ts +37 -3
  50. package/src/cli/profiles-command.ts +166 -31
  51. package/src/cli/provider-auth-routes.ts +2 -1
  52. package/src/cli/routines-command.ts +176 -40
  53. package/src/cli/service-posture.ts +16 -16
  54. package/src/cli/status.ts +56 -135
  55. package/src/core/conversation-message-snapshot.ts +131 -0
  56. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  57. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  58. package/src/input/agent-workspace-activation.ts +35 -8
  59. package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
  60. package/src/input/agent-workspace-basic-command-editors.ts +502 -9
  61. package/src/input/agent-workspace-categories.ts +423 -51
  62. package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
  63. package/src/input/agent-workspace-channel-command-editors.ts +65 -0
  64. package/src/input/agent-workspace-channels.ts +35 -2
  65. package/src/input/agent-workspace-command-editor.ts +41 -3
  66. package/src/input/agent-workspace-config-reader.ts +16 -0
  67. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  68. package/src/input/agent-workspace-editors.ts +166 -1
  69. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  70. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  71. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  72. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  73. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  74. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  75. package/src/input/agent-workspace-local-operations.ts +218 -0
  76. package/src/input/agent-workspace-local-selection.ts +75 -0
  77. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  78. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  79. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  80. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  81. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  82. package/src/input/agent-workspace-memory-editor.ts +2 -2
  83. package/src/input/agent-workspace-navigation.ts +81 -0
  84. package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
  85. package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
  86. package/src/input/agent-workspace-operations-command-editors.ts +196 -0
  87. package/src/input/agent-workspace-panel-route.ts +43 -0
  88. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  89. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  90. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  91. package/src/input/agent-workspace-requirements.ts +11 -0
  92. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  93. package/src/input/agent-workspace-search.ts +169 -0
  94. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  95. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  96. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  97. package/src/input/agent-workspace-setup.ts +37 -16
  98. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  99. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  100. package/src/input/agent-workspace-snapshot.ts +162 -21
  101. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  102. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  103. package/src/input/agent-workspace-token.ts +18 -2
  104. package/src/input/agent-workspace-types.ts +212 -4
  105. package/src/input/agent-workspace-voice-media.ts +4 -7
  106. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  107. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  108. package/src/input/agent-workspace.ts +178 -240
  109. package/src/input/command-registry.ts +5 -2
  110. package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
  111. package/src/input/commands/agent-skills-runtime.ts +149 -72
  112. package/src/input/commands/agent-workspace-runtime.ts +23 -6
  113. package/src/input/commands/brief-runtime.ts +55 -25
  114. package/src/input/commands/channels-runtime.ts +147 -33
  115. package/src/input/commands/compat-runtime.ts +32 -0
  116. package/src/input/commands/delegation-runtime.ts +29 -23
  117. package/src/input/commands/experience-runtime.ts +6 -4
  118. package/src/input/commands/guidance-runtime.ts +4 -4
  119. package/src/input/commands/health-runtime.ts +149 -126
  120. package/src/input/commands/knowledge.ts +82 -60
  121. package/src/input/commands/local-provider-runtime.ts +43 -21
  122. package/src/input/commands/local-runtime.ts +138 -16
  123. package/src/input/commands/local-setup-review.ts +10 -20
  124. package/src/input/commands/mcp-runtime.ts +63 -46
  125. package/src/input/commands/notify-runtime.ts +38 -9
  126. package/src/input/commands/operator-actions-runtime.ts +138 -0
  127. package/src/input/commands/operator-runtime.ts +6 -76
  128. package/src/input/commands/personas-runtime.ts +46 -31
  129. package/src/input/commands/planning-runtime.ts +1 -1
  130. package/src/input/commands/platform-access-runtime.ts +35 -98
  131. package/src/input/commands/product-runtime.ts +2 -2
  132. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  133. package/src/input/commands/qrcode-runtime.ts +50 -9
  134. package/src/input/commands/recall-bundle.ts +11 -11
  135. package/src/input/commands/recall-capture.ts +13 -11
  136. package/src/input/commands/recall-query.ts +29 -21
  137. package/src/input/commands/recall-review.ts +2 -1
  138. package/src/input/commands/routines-runtime.ts +99 -45
  139. package/src/input/commands/runtime-services.ts +1 -14
  140. package/src/input/commands/schedule-runtime.ts +33 -20
  141. package/src/input/commands/security-runtime.ts +6 -11
  142. package/src/input/commands/session-content.ts +80 -78
  143. package/src/input/commands/session-workflow.ts +134 -104
  144. package/src/input/commands/session.ts +3 -174
  145. package/src/input/commands/shell-core.ts +38 -17
  146. package/src/input/commands/subscription-runtime.ts +54 -185
  147. package/src/input/commands/support-bundle-runtime.ts +53 -0
  148. package/src/input/commands/tasks-runtime.ts +21 -21
  149. package/src/input/commands/work-plan-runtime.ts +33 -8
  150. package/src/input/commands.ts +6 -2
  151. package/src/input/feed-context-factory.ts +2 -2
  152. package/src/input/file-picker.ts +3 -2
  153. package/src/input/handler-command-route.ts +4 -7
  154. package/src/input/handler-content-actions.ts +89 -26
  155. package/src/input/handler-feed-routes.ts +19 -12
  156. package/src/input/handler-feed.ts +6 -5
  157. package/src/input/handler-interactions.ts +9 -36
  158. package/src/input/handler-modal-stack.ts +3 -3
  159. package/src/input/handler-onboarding.ts +52 -91
  160. package/src/input/handler-shortcuts.ts +16 -7
  161. package/src/input/handler.ts +50 -23
  162. package/src/input/input-history.ts +5 -6
  163. package/src/input/keybindings.ts +27 -16
  164. package/src/input/mcp-workspace.ts +90 -26
  165. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  166. package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
  167. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  168. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  169. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
  170. package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
  171. package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
  172. package/src/input/onboarding/onboarding-wizard.ts +87 -2
  173. package/src/input/profile-picker-modal.ts +31 -12
  174. package/src/input/session-picker-modal.ts +21 -4
  175. package/src/input/settings-modal-agent-policy.ts +6 -6
  176. package/src/input/settings-modal-behavior.ts +0 -3
  177. package/src/input/settings-modal-subscriptions.ts +3 -3
  178. package/src/input/settings-modal-types.ts +2 -13
  179. package/src/input/settings-modal.ts +20 -66
  180. package/src/input/submission-intent.ts +0 -1
  181. package/src/input/submission-router.ts +3 -3
  182. package/src/main.ts +18 -10
  183. package/src/panels/approval-panel.ts +8 -8
  184. package/src/panels/automation-control-panel.ts +4 -4
  185. package/src/panels/base-panel.ts +1 -1
  186. package/src/panels/builtin/agent.ts +1 -1
  187. package/src/panels/builtin/operations.ts +3 -12
  188. package/src/panels/builtin/session.ts +32 -24
  189. package/src/panels/builtin/shared.ts +7 -7
  190. package/src/panels/cost-tracker-panel.ts +1 -1
  191. package/src/panels/docs-panel.ts +5 -3
  192. package/src/panels/index.ts +0 -1
  193. package/src/panels/knowledge-panel.ts +6 -5
  194. package/src/panels/memory-panel.ts +7 -6
  195. package/src/panels/panel-list-panel.ts +36 -80
  196. package/src/panels/project-planning-panel.ts +19 -12
  197. package/src/panels/provider-account-snapshot.ts +51 -25
  198. package/src/panels/provider-accounts-panel.ts +33 -18
  199. package/src/panels/provider-health-domains.ts +48 -7
  200. package/src/panels/provider-health-panel.ts +5 -4
  201. package/src/panels/qr-panel.ts +44 -20
  202. package/src/panels/schedule-panel.ts +9 -17
  203. package/src/panels/security-panel.ts +8 -8
  204. package/src/panels/session-browser-panel.ts +10 -10
  205. package/src/panels/subscription-panel.ts +6 -6
  206. package/src/panels/system-messages-panel.ts +3 -3
  207. package/src/panels/tasks-panel.ts +21 -14
  208. package/src/panels/tool-inspector-panel.ts +19 -12
  209. package/src/panels/work-plan-panel.ts +5 -5
  210. package/src/planning/project-planning-coordinator.ts +3 -3
  211. package/src/provider-auth-route-display.ts +9 -0
  212. package/src/renderer/agent-workspace-style.ts +34 -0
  213. package/src/renderer/agent-workspace.ts +254 -57
  214. package/src/renderer/autocomplete-overlay.ts +25 -6
  215. package/src/renderer/block-actions.ts +1 -3
  216. package/src/renderer/bookmark-modal.ts +19 -4
  217. package/src/renderer/buffer.ts +4 -2
  218. package/src/renderer/context-inspector.ts +50 -13
  219. package/src/renderer/diff.ts +1 -1
  220. package/src/renderer/file-picker-overlay.ts +19 -6
  221. package/src/renderer/help-overlay.ts +112 -34
  222. package/src/renderer/history-search-overlay.ts +19 -4
  223. package/src/renderer/live-tail-modal.ts +27 -5
  224. package/src/renderer/mcp-workspace.ts +176 -43
  225. package/src/renderer/model-picker-overlay.ts +58 -3
  226. package/src/renderer/model-workspace.ts +104 -22
  227. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  228. package/src/renderer/process-modal.ts +27 -6
  229. package/src/renderer/profile-picker-modal.ts +21 -5
  230. package/src/renderer/search-overlay.ts +25 -5
  231. package/src/renderer/selection-modal-overlay.ts +46 -14
  232. package/src/renderer/session-picker-modal.ts +18 -1
  233. package/src/renderer/settings-modal-helpers.ts +2 -40
  234. package/src/renderer/settings-modal.ts +88 -55
  235. package/src/renderer/system-message.ts +1 -1
  236. package/src/renderer/tool-call.ts +20 -11
  237. package/src/runtime/agent-runtime-events.ts +129 -0
  238. package/src/runtime/bootstrap-command-context.ts +7 -1
  239. package/src/runtime/bootstrap-command-parts.ts +11 -8
  240. package/src/runtime/bootstrap-core.ts +23 -65
  241. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  242. package/src/runtime/bootstrap-shell.ts +46 -8
  243. package/src/runtime/bootstrap.ts +36 -46
  244. package/src/runtime/connected-host-auth.ts +47 -0
  245. package/src/runtime/diagnostics/panels/index.ts +2 -2
  246. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  247. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  248. package/src/runtime/index.ts +2 -5
  249. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  250. package/src/runtime/onboarding/apply.ts +288 -74
  251. package/src/runtime/onboarding/derivation.ts +10 -13
  252. package/src/runtime/onboarding/snapshot.ts +2 -17
  253. package/src/runtime/onboarding/types.ts +34 -20
  254. package/src/runtime/onboarding/verify.ts +105 -4
  255. package/src/runtime/operator-token-cleanup.ts +3 -3
  256. package/src/runtime/services.ts +95 -11
  257. package/src/runtime/store/selectors/index.ts +3 -3
  258. package/src/runtime/store/state.ts +1 -4
  259. package/src/runtime/surface-feature-flags.ts +41 -6
  260. package/src/runtime/ui-read-models.ts +3 -4
  261. package/src/runtime/ui-services.ts +6 -6
  262. package/src/shell/blocking-input.ts +2 -1
  263. package/src/shell/service-settings-sync.ts +7 -7
  264. package/src/shell/ui-openers.ts +17 -38
  265. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  266. package/src/tools/agent-channel-send-tool.ts +133 -0
  267. package/src/tools/agent-context-policy.ts +1 -1
  268. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  269. package/src/tools/agent-knowledge-tool.ts +170 -0
  270. package/src/tools/agent-local-registry-tool.ts +279 -73
  271. package/src/tools/agent-media-generate-tool.ts +133 -0
  272. package/src/tools/agent-notify-tool.ts +143 -0
  273. package/src/tools/agent-operator-action-tool.ts +137 -0
  274. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  275. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  276. package/src/tools/agent-tool-policy-guard.ts +13 -15
  277. package/src/tools/agent-work-plan-tool.ts +256 -0
  278. package/src/version.ts +1 -1
  279. package/docs/connected-services.md +0 -51
  280. package/src/cli/package-verification.ts +0 -274
  281. package/src/input/commands/policy-dispatch.ts +0 -339
  282. package/src/input/commands/policy.ts +0 -17
  283. package/src/panels/panel-picker.ts +0 -105
  284. package/src/panels/policy-panel.ts +0 -308
  285. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -34,7 +34,7 @@ export async function submitAgentWorkspaceMemoryEditor(
34
34
  detail: detail.length > 0 ? detail : undefined,
35
35
  tags,
36
36
  });
37
- if (!updated) throw new Error(`Unknown Agent memory: ${editor.recordId}`);
37
+ if (!updated) throw new Error(`Unknown Agent memory ${editor.recordId}`);
38
38
  return { record: updated, verb: 'Updated' };
39
39
  }
40
40
 
@@ -67,7 +67,7 @@ export function deleteAgentWorkspaceMemoryEditor(
67
67
  const expectedId = editor.recordId ?? '';
68
68
  if (!expectedId || confirmedId !== expectedId) return null;
69
69
  const removed = memory.delete(expectedId);
70
- if (!removed) throw new Error(`Unknown Agent memory: ${expectedId}`);
70
+ if (!removed) throw new Error(`Unknown Agent memory ${expectedId}`);
71
71
  return { id: expectedId, name: expectedId };
72
72
  }
73
73
 
@@ -0,0 +1,81 @@
1
+ import type { AgentWorkspaceAction, AgentWorkspaceCategory, AgentWorkspaceCategoryId, AgentWorkspaceFocusPane } from './agent-workspace-types.ts';
2
+
3
+ interface AgentWorkspaceNavigationHost {
4
+ readonly categories: readonly AgentWorkspaceCategory[];
5
+ readonly actions: readonly AgentWorkspaceAction[];
6
+ focusPane: AgentWorkspaceFocusPane;
7
+ selectedCategoryIndex: number;
8
+ selectedActionIndex: number;
9
+ clampSelection(): void;
10
+ }
11
+
12
+ const AGENT_WORKSPACE_CATEGORY_ALIASES = {
13
+ connected: 'host',
14
+ 'connected-host': 'host',
15
+ host: 'host',
16
+ mcp: 'tools',
17
+ tool: 'tools',
18
+ channel: 'channels',
19
+ voice: 'voice-media',
20
+ media: 'voice-media',
21
+ profile: 'profiles',
22
+ persona: 'personas',
23
+ skill: 'skills',
24
+ routine: 'routines',
25
+ schedule: 'automation',
26
+ schedules: 'automation',
27
+ plan: 'work',
28
+ planning: 'work',
29
+ task: 'host',
30
+ tasks: 'host',
31
+ note: 'notes',
32
+ scratchpad: 'notes',
33
+ kb: 'knowledge',
34
+ } as const satisfies Readonly<Record<string, AgentWorkspaceCategoryId>>;
35
+
36
+ type AgentWorkspaceCategoryAlias = keyof typeof AGENT_WORKSPACE_CATEGORY_ALIASES;
37
+
38
+ function isAgentWorkspaceCategoryAlias(categoryIdOrLabel: string): categoryIdOrLabel is AgentWorkspaceCategoryAlias {
39
+ return Object.prototype.hasOwnProperty.call(AGENT_WORKSPACE_CATEGORY_ALIASES, categoryIdOrLabel);
40
+ }
41
+
42
+ function normalizeAgentWorkspaceCategoryRequest(categoryIdOrLabel: string): string {
43
+ const normalized = categoryIdOrLabel.trim().toLowerCase();
44
+ if (!normalized) return '';
45
+ return isAgentWorkspaceCategoryAlias(normalized) ? AGENT_WORKSPACE_CATEGORY_ALIASES[normalized] : normalized;
46
+ }
47
+
48
+ export function moveAgentWorkspaceSelection(host: AgentWorkspaceNavigationHost, delta: -1 | 1): void {
49
+ if (host.focusPane === 'categories') {
50
+ host.selectedCategoryIndex = Math.max(0, Math.min(host.categories.length - 1, host.selectedCategoryIndex + delta));
51
+ host.selectedActionIndex = 0;
52
+ } else {
53
+ host.selectedActionIndex = Math.max(0, Math.min(host.actions.length - 1, host.selectedActionIndex + delta));
54
+ }
55
+ host.clampSelection();
56
+ }
57
+
58
+ export function jumpAgentWorkspaceSelection(host: AgentWorkspaceNavigationHost, target: 'home' | 'end'): void {
59
+ if (host.focusPane === 'categories') {
60
+ host.selectedCategoryIndex = target === 'home' ? 0 : host.categories.length - 1;
61
+ } else {
62
+ host.selectedActionIndex = target === 'home' ? 0 : host.actions.length - 1;
63
+ }
64
+ host.clampSelection();
65
+ }
66
+
67
+ export function selectAgentWorkspaceCategory(host: AgentWorkspaceNavigationHost, categoryIdOrLabel: string): boolean {
68
+ const normalized = normalizeAgentWorkspaceCategoryRequest(categoryIdOrLabel);
69
+ if (!normalized) return false;
70
+ const categoryIndex = host.categories.findIndex((category) =>
71
+ category.id.toLowerCase() === normalized
72
+ || category.label.toLowerCase() === normalized
73
+ || category.label.toLowerCase().replace(/[^a-z0-9]+/g, '-') === normalized
74
+ );
75
+ if (categoryIndex < 0) return false;
76
+ host.selectedCategoryIndex = categoryIndex;
77
+ host.selectedActionIndex = 0;
78
+ host.focusPane = 'actions';
79
+ host.clampSelection();
80
+ return true;
81
+ }
@@ -0,0 +1,121 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
3
+
4
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
5
+
6
+ export type AgentWorkspaceNotifyEditorKind = 'notify-webhook' | 'notify-webhook-remove' | 'notify-webhook-clear' | 'notify-webhook-test' | 'notify-send';
7
+
8
+ export type AgentWorkspaceNotifyEditorSubmission =
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
+ };
21
+
22
+ export function isAgentWorkspaceNotifyEditorKind(kind: string): kind is AgentWorkspaceNotifyEditorKind {
23
+ return kind === 'notify-webhook'
24
+ || kind === 'notify-webhook-remove'
25
+ || kind === 'notify-webhook-clear'
26
+ || kind === 'notify-webhook-test'
27
+ || kind === 'notify-send';
28
+ }
29
+
30
+ function isAffirmative(value: string): boolean {
31
+ return /^(y|yes|true)$/i.test(value.trim());
32
+ }
33
+
34
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string, status: string): AgentWorkspaceNotifyEditorSubmission {
35
+ return {
36
+ kind: 'editor',
37
+ editor: { ...editor, message },
38
+ status,
39
+ };
40
+ }
41
+
42
+ function dispatch(command: string, title: string, status: string, detail: string): AgentWorkspaceNotifyEditorSubmission {
43
+ return {
44
+ kind: 'dispatch',
45
+ command,
46
+ status,
47
+ actionResult: {
48
+ kind: 'dispatched',
49
+ title,
50
+ detail,
51
+ command,
52
+ safety: 'safe',
53
+ },
54
+ };
55
+ }
56
+
57
+ export function buildAgentWorkspaceNotifyEditorSubmission(
58
+ editor: AgentWorkspaceLocalEditor,
59
+ readField: AgentWorkspaceFieldReader,
60
+ ): AgentWorkspaceNotifyEditorSubmission {
61
+ if (editor.kind === 'notify-webhook') {
62
+ if (!isAffirmative(readField('confirm'))) {
63
+ return unconfirmed(editor, 'Notification webhook add not confirmed. Type yes, then press Enter.', 'Notification webhook add not confirmed.');
64
+ }
65
+ const command = `/notify add ${quoteSlashCommandArg(readField('url'))} --yes`;
66
+ return dispatch(
67
+ command,
68
+ 'Opening notification webhook add',
69
+ 'Opening notification webhook add.',
70
+ 'The workspace handed a confirmed notification target command to the shell-owned command router.',
71
+ );
72
+ }
73
+
74
+ if (editor.kind === 'notify-webhook-remove') {
75
+ if (!isAffirmative(readField('confirm'))) {
76
+ return unconfirmed(editor, 'Notification webhook remove not confirmed. Type yes, then press Enter.', 'Notification webhook remove not confirmed.');
77
+ }
78
+ const command = `/notify remove ${quoteSlashCommandArg(readField('url'))} --yes`;
79
+ return dispatch(
80
+ command,
81
+ 'Opening notification webhook remove',
82
+ 'Opening notification webhook remove.',
83
+ 'The workspace handed a confirmed notification target remove command to the shell-owned command router.',
84
+ );
85
+ }
86
+
87
+ if (editor.kind === 'notify-webhook-clear') {
88
+ if (!isAffirmative(readField('confirm'))) {
89
+ return unconfirmed(editor, 'Notification webhook clear not confirmed. Type yes, then press Enter.', 'Notification webhook clear not confirmed.');
90
+ }
91
+ return dispatch(
92
+ '/notify clear --yes',
93
+ 'Opening notification webhook clear',
94
+ 'Opening notification webhook clear.',
95
+ 'The workspace handed a confirmed notification target cleanup command to the shell-owned command router.',
96
+ );
97
+ }
98
+
99
+ if (editor.kind === 'notify-send') {
100
+ if (!isAffirmative(readField('confirm'))) {
101
+ return unconfirmed(editor, 'Notification send not confirmed. Type yes, then press Enter.', 'Notification send not confirmed.');
102
+ }
103
+ const command = `/notify send ${quoteSlashCommandArg(readField('message'))} --yes`;
104
+ return dispatch(
105
+ command,
106
+ 'Opening notification send',
107
+ 'Opening notification send.',
108
+ 'The workspace handed a confirmed notification send command to the shell-owned command router.',
109
+ );
110
+ }
111
+
112
+ if (!isAffirmative(readField('confirm'))) {
113
+ return unconfirmed(editor, 'Notification webhook test not confirmed. Type yes, then press Enter.', 'Notification webhook test not confirmed.');
114
+ }
115
+ return dispatch(
116
+ '/notify test --yes',
117
+ 'Opening notification webhook test',
118
+ 'Opening notification webhook test.',
119
+ 'The workspace handed a confirmed notification test command to the shell-owned command router.',
120
+ );
121
+ }
@@ -0,0 +1,208 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import type { AgentWorkspaceOperationsCommandEditorKind } from './agent-workspace-operations-command-editors.ts';
3
+ import { isAgentWorkspaceOperationsCommandEditorKind } from './agent-workspace-operations-command-editors.ts';
4
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
5
+
6
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
7
+
8
+ function isAffirmative(value: string): boolean {
9
+ return /^(y|yes|true)$/i.test(value.trim());
10
+ }
11
+
12
+ function optionalNoteArgs(value: string): string {
13
+ const trimmed = value.trim();
14
+ return trimmed ? ` --note ${quoteSlashCommandArg(trimmed)}` : '';
15
+ }
16
+
17
+ function optionalRememberArgs(value: string): string {
18
+ const trimmed = value.trim();
19
+ if (!trimmed) return '';
20
+ return isAffirmative(trimmed) ? ' --remember' : ' --no-remember';
21
+ }
22
+
23
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceOperationsCommandEditorSubmission {
24
+ return {
25
+ kind: 'editor',
26
+ editor: { ...editor, message },
27
+ status: message,
28
+ };
29
+ }
30
+
31
+ export type AgentWorkspaceOperationsCommandEditorSubmission =
32
+ | {
33
+ readonly kind: 'editor';
34
+ readonly editor: AgentWorkspaceLocalEditor;
35
+ readonly status: string;
36
+ readonly actionResult?: AgentWorkspaceActionResult;
37
+ }
38
+ | {
39
+ readonly kind: 'dispatch';
40
+ readonly command: string;
41
+ readonly status: string;
42
+ readonly actionResult: AgentWorkspaceActionResult;
43
+ };
44
+
45
+ export function isAgentWorkspaceOperationsCommandSubmissionKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceOperationsCommandEditorKind {
46
+ return isAgentWorkspaceOperationsCommandEditorKind(kind);
47
+ }
48
+
49
+ export function buildAgentWorkspaceOperationsCommandEditorSubmission(
50
+ editor: AgentWorkspaceLocalEditor,
51
+ readField: AgentWorkspaceFieldReader,
52
+ ): AgentWorkspaceOperationsCommandEditorSubmission {
53
+ if (editor.kind === 'plan-seed') {
54
+ const command = `/plan ${quoteSlashCommandArg(readField('goal'))}`;
55
+ return {
56
+ kind: 'dispatch',
57
+ command,
58
+ status: 'Opening planning goal seeding.',
59
+ actionResult: {
60
+ kind: 'dispatched',
61
+ title: 'Opening planning goal seeding',
62
+ detail: 'The workspace handed a concrete planning goal to the shell-owned command router without creating coding-role Agent jobs.',
63
+ command,
64
+ safety: 'safe',
65
+ },
66
+ };
67
+ }
68
+ if (editor.kind === 'plan-approve') {
69
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Planning approval not confirmed. Type yes, then press Enter.');
70
+ return {
71
+ kind: 'dispatch',
72
+ command: '/plan approve --yes',
73
+ status: 'Opening planning approval.',
74
+ actionResult: {
75
+ kind: 'dispatched',
76
+ title: 'Opening planning approval',
77
+ detail: 'The workspace handed confirmed planning approval to the shell-owned command router.',
78
+ command: '/plan approve --yes',
79
+ safety: 'safe',
80
+ },
81
+ };
82
+ }
83
+ if (editor.kind === 'plan-override') {
84
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Planning strategy override not confirmed. Type yes, then press Enter.');
85
+ const command = `/plan override ${quoteSlashCommandArg(readField('strategy'))} --yes`;
86
+ return {
87
+ kind: 'dispatch',
88
+ command,
89
+ status: 'Opening planning strategy override.',
90
+ actionResult: {
91
+ kind: 'dispatched',
92
+ title: 'Opening planning strategy override',
93
+ detail: 'The workspace handed a confirmed planning strategy override to the shell-owned command router.',
94
+ command,
95
+ safety: 'safe',
96
+ },
97
+ };
98
+ }
99
+ if (editor.kind === 'plan-clear') {
100
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Planning clear not confirmed. Type yes, then press Enter.');
101
+ return {
102
+ kind: 'dispatch',
103
+ command: '/plan clear --yes',
104
+ status: 'Opening planning clear.',
105
+ actionResult: {
106
+ kind: 'dispatched',
107
+ title: 'Opening planning clear',
108
+ detail: 'The workspace handed confirmed planning-state clearing to the shell-owned command router.',
109
+ command: '/plan clear --yes',
110
+ safety: 'safe',
111
+ },
112
+ };
113
+ }
114
+ if (editor.kind === 'approval-approve' || editor.kind === 'approval-deny' || editor.kind === 'approval-cancel') {
115
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Approval action not confirmed. Type yes, then press Enter.');
116
+ const verb = editor.kind.replace('approval-', '');
117
+ const command = `/approval ${verb} ${quoteSlashCommandArg(readField('approvalId'))}${optionalNoteArgs(readField('note'))}${optionalRememberArgs(readField('remember'))} --yes`;
118
+ const title = `${verb[0]?.toUpperCase() ?? ''}${verb.slice(1)} approval`;
119
+ return {
120
+ kind: 'dispatch',
121
+ command,
122
+ status: `${title}.`,
123
+ actionResult: {
124
+ kind: 'dispatched',
125
+ title,
126
+ detail: 'The workspace handed an explicit confirmed approval action to the shell-owned command router.',
127
+ command,
128
+ safety: 'safe',
129
+ },
130
+ };
131
+ }
132
+ if (
133
+ editor.kind === 'automation-job-run'
134
+ || editor.kind === 'automation-job-pause'
135
+ || editor.kind === 'automation-job-resume'
136
+ || editor.kind === 'automation-run-cancel'
137
+ || editor.kind === 'automation-run-retry'
138
+ || editor.kind === 'schedule-run'
139
+ ) {
140
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Automation action not confirmed. Type yes, then press Enter.');
141
+ const command = editor.kind === 'automation-job-run'
142
+ ? `/automation job run ${quoteSlashCommandArg(readField('jobId'))} --yes`
143
+ : editor.kind === 'automation-job-pause'
144
+ ? `/automation job pause ${quoteSlashCommandArg(readField('jobId'))} --yes`
145
+ : editor.kind === 'automation-job-resume'
146
+ ? `/automation job resume ${quoteSlashCommandArg(readField('jobId'))} --yes`
147
+ : editor.kind === 'automation-run-cancel'
148
+ ? `/automation run cancel ${quoteSlashCommandArg(readField('runId'))} --yes`
149
+ : editor.kind === 'automation-run-retry'
150
+ ? `/automation run retry ${quoteSlashCommandArg(readField('runId'))} --yes`
151
+ : `/automation schedule run ${quoteSlashCommandArg(readField('scheduleId'))} --yes`;
152
+ return {
153
+ kind: 'dispatch',
154
+ command,
155
+ status: 'Opening confirmed automation action.',
156
+ actionResult: {
157
+ kind: 'dispatched',
158
+ title: 'Opening confirmed automation action',
159
+ detail: 'The workspace handed an explicit connected-host automation action to the shell-owned command router.',
160
+ command,
161
+ safety: 'safe',
162
+ },
163
+ };
164
+ }
165
+ if (editor.kind === 'routine-receipt' || editor.kind === 'schedule-receipt') {
166
+ const routine = editor.kind === 'routine-receipt';
167
+ const command = `/${routine ? 'routines' : 'schedule'} receipt ${quoteSlashCommandArg(readField('receiptId'))}`;
168
+ const title = routine ? 'Opening routine receipt' : 'Opening schedule receipt';
169
+ return {
170
+ kind: 'dispatch',
171
+ command,
172
+ status: `${title}.`,
173
+ actionResult: {
174
+ kind: 'dispatched',
175
+ title,
176
+ detail: routine
177
+ ? 'The workspace handed read-only routine receipt inspection to the shell-owned command router.'
178
+ : 'The workspace handed read-only schedule receipt inspection to the shell-owned command router.',
179
+ command,
180
+ safety: 'read-only',
181
+ },
182
+ };
183
+ }
184
+ const plan = editor.kind === 'plan-show';
185
+ const approval = editor.kind === 'approval-review';
186
+ const command = plan
187
+ ? `/plan show ${quoteSlashCommandArg(readField('planId'))}`
188
+ : approval
189
+ ? `/approval review ${quoteSlashCommandArg(readField('kind'))}`
190
+ : `/health repair ${quoteSlashCommandArg(readField('domain'))}`;
191
+ const title = plan ? 'Opening saved plan' : approval ? 'Opening approval review' : 'Opening health repair guidance';
192
+ return {
193
+ kind: 'dispatch',
194
+ command,
195
+ status: `${title}.`,
196
+ actionResult: {
197
+ kind: 'dispatched',
198
+ title,
199
+ detail: plan
200
+ ? 'The workspace handed read-only saved-plan inspection to the shell-owned command router.'
201
+ : approval
202
+ ? 'The workspace handed read-only approval class review to the shell-owned command router.'
203
+ : 'The workspace handed read-only health repair guidance to the shell-owned command router.',
204
+ command,
205
+ safety: 'read-only',
206
+ },
207
+ };
208
+ }
@@ -0,0 +1,196 @@
1
+ import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+
3
+ export type AgentWorkspaceOperationsCommandEditorKind = Extract<
4
+ AgentWorkspaceEditorKind,
5
+ | 'plan-seed'
6
+ | 'plan-show'
7
+ | 'plan-approve'
8
+ | 'plan-override'
9
+ | 'plan-clear'
10
+ | 'health-repair'
11
+ | 'approval-review'
12
+ | 'approval-approve'
13
+ | 'approval-deny'
14
+ | 'approval-cancel'
15
+ | 'automation-job-run'
16
+ | 'automation-job-pause'
17
+ | 'automation-job-resume'
18
+ | 'automation-run-cancel'
19
+ | 'automation-run-retry'
20
+ | 'schedule-run'
21
+ | 'routine-receipt'
22
+ | 'schedule-receipt'
23
+ >;
24
+
25
+ export function isAgentWorkspaceOperationsCommandEditorKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceOperationsCommandEditorKind {
26
+ return kind === 'plan-seed'
27
+ || kind === 'plan-show'
28
+ || kind === 'plan-approve'
29
+ || kind === 'plan-override'
30
+ || kind === 'plan-clear'
31
+ || kind === 'health-repair'
32
+ || kind === 'approval-review'
33
+ || kind === 'approval-approve'
34
+ || kind === 'approval-deny'
35
+ || kind === 'approval-cancel'
36
+ || kind === 'automation-job-run'
37
+ || kind === 'automation-job-pause'
38
+ || kind === 'automation-job-resume'
39
+ || kind === 'automation-run-cancel'
40
+ || kind === 'automation-run-retry'
41
+ || kind === 'schedule-run'
42
+ || kind === 'routine-receipt'
43
+ || kind === 'schedule-receipt';
44
+ }
45
+
46
+ export function createAgentWorkspaceOperationsCommandEditor(kind: AgentWorkspaceOperationsCommandEditorKind): AgentWorkspaceLocalEditor {
47
+ if (kind === 'plan-seed') {
48
+ return {
49
+ kind,
50
+ mode: 'create',
51
+ title: 'Seed Planning Goal',
52
+ selectedFieldIndex: 0,
53
+ message: 'Seed Agent planning state from a concrete goal. This stays in the main Agent planning flow and does not create coding-role Agent jobs.',
54
+ fields: [
55
+ { id: 'goal', label: 'Planning goal', value: '', required: true, multiline: true, hint: 'Describe the goal or operating plan to evaluate. Ctrl-J inserts a new line.' },
56
+ ],
57
+ };
58
+ }
59
+ if (kind === 'health-repair') {
60
+ return {
61
+ kind,
62
+ mode: 'create',
63
+ title: 'Show Health Repair Guidance',
64
+ selectedFieldIndex: 0,
65
+ message: 'Show health repair guidance for one domain. Agent does not manage connected-host hosting or mutate connected-host lifecycle.',
66
+ fields: [
67
+ { id: 'domain', label: 'Domain', value: 'settings', required: true, multiline: false, hint: 'settings, auth, accounts, host, remote, mcp, continuity, or maintenance.' },
68
+ ],
69
+ };
70
+ }
71
+ if (kind === 'approval-review') {
72
+ return {
73
+ kind,
74
+ mode: 'create',
75
+ title: 'Review Approval Class',
76
+ selectedFieldIndex: 0,
77
+ message: 'Review one approval class without approving, denying, or mutating pending requests.',
78
+ fields: [
79
+ { id: 'kind', label: 'Approval kind', value: 'shell', required: true, multiline: false, hint: 'shell, file, network, delegate, mcp, remote, hook, or plugin.' },
80
+ ],
81
+ };
82
+ }
83
+ if (kind === 'approval-approve' || kind === 'approval-deny' || kind === 'approval-cancel') {
84
+ const verb = kind === 'approval-approve' ? 'Approve' : kind === 'approval-deny' ? 'Deny' : 'Cancel';
85
+ return {
86
+ kind,
87
+ mode: 'update',
88
+ title: `${verb} Approval`,
89
+ selectedFieldIndex: 0,
90
+ message: `${verb} one pending connected-host approval request. This is an explicit operator action and requires typed confirmation.`,
91
+ fields: [
92
+ { id: 'approvalId', label: 'Approval id', value: '', required: true, multiline: false, hint: 'Approval request id from the approval list.' },
93
+ { id: 'note', label: 'Note', value: '', required: false, multiline: true, hint: 'Optional approval note. Ctrl-J inserts a new line.' },
94
+ { id: 'remember', label: 'Remember', value: '', required: false, multiline: false, hint: 'yes/no when you explicitly want to set the connected-host remember flag; blank leaves it unset.' },
95
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: `Type yes to run /approval ${kind.replace('approval-', '')} with --yes.` },
96
+ ],
97
+ };
98
+ }
99
+ if (
100
+ kind === 'automation-job-run'
101
+ || kind === 'automation-job-pause'
102
+ || kind === 'automation-job-resume'
103
+ || kind === 'automation-run-cancel'
104
+ || kind === 'automation-run-retry'
105
+ || kind === 'schedule-run'
106
+ ) {
107
+ const job = kind.startsWith('automation-job-');
108
+ const run = kind.startsWith('automation-run-');
109
+ const label = job ? 'Job id' : run ? 'Run id' : 'Schedule id';
110
+ const field = job ? 'jobId' : run ? 'runId' : 'scheduleId';
111
+ const action = kind === 'automation-job-run'
112
+ ? 'Run Automation Job'
113
+ : kind === 'automation-job-pause'
114
+ ? 'Pause Automation Job'
115
+ : kind === 'automation-job-resume'
116
+ ? 'Resume Automation Job'
117
+ : kind === 'automation-run-cancel'
118
+ ? 'Cancel Automation Run'
119
+ : kind === 'automation-run-retry'
120
+ ? 'Retry Automation Run'
121
+ : 'Run Schedule';
122
+ return {
123
+ kind,
124
+ mode: 'update',
125
+ title: action,
126
+ selectedFieldIndex: 0,
127
+ message: `${action} through the connected host. This is never automatic and requires typed confirmation.`,
128
+ fields: [
129
+ { id: field, label, value: '', required: true, multiline: false, hint: `${label} from the Automation workspace list.` },
130
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run the confirmed connected-host action with --yes.' },
131
+ ],
132
+ };
133
+ }
134
+ if (kind === 'plan-approve') {
135
+ return {
136
+ kind,
137
+ mode: 'update',
138
+ title: 'Approve Planning State',
139
+ selectedFieldIndex: 0,
140
+ message: 'Approve the current Agent planning state for execution. This changes planning state and requires typed confirmation.',
141
+ fields: [
142
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /plan approve with --yes.' },
143
+ ],
144
+ };
145
+ }
146
+ if (kind === 'plan-override') {
147
+ return {
148
+ kind,
149
+ mode: 'update',
150
+ title: 'Override Planning Strategy',
151
+ selectedFieldIndex: 0,
152
+ message: 'Override the planner strategy through the runtime bridge. This changes planner state and requires typed confirmation.',
153
+ fields: [
154
+ { id: 'strategy', label: 'Strategy', value: 'serial', required: true, multiline: false, hint: 'Planner strategy, such as serial.' },
155
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /plan override with --yes.' },
156
+ ],
157
+ };
158
+ }
159
+ if (kind === 'plan-clear') {
160
+ return {
161
+ kind,
162
+ mode: 'delete',
163
+ title: 'Clear Planning State',
164
+ selectedFieldIndex: 0,
165
+ message: 'Clear planner state. This is destructive and requires typed confirmation.',
166
+ fields: [
167
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /plan clear with --yes.' },
168
+ ],
169
+ };
170
+ }
171
+ if (kind === 'routine-receipt' || kind === 'schedule-receipt') {
172
+ const routine = kind === 'routine-receipt';
173
+ return {
174
+ kind,
175
+ mode: 'create',
176
+ title: routine ? 'Show Routine Promotion Receipt' : 'Show Schedule Receipt',
177
+ selectedFieldIndex: 0,
178
+ message: routine
179
+ ? 'Show one local routine schedule-promotion receipt without reconciling or mutating connected schedules.'
180
+ : 'Show one local schedule receipt without reconciling or mutating connected schedules.',
181
+ fields: [
182
+ { id: 'receiptId', label: 'Receipt id', value: '', required: true, multiline: false, hint: 'Receipt id from Promotion receipts.' },
183
+ ],
184
+ };
185
+ }
186
+ return {
187
+ kind,
188
+ mode: 'create',
189
+ title: 'Show Saved Plan',
190
+ selectedFieldIndex: 0,
191
+ message: 'Show one saved execution plan by id or prefix without approving or starting execution.',
192
+ fields: [
193
+ { id: 'planId', label: 'Plan id', value: '', required: true, multiline: false, hint: 'Plan id or unique prefix from Saved plans.' },
194
+ ],
195
+ };
196
+ }
@@ -0,0 +1,43 @@
1
+ import type { AgentWorkspaceCategoryId } from './agent-workspace-types.ts';
2
+
3
+ const PANEL_CATEGORY_ROUTES = {
4
+ knowledge: 'knowledge',
5
+ memory: 'memory',
6
+ 'work-plan': 'work',
7
+ 'project-planning': 'work',
8
+ plan: 'work',
9
+ approval: 'work',
10
+ tasks: 'work',
11
+ 'provider-health': 'setup',
12
+ automation: 'automation',
13
+ schedule: 'automation',
14
+ providers: 'setup',
15
+ accounts: 'setup',
16
+ subscription: 'setup',
17
+ cost: 'setup',
18
+ tokens: 'setup',
19
+ security: 'tools',
20
+ policy: 'tools',
21
+ tools: 'tools',
22
+ 'qr-code': 'channels',
23
+ sessions: 'conversation',
24
+ context: 'conversation',
25
+ thinking: 'conversation',
26
+ 'system-messages': 'conversation',
27
+ docs: 'home',
28
+ 'panel-list': 'home',
29
+ } as const satisfies Readonly<Record<string, AgentWorkspaceCategoryId>>;
30
+
31
+ type AgentWorkspacePanelRouteId = keyof typeof PANEL_CATEGORY_ROUTES;
32
+
33
+ function hasPanelCategoryRoute(panelId: string): panelId is AgentWorkspacePanelRouteId {
34
+ return Object.prototype.hasOwnProperty.call(PANEL_CATEGORY_ROUTES, panelId);
35
+ }
36
+
37
+ export function agentWorkspaceCategoryForPanel(panelId: string): AgentWorkspaceCategoryId {
38
+ return hasPanelCategoryRoute(panelId) ? PANEL_CATEGORY_ROUTES[panelId] : 'home';
39
+ }
40
+
41
+ export function agentWorkspaceCommandForPanel(panelId: string): string {
42
+ return `/agent ${agentWorkspaceCategoryForPanel(panelId)}`;
43
+ }