@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
@@ -1,14 +1,13 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, resolve } from 'node:path';
3
3
  import type { CommandContext, CommandRegistry } from '../command-registry.ts';
4
- import { createOAuthLocalListener } from '@pellux/goodvibes-sdk/platform/config';
5
4
  import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
6
5
  import type { OAuthProviderConfig, ProviderSubscription } from '@pellux/goodvibes-sdk/platform/config';
7
6
  import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
8
7
  import { inspectProviderAuth } from '@/runtime/index.ts';
8
+ import { formatAgentRecordSource } from '../../agent/record-labels.ts';
9
9
  import { openExternalUrl } from '@pellux/goodvibes-sdk/platform/utils';
10
10
  import { requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
11
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
12
11
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
13
12
 
14
13
  interface SubscriptionBundle {
@@ -24,13 +23,13 @@ function buildReviewText(ctx: CommandContext): string {
24
23
  return [
25
24
  'Subscription Review',
26
25
  ' No provider subscriptions stored yet.',
27
- ...(available.length > 0 ? [` available providers: ${available.map((entry) => entry.provider).join(', ')}`] : []),
26
+ ...(available.length > 0 ? [` available providers ${available.map((entry) => entry.provider).join(', ')}`] : []),
28
27
  ].join('\n');
29
28
  }
30
29
  return [
31
30
  `Subscription Review`,
32
31
  ...subscriptions.map((subscription) => (
33
- ` ${subscription.provider} ${subscription.authMode} token=${subscription.tokenType} expires=${subscription.expiresAt ? new Date(subscription.expiresAt).toISOString() : 'n/a'}`
32
+ ` ${subscription.provider} auth mode ${subscription.authMode} token ${subscription.tokenType} expires ${subscription.expiresAt ? new Date(subscription.expiresAt).toISOString() : 'n/a'}`
34
33
  )),
35
34
  ].join('\n');
36
35
  }
@@ -39,8 +38,8 @@ function inspectBundle(path: string): string {
39
38
  const bundle = JSON.parse(readFileSync(path, 'utf-8')) as SubscriptionBundle;
40
39
  return [
41
40
  'Subscription Bundle Review',
42
- ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
43
- ` subscriptions: ${bundle.subscriptions.length}`,
41
+ ` exported at ${new Date(bundle.exportedAt).toISOString()}`,
42
+ ` subscriptions ${bundle.subscriptions.length}`,
44
43
  ...bundle.subscriptions.map((subscription) => ` ${subscription.provider} ${subscription.authMode}`),
45
44
  ].join('\n');
46
45
  }
@@ -57,19 +56,16 @@ function extractAuthorizationCode(input: string): string | null {
57
56
  }
58
57
  }
59
58
 
60
- function resolveLoginConfig(config: OAuthProviderConfig, useLocalCallback: boolean): OAuthProviderConfig {
61
- if (!useLocalCallback || !config.localCallback) {
62
- return config.manualRedirectUri
63
- ? { ...config, redirectUri: config.manualRedirectUri }
64
- : config;
65
- }
66
- return config;
59
+ function resolveManualLoginConfig(config: OAuthProviderConfig): OAuthProviderConfig {
60
+ return config.manualRedirectUri
61
+ ? { ...config, redirectUri: config.manualRedirectUri }
62
+ : config;
67
63
  }
68
64
 
69
65
  function describePrecedence(record: Pick<ProviderSubscription, 'overrideAmbientApiKeys'>): string {
70
66
  return record.overrideAmbientApiKeys
71
- ? ' precedence: this now overrides ambient API keys for the provider'
72
- : ' precedence: stored for subscription-backed flows only; ambient API keys are unchanged';
67
+ ? ' precedence this now overrides ambient API keys for the provider'
68
+ : ' precedence stored for subscription-backed flows only; ambient API keys are unchanged';
73
69
  }
74
70
 
75
71
  export function registerSubscriptionRuntimeCommands(registry: CommandRegistry): void {
@@ -77,15 +73,10 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
77
73
  name: 'subscription',
78
74
  aliases: ['subs'],
79
75
  description: 'Manage provider subscription sessions and, when supported, let them override ambient API keys for matching providers',
80
- usage: '[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>]',
76
+ 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>]',
81
77
  async handler(args, ctx) {
82
78
  const parsed = stripYesFlag(args);
83
79
  const commandArgs = [...parsed.rest];
84
- const shellPaths = requireShellPaths(ctx);
85
- if (args.length === 0 && ctx.openSubscriptionPanel) {
86
- ctx.openSubscriptionPanel();
87
- return;
88
- }
89
80
  const sub = (commandArgs[0] ?? 'review').toLowerCase();
90
81
  const manager = requireSubscriptionManager(ctx);
91
82
  const services = requireServiceRegistry(ctx);
@@ -104,7 +95,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
104
95
  ctx.print([
105
96
  'Available Subscription Providers',
106
97
  ...available.map((provider) => (
107
- ` ${provider.provider} source=${provider.source} redirect=${provider.oauth.redirectUri}`
98
+ ` ${provider.provider} origin ${formatAgentRecordSource(provider.source)} redirect ${provider.oauth.redirectUri}`
108
99
  )),
109
100
  ].join('\n'));
110
101
  return;
@@ -128,29 +119,28 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
128
119
  });
129
120
  ctx.print([
130
121
  `Subscription ${provider}`,
131
- ` configured: ${inspection.configured ? 'yes' : 'no'}`,
132
- ` freshness: ${inspection.freshness}`,
133
- ` callbackMode: ${inspection.callbackMode}`,
122
+ ` configured ${inspection.configured ? 'yes' : 'no'}`,
123
+ ` freshness ${inspection.freshness}`,
124
+ ' finish mode explicit manual',
134
125
  ...(resolved ? [
135
- ` source: ${resolved.source}`,
136
- ` redirectUri: ${resolved.oauth.redirectUri}`,
137
- ` authUrl: ${resolved.oauth.authUrl}`,
138
- ` tokenUrl: ${resolved.oauth.tokenUrl}`,
139
- ...(inspection.localCallback ? [` localCallback: ${inspection.localCallback}`] : []),
126
+ ` origin ${formatAgentRecordSource(resolved.source)}`,
127
+ ` redirect URI ${resolved.oauth.redirectUri}`,
128
+ ` auth URL ${resolved.oauth.authUrl}`,
129
+ ` token URL ${resolved.oauth.tokenUrl}`,
140
130
  ] : []),
141
131
  ...(inspection.activeSubscription ? [
142
- ` authMode: ${manager.get(provider)?.authMode ?? 'oauth'}`,
143
- ` tokenType: ${inspection.tokenType ?? 'n/a'}`,
144
- ` createdAt: ${manager.get(provider)?.createdAt ? new Date(manager.get(provider)!.createdAt).toISOString() : 'n/a'}`,
145
- ` updatedAt: ${manager.get(provider)?.updatedAt ? new Date(manager.get(provider)!.updatedAt).toISOString() : 'n/a'}`,
146
- ` expiresAt: ${inspection.expiresAt ? new Date(inspection.expiresAt).toISOString() : 'n/a'}`,
147
- ` refreshToken: ${manager.get(provider)?.refreshToken ? 'present' : 'absent'}`,
132
+ ` auth mode ${manager.get(provider)?.authMode ?? 'oauth'}`,
133
+ ` token type ${inspection.tokenType ?? 'n/a'}`,
134
+ ` created at ${manager.get(provider)?.createdAt ? new Date(manager.get(provider)!.createdAt).toISOString() : 'n/a'}`,
135
+ ` updated at ${manager.get(provider)?.updatedAt ? new Date(manager.get(provider)!.updatedAt).toISOString() : 'n/a'}`,
136
+ ` expires at ${inspection.expiresAt ? new Date(inspection.expiresAt).toISOString() : 'n/a'}`,
137
+ ` refresh token ${manager.get(provider)?.refreshToken ? 'present' : 'absent'}`,
148
138
  describePrecedence(manager.get(provider)!),
149
139
  ] : [
150
- ` state: ${inspection.freshness === 'pending' ? 'pending login' : 'available for login'}`,
140
+ ` state ${inspection.freshness === 'pending' ? 'pending login' : 'available for login'}`,
151
141
  ]),
152
- ...inspection.issues.map((issue) => ` issue: ${issue}`),
153
- ...inspection.nextActions.map((action) => ` next: ${action}`),
142
+ ...inspection.issues.map((issue) => ` issue ${issue}`),
143
+ ...inspection.nextActions.map((action) => ` next ${action}`),
154
144
  ].join('\n'));
155
145
  return;
156
146
  }
@@ -179,7 +169,6 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
179
169
  if (mode === 'start') {
180
170
  const flags = new Set(commandArgs.slice(3));
181
171
  const openBrowser = !flags.has('--no-browser');
182
- const useManualMode = flags.has('--manual');
183
172
  if (provider === 'openai' && resolved.source === 'builtin') {
184
173
  const started = await beginOpenAICodexLogin();
185
174
  manager.savePending({
@@ -190,158 +179,38 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
190
179
  createdAt: Date.now(),
191
180
  });
192
181
 
193
- let listener: Awaited<ReturnType<typeof createOAuthLocalListener>> | null = null;
194
- if (!useManualMode) {
195
- try {
196
- listener = await createOAuthLocalListener({
197
- expectedState: started.state,
198
- host: '127.0.0.1',
199
- port: 1455,
200
- path: '/auth/callback',
201
- }).catch(() => null); // best-effort: listener creation is optional; null triggers manual flow
202
- } catch {
203
- listener = null;
204
- }
205
- }
206
-
207
182
  const browserOpened = openBrowser
208
183
  ? await openExternalUrl(started.authorizationUrl)
209
184
  : false;
210
185
 
211
- if (listener && browserOpened) {
212
- try {
213
- const callback = await listener.waitForCode();
214
- const token = await exchangeOpenAICodexCode(callback.code, started.verifier);
215
- const now = Date.now();
216
- const record = manager.saveSubscription({
217
- provider,
218
- accessToken: token.accessToken,
219
- refreshToken: token.refreshToken,
220
- tokenType: token.tokenType,
221
- expiresAt: token.expiresAt,
222
- ...(token.scopes ? { scopes: token.scopes } : {}),
223
- authMode: 'oauth',
224
- overrideAmbientApiKeys: false,
225
- createdAt: manager.get(provider)?.createdAt ?? now,
226
- updatedAt: now,
227
- });
228
- ctx.print([
229
- `Subscription OAuth Start: ${provider}`,
230
- ` source: ${resolved.source}`,
231
- ` state: ${started.state}`,
232
- ` redirectUri: ${started.redirectUri}`,
233
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
234
- ' authorizationUrl:',
235
- ` ${started.authorizationUrl}`,
236
- `Subscription OAuth Complete: ${provider}`,
237
- ` tokenType: ${record.tokenType}`,
238
- ` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
239
- describePrecedence(record),
240
- ].join('\n'));
241
- return;
242
- } catch (error) {
243
- listener.close();
244
- ctx.print([
245
- `Subscription OAuth Start: ${provider}`,
246
- ` source: ${resolved.source}`,
247
- ` state: ${started.state}`,
248
- ` redirectUri: ${started.redirectUri}`,
249
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
250
- ` next: /subscription login ${provider} finish <code-or-url> --yes`,
251
- ` listener: ${summarizeError(error)}`,
252
- ' authorizationUrl:',
253
- ` ${started.authorizationUrl}`,
254
- ].join('\n'));
255
- return;
256
- }
257
- }
258
-
259
- listener?.close();
260
186
  ctx.print([
261
- `Subscription OAuth Start: ${provider}`,
262
- ` source: ${resolved.source}`,
263
- ` state: ${started.state}`,
264
- ` redirectUri: ${started.redirectUri}`,
265
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
266
- ` next: /subscription login ${provider} finish <code-or-url> --yes`,
267
- ' authorizationUrl:',
187
+ `Subscription OAuth start ${provider}`,
188
+ ` origin ${formatAgentRecordSource(resolved.source)}`,
189
+ ` state ${started.state}`,
190
+ ` redirect URI ${started.redirectUri}`,
191
+ ` browser ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
192
+ ' completion paste the callback code or redirect URL into the finish command',
193
+ ` next /subscription login ${provider} finish <code-or-url> --yes`,
194
+ ' authorization URL',
268
195
  ` ${started.authorizationUrl}`,
269
196
  ].join('\n'));
270
197
  return;
271
198
  }
272
- const useLocalCallback = Boolean(resolved.oauth.localCallback) && !flags.has('--manual');
273
- let activeConfig = resolveLoginConfig(resolved.oauth, useLocalCallback);
274
- let listener: Awaited<ReturnType<typeof createOAuthLocalListener>> | null = null;
275
-
276
- if (useLocalCallback && resolved.oauth.localCallback) {
277
- listener = await createOAuthLocalListener({
278
- expectedState: '',
279
- host: resolved.oauth.localCallback.host,
280
- port: resolved.oauth.localCallback.port,
281
- path: resolved.oauth.localCallback.path,
282
- }).catch(() => null); // best-effort: local callback listener is optional; null falls back to manual redirect
283
- }
284
-
285
- if (listener) {
286
- activeConfig = { ...activeConfig, redirectUri: listener.redirectUri };
287
- }
288
-
199
+ const activeConfig = resolveManualLoginConfig(resolved.oauth);
289
200
  const started = await manager.beginOAuthLogin(provider, activeConfig);
290
- if (listener) {
291
- listener.setExpectedState(started.pending.state);
292
- }
293
-
294
201
  const browserOpened = openBrowser
295
- ? await openExternalUrl(started.authorizationUrl)
296
- : false;
297
-
298
- const shouldAutoComplete = Boolean(listener) && (resolved.oauth.localCallback?.autoComplete ?? true) && browserOpened;
299
-
300
- if (shouldAutoComplete && listener) {
301
- try {
302
- const callback = await listener.waitForCode();
303
- const record = await manager.completeOAuthLogin(provider, activeConfig, callback.code);
304
- ctx.print([
305
- `Subscription OAuth Start: ${provider}`,
306
- ` source: ${resolved.source}`,
307
- ` state: ${started.pending.state}`,
308
- ` redirectUri: ${activeConfig.redirectUri}`,
309
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
310
- ' authorizationUrl:',
311
- ` ${started.authorizationUrl}`,
312
- `Subscription OAuth Complete: ${provider}`,
313
- ` tokenType: ${record.tokenType}`,
314
- ` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
315
- describePrecedence(record),
316
- ].join('\n'));
317
- return;
318
- } catch (error) {
319
- listener.close();
320
- ctx.print([
321
- `Subscription OAuth Start: ${provider}`,
322
- ` source: ${resolved.source}`,
323
- ` state: ${started.pending.state}`,
324
- ` redirectUri: ${activeConfig.redirectUri}`,
325
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
326
- ` next: /subscription login ${provider} finish <code-or-url> --yes`,
327
- ` listener: ${summarizeError(error)}`,
328
- ' authorizationUrl:',
329
- ` ${started.authorizationUrl}`,
330
- ].join('\n'));
331
- return;
332
- }
333
- }
334
-
335
- listener?.close();
202
+ ? await openExternalUrl(started.authorizationUrl)
203
+ : false;
336
204
 
337
205
  ctx.print([
338
- `Subscription OAuth Start: ${provider}`,
339
- ` source: ${resolved.source}`,
340
- ` state: ${started.pending.state}`,
341
- ` redirectUri: ${activeConfig.redirectUri}`,
342
- ` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
343
- ` next: /subscription login ${provider} finish <code-or-url> --yes`,
344
- ' authorizationUrl:',
206
+ `Subscription OAuth start ${provider}`,
207
+ ` origin ${formatAgentRecordSource(resolved.source)}`,
208
+ ` state ${started.pending.state}`,
209
+ ` redirect URI ${activeConfig.redirectUri}`,
210
+ ` browser ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
211
+ ' completion paste the callback code or redirect URL into the finish command',
212
+ ` next /subscription login ${provider} finish <code-or-url> --yes`,
213
+ ' authorization URL',
345
214
  ` ${started.authorizationUrl}`,
346
215
  ].join('\n'));
347
216
  return;
@@ -375,18 +244,18 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
375
244
  });
376
245
  ctx.print([
377
246
  `Stored subscription session for ${provider}.`,
378
- ` tokenType: ${record.tokenType}`,
379
- ` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
247
+ ` token type ${record.tokenType}`,
248
+ ` expires at ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
380
249
  describePrecedence(record),
381
250
  ].join('\n'));
382
251
  return;
383
252
  }
384
- const activeConfig = resolveLoginConfig(resolved.oauth, false);
253
+ const activeConfig = resolveManualLoginConfig(resolved.oauth);
385
254
  const record = await manager.completeOAuthLogin(provider, activeConfig, code);
386
255
  ctx.print([
387
256
  `Stored subscription session for ${provider}.`,
388
- ` tokenType: ${record.tokenType}`,
389
- ` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
257
+ ` token type ${record.tokenType}`,
258
+ ` expires at ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
390
259
  describePrecedence(record),
391
260
  ].join('\n'));
392
261
  return;
@@ -419,7 +288,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
419
288
  ctx.print('Usage: /subscription bundle <export|inspect> <path>');
420
289
  return;
421
290
  }
422
- const targetPath = shellPaths.resolveWorkspacePath(pathArg);
291
+ const targetPath = requireShellPaths(ctx).resolveWorkspacePath(pathArg);
423
292
  if (mode === 'export') {
424
293
  if (!parsed.yes) {
425
294
  requireYesFlag(ctx, `export subscription bundle to ${pathArg}`, '/subscription bundle export <path> --yes');
@@ -0,0 +1,53 @@
1
+ import type { CommandRegistry } from '../command-registry.ts';
2
+ import type { CliCommandRuntime } from '../../cli/management.ts';
3
+ import { handleBundleCommand } from '../../cli/bundle-command.ts';
4
+ import { parseGoodVibesCli } from '../../cli/parser.ts';
5
+ import { requireShellPaths } from './runtime-services.ts';
6
+ import { requireYesFlag, stripYesFlag } from './confirmation.ts';
7
+
8
+ function bundleUsageFor(subcommand: string | undefined): string {
9
+ if (subcommand === 'export') return '/bundle export [path] --yes';
10
+ if (subcommand === 'import') return '/bundle import <path> --yes';
11
+ if (subcommand === 'inspect') return '/bundle inspect <path>';
12
+ return '/bundle [export [path] --yes|inspect <path>|import <path> --yes]';
13
+ }
14
+
15
+ function bundleActionFor(subcommand: string): string | null {
16
+ if (subcommand === 'export') return 'export Agent support bundle';
17
+ if (subcommand === 'import') return 'import Agent support bundle';
18
+ return null;
19
+ }
20
+
21
+ export function registerSupportBundleRuntimeCommands(registry: CommandRegistry): void {
22
+ registry.register({
23
+ name: 'bundle',
24
+ description: 'Export, inspect, or import redacted Agent support bundles from the TUI',
25
+ usage: '[export [path] --yes|inspect <path>|import <path> --yes]',
26
+ argsHint: 'export|inspect|import',
27
+ async handler(args, ctx) {
28
+ const confirmation = stripYesFlag(args);
29
+ const cli = parseGoodVibesCli(['bundle', ...confirmation.rest], 'goodvibes-agent');
30
+ if (cli.errors.length > 0) {
31
+ ctx.print(cli.errors.join('\n'));
32
+ return;
33
+ }
34
+
35
+ const subcommand = cli.commandArgs[0] ?? 'inspect';
36
+ const guardedAction = bundleActionFor(subcommand);
37
+ if (guardedAction !== null && !confirmation.yes) {
38
+ requireYesFlag(ctx, guardedAction, bundleUsageFor(subcommand));
39
+ return;
40
+ }
41
+
42
+ const shellPaths = requireShellPaths(ctx);
43
+ const runtime: CliCommandRuntime = {
44
+ cli,
45
+ configManager: ctx.platform.configManager,
46
+ workingDirectory: shellPaths.workingDirectory,
47
+ homeDirectory: shellPaths.homeDirectory,
48
+ };
49
+ const result = await handleBundleCommand(runtime);
50
+ ctx.print(result.output);
51
+ },
52
+ });
53
+ }
@@ -16,10 +16,10 @@ const BLOCKED_TASK_MUTATIONS: ReadonlySet<string> = new Set([
16
16
  function printTaskMutationBlocked(print: (text: string) => void, subcommand: string): void {
17
17
  print([
18
18
  `Task mutation "${subcommand}" is blocked in GoodVibes Agent.`,
19
- ' policy: connected-service tasks are read-only from the Agent TUI; normal work stays in the main conversation.',
20
- ' durable tasks: use /workplan for visible planning and task tracking.',
21
- ' build/fix/review: use /delegate <task> to hand explicit implementation work to GoodVibes TUI.',
22
- ' result: no local task state was changed.',
19
+ ' policy connected-host tasks are read-only from the Agent TUI; normal work stays in the main conversation.',
20
+ ' durable tasks use /workplan for visible planning and task tracking.',
21
+ ' build/fix/review use /delegate <task> to hand explicit implementation work to GoodVibes TUI.',
22
+ ' result no local task state was changed.',
23
23
  ].join('\n'));
24
24
  }
25
25
 
@@ -51,12 +51,12 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
51
51
  registry.register({
52
52
  name: 'tasks',
53
53
  aliases: ['task'],
54
- description: 'Inspect connected-service tasks without starting or mutating local background work',
54
+ description: 'Inspect connected-host tasks without starting or mutating local background work',
55
55
  usage: '[list [status|kind] | show <taskId> | output <taskId>]',
56
56
  handler(args, ctx) {
57
57
  const subcommand = args[0]?.toLowerCase() ?? 'list';
58
58
  if (subcommand === 'open' || subcommand === 'panel') {
59
- ctx.print('Task panels are not part of the Agent workspace. Use /tasks list.');
59
+ ctx.print('Open Agent Workspace -> Work -> Host tasks for the workspace view, or run /tasks list for compact command output.');
60
60
  return;
61
61
  }
62
62
 
@@ -76,7 +76,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
76
76
  return;
77
77
  }
78
78
  ctx.print([
79
- `Runtime Tasks (${filtered.length})`,
79
+ `Connected-host Tasks (${filtered.length})`,
80
80
  ...filtered.slice(0, 20).map((task) => ` ${task.id} ${task.status.padEnd(9)} ${task.kind.padEnd(11)} ${task.owner} ${task.title}`),
81
81
  ].join('\n'));
82
82
  return;
@@ -90,23 +90,23 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
90
90
  }
91
91
  const task = operatorClient.tasks.get(taskId);
92
92
  if (!task) {
93
- ctx.print(`Unknown task: ${taskId}`);
93
+ ctx.print(`Unknown task ${taskId}`);
94
94
  return;
95
95
  }
96
96
  ctx.print([
97
97
  `Task ${task.id}`,
98
- ` title: ${task.title}`,
98
+ ` title ${task.title}`,
99
99
  ` kind: ${task.kind}`,
100
- ` status: ${task.status}`,
101
- ` owner: ${task.owner}`,
102
- ` cancellable: ${task.cancellable ? 'yes' : 'no'}`,
103
- ` queuedAt: ${new Date(task.queuedAt).toISOString()}`,
104
- ` startedAt: ${task.startedAt ? new Date(task.startedAt).toISOString() : 'n/a'}`,
105
- ` endedAt: ${task.endedAt ? new Date(task.endedAt).toISOString() : 'n/a'}`,
106
- ` parent: ${task.parentTaskId ?? 'none'}`,
107
- ` children: ${task.childTaskIds.join(', ') || '(none)'}`,
108
- ` correlationId: ${task.correlationId ?? 'n/a'}`,
109
- ` summary: ${summarizeTaskResult(task)}`,
100
+ ` status ${task.status}`,
101
+ ` owner ${task.owner}`,
102
+ ` cancellable ${task.cancellable ? 'yes' : 'no'}`,
103
+ ` queued at ${new Date(task.queuedAt).toISOString()}`,
104
+ ` started at ${task.startedAt ? new Date(task.startedAt).toISOString() : 'n/a'}`,
105
+ ` ended at ${task.endedAt ? new Date(task.endedAt).toISOString() : 'n/a'}`,
106
+ ` parent ${task.parentTaskId ?? 'none'}`,
107
+ ` children ${task.childTaskIds.join(', ') || '(none)'}`,
108
+ ` correlation ID ${task.correlationId ?? 'n/a'}`,
109
+ ` summary ${summarizeTaskResult(task)}`,
110
110
  ].join('\n'));
111
111
  return;
112
112
  }
@@ -119,7 +119,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
119
119
  }
120
120
  const task = operatorClient.tasks.get(taskId);
121
121
  if (!task) {
122
- ctx.print(`Unknown task: ${taskId}`);
122
+ ctx.print(`Unknown task ${taskId}`);
123
123
  return;
124
124
  }
125
125
  const payload = typeof task.result === 'string'
@@ -131,7 +131,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
131
131
  return;
132
132
  }
133
133
 
134
- ctx.print(`Unknown tasks subcommand: ${subcommand}`);
134
+ ctx.print(`Unknown tasks subcommand ${subcommand}`);
135
135
  },
136
136
  });
137
137
  }
@@ -26,7 +26,12 @@ function getStore(ctx: import('../command-registry.ts').CommandContext): WorkPla
26
26
 
27
27
  function formatList(store: WorkPlanStore): string {
28
28
  const items = store.listItems();
29
- if (items.length === 0) return 'Work plan is empty. Add one with /workplan add <title>.';
29
+ if (items.length === 0) {
30
+ return [
31
+ 'Work plan is empty',
32
+ ' next /workplan add <title>',
33
+ ].join('\n');
34
+ }
30
35
  return [
31
36
  `Work Plan (${items.length})`,
32
37
  ...items.map((item) => {
@@ -83,7 +88,7 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
83
88
  const subcommand = (commandArgs[0] ?? 'list').toLowerCase();
84
89
  try {
85
90
  if (subcommand === 'panel' || subcommand === 'open') {
86
- ctx.print('Work plan panels are not part of the Agent workspace. Use /workplan list.');
91
+ ctx.print('Open Agent Workspace -> Work -> Work plan for the workspace view, or run /workplan list for compact command output.');
87
92
  return;
88
93
  }
89
94
  if (subcommand === 'list') {
@@ -106,7 +111,12 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
106
111
  ...(addArgs.notes ? { notes: addArgs.notes } : {}),
107
112
  };
108
113
  const item = store.addItem(addArgs.title, addOptions);
109
- ctx.print(`Added work plan item ${item.id}. Use /workplan list to review.`);
114
+ ctx.print([
115
+ 'Added work plan item',
116
+ ` id ${item.id}`,
117
+ ` title ${item.title}`,
118
+ ' next open Agent Workspace -> Work -> Work plan to review',
119
+ ].join('\n'));
110
120
  return;
111
121
  }
112
122
  if (subcommand === 'remove' || subcommand === 'delete' || subcommand === 'rm') {
@@ -120,7 +130,11 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
120
130
  return;
121
131
  }
122
132
  const item = store.removeItem(id);
123
- ctx.print(`Removed work plan item ${item.id}: ${item.title}`);
133
+ ctx.print([
134
+ 'Removed work plan item',
135
+ ` id ${item.id}`,
136
+ ` title ${item.title}`,
137
+ ].join('\n'));
124
138
  return;
125
139
  }
126
140
  if (subcommand === 'clear-done' || subcommand === 'clear-completed') {
@@ -129,7 +143,10 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
129
143
  return;
130
144
  }
131
145
  const count = store.clearCompleted();
132
- ctx.print(`Cleared ${count} completed/cancelled work plan item${count === 1 ? '' : 's'}.`);
146
+ ctx.print([
147
+ 'Cleared completed/cancelled work plan items',
148
+ ` count ${count}`,
149
+ ].join('\n'));
133
150
  return;
134
151
  }
135
152
  if (subcommand === 'cycle' || subcommand === 'toggle') {
@@ -139,7 +156,11 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
139
156
  return;
140
157
  }
141
158
  const item = store.cycleItemStatus(id);
142
- ctx.print(`Updated ${item.id}: ${item.status}.`);
159
+ ctx.print([
160
+ 'Updated work plan item',
161
+ ` id ${item.id}`,
162
+ ` status ${item.status}`,
163
+ ].join('\n'));
143
164
  return;
144
165
  }
145
166
  const status = STATUS_COMMANDS[subcommand];
@@ -150,14 +171,18 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
150
171
  return;
151
172
  }
152
173
  const item = store.setItemStatus(id, status);
153
- ctx.print(`Updated ${item.id}: ${item.status}.`);
174
+ ctx.print([
175
+ 'Updated work plan item',
176
+ ` id ${item.id}`,
177
+ ` status ${item.status}`,
178
+ ].join('\n'));
154
179
  return;
155
180
  }
156
181
  if (WORK_PLAN_STATUSES.includes(subcommand as WorkPlanItemStatus)) {
157
182
  ctx.print(`Usage: /workplan ${subcommand} <id>`);
158
183
  return;
159
184
  }
160
- ctx.print(`Unknown workplan subcommand: ${subcommand}`);
185
+ ctx.print(`Unknown workplan subcommand ${subcommand}`);
161
186
  } catch (error) {
162
187
  ctx.print(summarizeError(error));
163
188
  }
@@ -36,6 +36,9 @@ import { registerAgentSkillsRuntimeCommands } from './commands/agent-skills-runt
36
36
  import { registerRoutinesRuntimeCommands } from './commands/routines-runtime.ts';
37
37
  import { registerChannelsRuntimeCommands } from './commands/channels-runtime.ts';
38
38
  import { registerBriefRuntimeCommands } from './commands/brief-runtime.ts';
39
+ import { registerSupportBundleRuntimeCommands } from './commands/support-bundle-runtime.ts';
40
+ import { registerCompatRuntimeCommands } from './commands/compat-runtime.ts';
41
+ import { registerOperatorActionRuntimeCommands } from './commands/operator-actions-runtime.ts';
39
42
 
40
43
  function registerAgentMemoryCommand(registry: CommandRegistry): void {
41
44
  registry.register({
@@ -58,6 +61,9 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
58
61
  registerShellCoreCommands(registry);
59
62
  registerAgentWorkspaceRuntimeCommands(registry);
60
63
  registerBriefRuntimeCommands(registry);
64
+ registerSupportBundleRuntimeCommands(registry);
65
+ registerCompatRuntimeCommands(registry);
66
+ registerOperatorActionRuntimeCommands(registry);
61
67
  registerAgentRuntimeProfileRuntimeCommands(registry);
62
68
  registerPersonasRuntimeCommands(registry);
63
69
  registerAgentSkillsRuntimeCommands(registry);
@@ -66,7 +72,6 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
66
72
  registerDelegationRuntimeCommands(registry);
67
73
  registerConfigCommand(registry);
68
74
  registerOperatorRuntimeCommands(registry);
69
- registry.unregister('profiles');
70
75
  registerNotifyRuntimeCommands(registry);
71
76
  registerProductRuntimeCommands(registry);
72
77
  registerPlatformAccessRuntimeCommands(registry);
@@ -89,7 +94,6 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
89
94
  registerPlanningRuntimeCommands(registry);
90
95
  registerScheduleRuntimeCommands(registry);
91
96
  registerSessionContentCommands(registry);
92
- registry.unregister('session-memory');
93
97
  registerAgentMemoryCommand(registry);
94
98
 
95
99
  // ── /session ─────────────────────────────────────────────────────────────
@@ -140,7 +140,6 @@ export interface FeedContextClosures {
140
140
  handleBlockCopy: () => void;
141
141
  handleBookmark: () => void;
142
142
  handleBlockSave: () => void;
143
- handleDiffApply: () => boolean;
144
143
  handleUndo: () => void;
145
144
  handleRedo: () => void;
146
145
  handlePaste: () => void;
@@ -148,7 +147,8 @@ export interface FeedContextClosures {
148
147
  ensureInputCursorVisible: (contentWidth?: number) => void;
149
148
  registerPaste: (content: string) => string;
150
149
  executeBlockAction: (id: string) => void;
151
- cyclePanelTab: (direction: 'next' | 'prev') => void;
150
+ cycleAgentWorkspaceCategory: (direction: 'next' | 'prev') => void;
151
+ dismissAgentWorkspace: () => boolean;
152
152
  onPanelInputConsumed: (activePanel: Panel | null, key: string) => void;
153
153
  getWrappedPromptInfo: (contentWidth: number) => WrappedPromptInfo;
154
154
  moveCursorVertical: (direction: -1 | 1) => boolean;