@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
package/src/cli/status.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
2
2
  import type { OnboardingCheckMarkersState } from '../runtime/onboarding/index.ts';
3
3
  import { resolveRuntimeEndpointBinding } from './endpoints.ts';
4
- import { isNetworkFacing } from './network-posture.ts';
5
4
  import type { GoodVibesCliOutputFormat } from './types.ts';
6
5
  import type { CliServicePosture } from './service-posture.ts';
7
6
  import type { CliExternalRuntimeSnapshot } from './external-runtime.ts';
8
7
  import { getProviderIdFromModel } from '../config/provider-model.ts';
8
+ import { formatAgentRecordSource } from '../agent/record-labels.ts';
9
+ import { formatAgentKnowledgeFailureKind } from './agent-knowledge-format.ts';
9
10
 
10
11
  export interface CliStatusOptions {
11
12
  readonly configManager: Pick<ConfigManager, 'get'>;
@@ -30,7 +31,7 @@ export interface CliAuthStatus {
30
31
 
31
32
  export interface CliDoctorFinding {
32
33
  readonly id: string;
33
- readonly area: 'auth' | 'network' | 'onboarding' | 'runtime' | 'security' | 'secrets';
34
+ readonly area: 'auth' | 'onboarding' | 'runtime' | 'security' | 'secrets';
34
35
  readonly severity: 'warning' | 'risk';
35
36
  readonly summary: string;
36
37
  readonly cause: string;
@@ -92,29 +93,11 @@ function secretPolicyLabel(policy: unknown): string {
92
93
  return String(policy ?? 'unknown');
93
94
  }
94
95
 
95
- function bindLine(label: string, enabled: unknown, binding: { readonly hostMode: string; readonly host: string; readonly port: number }): string {
96
- return ` ${label}: ${yesNo(enabled)} (${binding.hostMode} ${binding.host}:${binding.port})`;
97
- }
98
-
99
96
  export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliDoctorFinding[] {
100
97
  const config = options.configManager;
101
- const serviceEnabled = config.get('service.enabled') === true;
102
- const daemonEnabled = config.get('danger.daemon') === true;
103
- const listenerEnabled = config.get('danger.httpListener') === true;
104
- const webEnabled = config.get('web.enabled') === true;
105
- const controlPlaneEnabled = config.get('controlPlane.enabled') === true;
106
- const controlPlaneBinding = resolveRuntimeEndpointBinding(config, 'controlPlane');
107
- const httpListenerBinding = resolveRuntimeEndpointBinding(config, 'httpListener');
108
- const webBinding = resolveRuntimeEndpointBinding(config, 'web');
109
98
  const permissionMode = config.get('permissions.mode');
110
99
  const secretPolicy = config.get('storage.secretPolicy');
111
100
  const marker = options.onboardingMarkers?.effective;
112
- const serverBackedEnabled = daemonEnabled || controlPlaneEnabled || listenerEnabled || webEnabled;
113
- const networkFacingSurfaces = [
114
- ['runtime connection', controlPlaneEnabled, controlPlaneBinding],
115
- ['inbound events endpoint', listenerEnabled, httpListenerBinding],
116
- ['browser companion route', webEnabled, webBinding],
117
- ].filter(([, enabled, binding]) => isNetworkFacing(enabled, binding as typeof controlPlaneBinding));
118
101
 
119
102
  const findings: CliDoctorFinding[] = [];
120
103
 
@@ -124,18 +107,18 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
124
107
  id: 'external-runtime-unreachable',
125
108
  area: 'runtime',
126
109
  severity: 'warning',
127
- summary: 'Connected GoodVibes services are not reachable.',
110
+ summary: 'Connected GoodVibes host is not reachable.',
128
111
  cause: `Agent could not reach ${options.externalRuntime.baseUrl}${options.externalRuntime.error ? `: ${options.externalRuntime.error}` : '.'}`,
129
- impact: 'Companion chat, isolated Agent Knowledge, approvals, automation status, and build delegation cannot work until connected GoodVibes services are available.',
130
- action: 'Start or repair the owning GoodVibes host, then rerun goodvibes-agent status.',
112
+ impact: 'Companion chat, isolated Agent Knowledge, approvals, automation status, and build delegation cannot work until the connected GoodVibes host is available.',
113
+ action: 'Make the owning GoodVibes host available, then rerun goodvibes-agent status.',
131
114
  });
132
115
  } else if (!options.externalRuntime.compatible) {
133
116
  findings.push({
134
117
  id: 'external-runtime-version-mismatch',
135
118
  area: 'runtime',
136
119
  severity: 'warning',
137
- summary: 'Connected GoodVibes service SDK version does not match Agent.',
138
- cause: `Connected service reports SDK ${options.externalRuntime.version}; Agent expects ${options.externalRuntime.expectedVersion}.`,
120
+ summary: 'Connected GoodVibes host SDK version does not match Agent.',
121
+ cause: `Connected host reports SDK ${options.externalRuntime.version}; Agent expects ${options.externalRuntime.expectedVersion}.`,
139
122
  impact: 'Agent-only routes, especially isolated Agent Knowledge, may be missing or incompatible.',
140
123
  action: 'Update the owning GoodVibes host so /status matches this Agent package SDK pin.',
141
124
  });
@@ -146,9 +129,9 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
146
129
  id: 'external-runtime-token-missing',
147
130
  area: 'auth',
148
131
  severity: 'warning',
149
- summary: 'Connected-service operator token is missing.',
132
+ summary: 'Connected-host operator token is missing.',
150
133
  cause: `No operator token was found at ${options.externalRuntime.operatorToken.path}.`,
151
- impact: 'Agent can inspect only unauthenticated routes and cannot use protected connected-service APIs.',
134
+ impact: 'Agent can inspect only unauthenticated routes and cannot use protected connected-host APIs.',
152
135
  action: 'Pair or provision access through the owning GoodVibes host, then rerun goodvibes-agent auth.',
153
136
  });
154
137
  }
@@ -160,24 +143,12 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
160
143
  severity: 'warning',
161
144
  summary: 'Isolated Agent Knowledge route is not ready.',
162
145
  cause: `${options.externalRuntime.agentKnowledge.route} returned ${options.externalRuntime.agentKnowledge.kind}${options.externalRuntime.agentKnowledge.statusCode === null ? '' : ` (${options.externalRuntime.agentKnowledge.statusCode})`}.`,
163
- impact: 'Agent Knowledge ask/search will not use any fallback wiki or non-Agent knowledge segment; it will fail closed until the Agent route is available.',
164
- action: 'Update the connected GoodVibes services to the Agent-compatible SDK and verify goodvibes-agent compat.',
146
+ impact: 'Agent Knowledge ask/search will not use default or non-Agent knowledge fallback; it will fail closed until the Agent route is available.',
147
+ action: 'Update the connected GoodVibes host to the Agent-compatible SDK and verify goodvibes-agent compat.',
165
148
  });
166
149
  }
167
150
  }
168
151
 
169
- if (serverBackedEnabled && !serviceEnabled) {
170
- findings.push({
171
- id: 'runtime-ownership-external',
172
- area: 'runtime',
173
- severity: 'warning',
174
- summary: 'Connected-service settings are present while Agent service ownership is disabled by design.',
175
- cause: 'One or more connected API, inbound events, or browser companion settings are enabled while service.enabled is false.',
176
- impact: 'The owning GoodVibes host must provide availability for those endpoints; Agent will not start or enable them.',
177
- action: 'Manage connected-service availability from GoodVibes TUI or the owning host, then use Agent for read-only diagnostics.',
178
- });
179
- }
180
-
181
152
  if (options.service) {
182
153
  for (const issue of options.service.issues) {
183
154
  if (findings.some((finding) => finding.summary === issue)) continue;
@@ -186,9 +157,9 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
186
157
  area: 'runtime',
187
158
  severity: 'warning',
188
159
  summary: issue,
189
- cause: 'The connected-service inspection found a mismatch between configured endpoint state and observed host state.',
190
- impact: 'Connected API, listener, or web availability may not match the configuration.',
191
- action: 'Use Agent status and doctor diagnostics here, then manage connected services outside Agent.',
160
+ cause: 'The connected-host inspection found a mismatch between configured endpoint state and observed host state.',
161
+ impact: 'Companion chat, Agent Knowledge, approvals, automation status, or build delegation may be unavailable.',
162
+ action: 'Use Agent status and doctor diagnostics here, then repair the connected GoodVibes host outside Agent.',
192
163
  });
193
164
  }
194
165
  }
@@ -198,37 +169,13 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
198
169
  id: 'onboarding-incomplete',
199
170
  area: 'onboarding',
200
171
  severity: 'warning',
201
- summary: 'Agent setup has not been shown for this user.',
202
- cause: 'No global user setup check marker was found.',
203
- impact: 'Important connected-service, network, provider, auth, or permission choices may still be implicit defaults.',
172
+ summary: 'Agent setup has not been applied for this user.',
173
+ cause: 'No global user setup completion marker was found.',
174
+ impact: 'Provider/model, Agent Knowledge, local behavior, channel, and permission choices may still be implicit defaults.',
204
175
  action: 'Run /setup in GoodVibes Agent or goodvibes-agent setup status to review setup state.',
205
176
  });
206
177
  }
207
178
 
208
- if (networkFacingSurfaces.length > 0 && options.auth?.userStorePresent !== true) {
209
- findings.push({
210
- id: 'network-endpoint-without-runtime-auth-signal',
211
- area: 'auth',
212
- severity: 'risk',
213
- summary: 'Network-facing connected-service endpoints are enabled without a visible auth signal.',
214
- cause: `${networkFacingSurfaces.map(([name]) => name).join(', ')} are LAN/custom-bound, but Agent cannot see connected-service auth state from its local compatibility files.`,
215
- impact: 'Remote access paths may be unusable or unsafe unless the owning host configured auth.',
216
- action: 'Review connected-service auth outside Agent; Agent will not create local service users.',
217
- });
218
- }
219
-
220
- if (networkFacingSurfaces.length > 0 && options.auth?.bootstrapCredentialPresent === true) {
221
- findings.push({
222
- id: 'network-endpoint-with-bootstrap-credential',
223
- area: 'auth',
224
- severity: 'risk',
225
- summary: 'A bootstrap credential is still present while network-facing surfaces are enabled.',
226
- cause: `${networkFacingSurfaces.map(([name]) => name).join(', ')} are LAN/custom-bound and auth-bootstrap.txt exists.`,
227
- impact: 'Bootstrap credentials should be treated as temporary setup material, not long-lived network access credentials.',
228
- action: 'Replace bootstrap auth and retire the bootstrap credential outside Agent.',
229
- });
230
- }
231
-
232
179
  if (permissionMode === 'allow-all') {
233
180
  findings.push({
234
181
  id: 'allow-all-permissions',
@@ -253,18 +200,6 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
253
200
  });
254
201
  }
255
202
 
256
- if (listenerEnabled && isNetworkFacing(listenerEnabled, httpListenerBinding)) {
257
- findings.push({
258
- id: 'network-http-listener-enabled',
259
- area: 'network',
260
- severity: 'warning',
261
- summary: 'The inbound events endpoint is reachable beyond loopback.',
262
- cause: `Inbound events endpoint is enabled on ${httpListenerBinding.host}:${httpListenerBinding.port} with ${httpListenerBinding.hostMode} binding.`,
263
- impact: 'External tools and devices may be able to reach incoming event endpoints.',
264
- action: 'Keep inbound-event secrets/signature checks configured for every enabled endpoint.',
265
- });
266
- }
267
-
268
203
  return findings;
269
204
  }
270
205
 
@@ -315,13 +250,6 @@ export function buildCliStatusSnapshot(options: CliStatusOptions): CliStatusSnap
315
250
  export function renderCliStatus(options: CliStatusOptions): string {
316
251
  const config = options.configManager;
317
252
  const snapshot = buildCliStatusSnapshot(options);
318
- const serviceEnabled = snapshot.runtimeConnection.enabled;
319
- const controlPlaneEnabled = snapshot.runtimeEndpoints.controlPlane.enabled;
320
- const listenerEnabled = snapshot.runtimeEndpoints.httpListener.enabled;
321
- const webEnabled = snapshot.runtimeEndpoints.web.enabled;
322
- const controlPlaneBinding = snapshot.runtimeEndpoints.controlPlane;
323
- const httpListenerBinding = snapshot.runtimeEndpoints.httpListener;
324
- const webBinding = snapshot.runtimeEndpoints.web;
325
253
  const marker = options.onboardingMarkers?.effective;
326
254
  const findings = snapshot.findings;
327
255
  const externalRuntime = snapshot.externalRuntime;
@@ -330,70 +258,63 @@ export function renderCliStatus(options: CliStatusOptions): string {
330
258
 
331
259
  const lines = [
332
260
  snapshot.title,
333
- ` workingDir: ${options.workingDirectory}`,
334
- ` homeDir: ${options.homeDirectory}`,
261
+ ` working directory ${options.workingDirectory}`,
262
+ ` home directory ${options.homeDirectory}`,
335
263
  '',
336
- 'Provider:',
337
- ` provider: ${getProviderIdFromModel(config.get('provider.model'))}`,
338
- ` model: ${String(config.get('provider.model'))}`,
339
- ` reasoning: ${String(config.get('provider.reasoningEffort'))}`,
264
+ 'Provider',
265
+ ` provider ${getProviderIdFromModel(config.get('provider.model'))}`,
266
+ ` model ${String(config.get('provider.model'))}`,
267
+ ` reasoning ${String(config.get('provider.reasoningEffort'))}`,
340
268
  '',
341
- 'Auth:',
269
+ 'Auth',
342
270
  ` permissions: ${permissionModeLabel(config.get('permissions.mode'))} (${String(config.get('permissions.mode'))})`,
343
271
  ` secretPolicy: ${secretPolicyLabel(config.get('storage.secretPolicy'))} (${String(config.get('storage.secretPolicy'))})`,
344
272
  options.auth
345
- ? ` runtimeAuthSignal: ${options.auth.userStorePresent ? 'present' : 'missing'} (${options.auth.userStorePath})`
346
- : ' runtimeAuthSignal: unknown',
273
+ ? ` local auth store ${options.auth.userStorePresent ? 'present' : 'missing'} (${options.auth.userStorePath})`
274
+ : ' local auth store unknown',
347
275
  options.auth
348
- ? ` bootstrapCredential: ${options.auth.bootstrapCredentialPresent ? 'present' : 'missing'} (${options.auth.bootstrapCredentialPath})`
349
- : ' bootstrapCredential: unknown',
276
+ ? ` setup credential ${options.auth.bootstrapCredentialPresent ? 'present' : 'missing'} (${options.auth.bootstrapCredentialPath})`
277
+ : ' setup credential unknown',
350
278
  options.auth
351
- ? ` operatorTokens: ${options.auth.operatorTokenPresent ? 'present' : 'missing'} (${options.auth.operatorTokenPath})`
352
- : ' operatorTokens: unknown',
279
+ ? ` connected host token ${options.auth.operatorTokenPresent ? 'present' : 'missing'} (${options.auth.operatorTokenPath})`
280
+ : ' connected host token unknown',
353
281
  '',
354
- 'Connected GoodVibes API:',
282
+ 'Connected GoodVibes host:',
355
283
  ...(externalRuntime ? [
356
284
  ` baseUrl: ${externalRuntime.baseUrl}`,
357
285
  ` reachable: ${yesNo(externalRuntime.reachable)}${externalRuntime.statusCode === null ? '' : ` (HTTP ${externalRuntime.statusCode})`}`,
358
286
  ` sdk: ${externalRuntime.version} expected ${externalRuntime.expectedVersion}`,
359
287
  ` compatible: ${yesNo(externalRuntime.compatible)}`,
360
- ` operatorToken: ${externalRuntime.operatorToken.present ? 'present' : 'missing'} (${externalRuntime.operatorToken.path})`,
361
- ` Agent Knowledge: ${externalRuntime.agentKnowledge.ready ? 'ready' : `not ready (${externalRuntime.agentKnowledge.kind})`}`,
288
+ ` access token: ${externalRuntime.operatorToken.present ? 'present' : 'missing'} (${externalRuntime.operatorToken.path})`,
289
+ ` Agent Knowledge: ${externalRuntime.agentKnowledge.ready ? 'ready' : `not ready (${formatAgentKnowledgeFailureKind(externalRuntime.agentKnowledge.kind)})`}`,
362
290
  ...(externalRuntime.error ? [` error: ${externalRuntime.error}`] : []),
363
291
  ] : [
364
- ' live check: unavailable',
292
+ ' live check unavailable',
365
293
  ]),
366
294
  '',
367
- 'Connected GoodVibes Services:',
368
- ' Agent role: client/operator TUI only',
369
- ' service ownership: outside Agent',
370
- ' Agent starts services: no',
295
+ 'Agent role:',
296
+ ' product: interactive operator TUI',
297
+ ' host lifecycle: external',
298
+ ' starts or exposes host: no',
371
299
  ...(options.service ? [
372
- ` platform: ${options.service.managed.platform}`,
373
- ` installed: ${yesNo(options.service.managed.installed)}`,
374
- ` running: ${yesNo(options.service.managed.running)}`,
375
- ` definition: ${options.service.managed.path}`,
376
- ` log: ${options.service.log.path ?? 'n/a'} (${options.service.log.exists ? 'present' : 'missing'})`,
300
+ ` host log signal ${options.service.log.path ?? 'n/a'} (${options.service.log.exists ? 'present' : 'missing'})`,
377
301
  ] : []),
378
- 'Onboarding:',
379
- ` checked: ${marker?.exists ? 'yes' : 'no'}`,
380
- ` scope: ${marker?.scope ?? 'none'}`,
381
- ` updatedAt: ${marker?.payload ? new Date(marker.payload.updatedAt).toISOString() : 'n/a'}`,
302
+ 'Onboarding',
303
+ ` checked ${marker?.exists ? 'yes' : 'no'}`,
304
+ ` scope ${marker?.scope ?? 'none'}`,
305
+ ` updated ${marker?.payload ? new Date(marker.payload.updatedAt).toISOString() : 'n/a'}`,
382
306
  ];
383
307
 
384
308
  if (options.doctor) {
385
309
  lines.push(
386
310
  '',
387
- 'Connected-Service Config Signals:',
388
- ` host config present: ${yesNo(serviceEnabled)}`,
389
- ' lifecycle config: external to Agent',
390
- '',
391
- 'Endpoint Diagnostics:',
392
- bindLine('runtimeApi', controlPlaneEnabled, controlPlaneBinding),
393
- bindLine('incomingWebhook', listenerEnabled, httpListenerBinding),
394
- bindLine('browserCompanion', webEnabled, webBinding),
311
+ 'Readiness Checks:',
312
+ ' companion chat route',
313
+ ' isolated Agent Knowledge route',
314
+ ' approvals and automation status routes',
315
+ ' explicit build delegation route',
395
316
  );
396
- lines.push('', 'Warnings:');
317
+ lines.push('', 'Warnings');
397
318
  if (findings.length === 0) {
398
319
  lines.push(' none');
399
320
  } else {
@@ -415,11 +336,11 @@ export function renderOnboardingCliStatus(options: CliStatusOptions): string {
415
336
  const marker = options.onboardingMarkers?.effective;
416
337
  return [
417
338
  'GoodVibes Agent setup status',
418
- ` checked: ${marker?.exists ? 'yes' : 'no'}`,
419
- ` scope: ${marker?.scope ?? 'none'}`,
420
- ` source: ${marker?.payload?.source ?? 'n/a'}`,
421
- ` mode: ${marker?.payload?.mode ?? 'n/a'}`,
422
- ` updatedAt: ${marker?.payload ? new Date(marker.payload.updatedAt).toISOString() : 'n/a'}`,
423
- ` workingDir: ${options.workingDirectory}`,
339
+ ` checked ${marker?.exists ? 'yes' : 'no'}`,
340
+ ` scope ${marker?.scope ?? 'none'}`,
341
+ ` origin ${marker?.payload?.source ? formatAgentRecordSource(marker.payload.source) : 'n/a'}`,
342
+ ` mode ${marker?.payload?.mode ?? 'n/a'}`,
343
+ ` updated ${marker?.payload ? new Date(marker.payload.updatedAt).toISOString() : 'n/a'}`,
344
+ ` working directory ${options.workingDirectory}`,
424
345
  ].join('\n');
425
346
  }
@@ -0,0 +1,131 @@
1
+ import type { ConversationMessageSnapshot, TokenUsage } from './conversation.ts';
2
+ import type { ContentPart } from '@pellux/goodvibes-sdk/platform/providers';
3
+ import type { ToolCall } from '@pellux/goodvibes-sdk/platform/types';
4
+
5
+ function isRecord(value: unknown): value is Record<string, unknown> {
6
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
7
+ }
8
+
9
+ function readString(value: unknown): string | undefined {
10
+ return typeof value === 'string' ? value : undefined;
11
+ }
12
+
13
+ function readBoolean(value: unknown): boolean | undefined {
14
+ return typeof value === 'boolean' ? value : undefined;
15
+ }
16
+
17
+ function readContentPart(value: unknown): ContentPart | null {
18
+ if (!isRecord(value)) return null;
19
+ if (value.type === 'text' && typeof value.text === 'string') {
20
+ return { type: 'text', text: value.text };
21
+ }
22
+ if (value.type === 'image' && typeof value.data === 'string' && typeof value.mediaType === 'string') {
23
+ return { type: 'image', data: value.data, mediaType: value.mediaType };
24
+ }
25
+ return null;
26
+ }
27
+
28
+ function readContent(value: unknown): string | ContentPart[] | null {
29
+ if (typeof value === 'string') return value;
30
+ if (!Array.isArray(value)) return null;
31
+ const parts: ContentPart[] = [];
32
+ for (const entry of value) {
33
+ const part = readContentPart(entry);
34
+ if (!part) return null;
35
+ parts.push(part);
36
+ }
37
+ return parts;
38
+ }
39
+
40
+ function readTokenUsage(value: unknown): TokenUsage | undefined {
41
+ if (!isRecord(value) || typeof value.inputTokens !== 'number' || typeof value.outputTokens !== 'number') return undefined;
42
+ return {
43
+ inputTokens: value.inputTokens,
44
+ outputTokens: value.outputTokens,
45
+ ...(typeof value.cacheReadTokens === 'number' ? { cacheReadTokens: value.cacheReadTokens } : {}),
46
+ ...(typeof value.cacheWriteTokens === 'number' ? { cacheWriteTokens: value.cacheWriteTokens } : {}),
47
+ };
48
+ }
49
+
50
+ function readToolCalls(value: unknown): ToolCall[] | null {
51
+ if (!Array.isArray(value)) return null;
52
+ const calls: ToolCall[] = [];
53
+ for (const entry of value) {
54
+ if (!isRecord(entry) || typeof entry.id !== 'string' || typeof entry.name !== 'string' || !isRecord(entry.arguments)) return null;
55
+ calls.push({ id: entry.id, name: entry.name, arguments: entry.arguments });
56
+ }
57
+ return calls;
58
+ }
59
+
60
+ function hasOwn(record: Record<string, unknown>, key: string): boolean {
61
+ return Object.prototype.hasOwnProperty.call(record, key);
62
+ }
63
+
64
+ function readConversationMessageSnapshot(value: unknown): ConversationMessageSnapshot | null {
65
+ if (!isRecord(value)) return null;
66
+ if (value.role === 'user') {
67
+ const content = readContent(value.content);
68
+ if (content === null) return null;
69
+ const cancelled = hasOwn(value, 'cancelled') ? readBoolean(value.cancelled) : undefined;
70
+ if (hasOwn(value, 'cancelled') && cancelled === undefined) return null;
71
+ return {
72
+ role: 'user',
73
+ content,
74
+ ...(cancelled !== undefined ? { cancelled } : {}),
75
+ };
76
+ }
77
+ if (value.role === 'assistant') {
78
+ const content = readString(value.content);
79
+ if (content === undefined) return null;
80
+ const toolCalls = hasOwn(value, 'toolCalls') ? readToolCalls(value.toolCalls) : undefined;
81
+ if (toolCalls === null) return null;
82
+ const reasoningContent = hasOwn(value, 'reasoningContent') ? readString(value.reasoningContent) : undefined;
83
+ if (hasOwn(value, 'reasoningContent') && reasoningContent === undefined) return null;
84
+ const reasoningSummary = hasOwn(value, 'reasoningSummary') ? readString(value.reasoningSummary) : undefined;
85
+ if (hasOwn(value, 'reasoningSummary') && reasoningSummary === undefined) return null;
86
+ const usage = hasOwn(value, 'usage') ? readTokenUsage(value.usage) : undefined;
87
+ if (hasOwn(value, 'usage') && usage === undefined) return null;
88
+ const model = hasOwn(value, 'model') ? readString(value.model) : undefined;
89
+ if (hasOwn(value, 'model') && model === undefined) return null;
90
+ const provider = hasOwn(value, 'provider') ? readString(value.provider) : undefined;
91
+ if (hasOwn(value, 'provider') && provider === undefined) return null;
92
+ return {
93
+ role: 'assistant',
94
+ content,
95
+ ...(toolCalls !== undefined ? { toolCalls } : {}),
96
+ ...(reasoningContent !== undefined ? { reasoningContent } : {}),
97
+ ...(reasoningSummary !== undefined ? { reasoningSummary } : {}),
98
+ ...(usage !== undefined ? { usage } : {}),
99
+ ...(model !== undefined ? { model } : {}),
100
+ ...(provider !== undefined ? { provider } : {}),
101
+ };
102
+ }
103
+ if (value.role === 'system' && typeof value.content === 'string') {
104
+ return { role: 'system', content: value.content };
105
+ }
106
+ if (value.role === 'tool' && typeof value.callId === 'string' && typeof value.content === 'string') {
107
+ const toolName = hasOwn(value, 'toolName') ? readString(value.toolName) : undefined;
108
+ if (hasOwn(value, 'toolName') && toolName === undefined) return null;
109
+ return {
110
+ role: 'tool',
111
+ callId: value.callId,
112
+ content: value.content,
113
+ ...(toolName !== undefined ? { toolName } : {}),
114
+ };
115
+ }
116
+ return null;
117
+ }
118
+
119
+ export function readConversationMessageSnapshots(messages: readonly object[]): ConversationMessageSnapshot[] {
120
+ const snapshots: ConversationMessageSnapshot[] = [];
121
+ for (const [index, message] of messages.entries()) {
122
+ const snapshot = readConversationMessageSnapshot(message);
123
+ if (!snapshot) throw new Error(`Invalid saved conversation message at index ${index}.`);
124
+ snapshots.push(snapshot);
125
+ }
126
+ return snapshots;
127
+ }
128
+
129
+ export function conversationMessagesAsSessionRecords(messages: readonly ConversationMessageSnapshot[]): Array<Record<string, unknown>> {
130
+ return messages.map((message) => ({ ...message }));
131
+ }
@@ -0,0 +1,149 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import type { AgentWorkspaceAccessCommandEditorKind } from './agent-workspace-access-command-editors.ts';
3
+ import { isAgentWorkspaceAccessCommandEditorKind } from './agent-workspace-access-command-editors.ts';
4
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
5
+
6
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
7
+
8
+ export type AgentWorkspaceAccessCommandEditorSubmission =
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 isAgentWorkspaceAccessCommandSubmissionKind(kind: string): kind is AgentWorkspaceAccessCommandEditorKind {
23
+ return isAgentWorkspaceAccessCommandEditorKind(kind as AgentWorkspaceAccessCommandEditorKind);
24
+ }
25
+
26
+ function isAffirmative(value: string): boolean {
27
+ return /^(y|yes|true)$/i.test(value.trim());
28
+ }
29
+
30
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceAccessCommandEditorSubmission {
31
+ return {
32
+ kind: 'editor',
33
+ editor: { ...editor, message },
34
+ status: message,
35
+ };
36
+ }
37
+
38
+ function dispatch(command: string, title: string, detail: string, safety: AgentWorkspaceActionResult['safety']): AgentWorkspaceAccessCommandEditorSubmission {
39
+ return {
40
+ kind: 'dispatch',
41
+ command,
42
+ status: `${title}.`,
43
+ actionResult: {
44
+ kind: 'dispatched',
45
+ title,
46
+ detail,
47
+ command,
48
+ safety,
49
+ },
50
+ };
51
+ }
52
+
53
+ export function buildAgentWorkspaceAccessCommandEditorSubmission(
54
+ editor: AgentWorkspaceLocalEditor,
55
+ readField: AgentWorkspaceFieldReader,
56
+ ): AgentWorkspaceAccessCommandEditorSubmission {
57
+ if (editor.kind === 'auth-show') {
58
+ return dispatch(
59
+ `/auth show ${quoteSlashCommandArg(readField('provider'))}`,
60
+ 'Opening provider auth inspection',
61
+ 'The workspace handed a read-only provider auth inspection command to the shell-owned command router.',
62
+ 'read-only',
63
+ );
64
+ }
65
+ if (editor.kind === 'auth-repair') {
66
+ return dispatch(
67
+ `/auth repair ${quoteSlashCommandArg(readField('provider'))}`,
68
+ 'Opening provider auth repair review',
69
+ 'The workspace handed a read-only provider auth repair review command to the shell-owned command router.',
70
+ 'read-only',
71
+ );
72
+ }
73
+ if (editor.kind === 'auth-bundle-export') {
74
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Auth review bundle export not confirmed. Type yes, then press Enter.');
75
+ return dispatch(
76
+ `/auth bundle export ${quoteSlashCommandArg(readField('path'))} --yes`,
77
+ 'Opening auth review bundle export',
78
+ 'The workspace handed a confirmed auth review bundle export command to the shell-owned command router.',
79
+ 'safe',
80
+ );
81
+ }
82
+ if (editor.kind === 'auth-bundle-inspect') {
83
+ return dispatch(
84
+ `/auth bundle inspect ${quoteSlashCommandArg(readField('path'))}`,
85
+ 'Opening auth review bundle inspection',
86
+ 'The workspace handed a read-only auth review bundle inspect command to the shell-owned command router.',
87
+ 'read-only',
88
+ );
89
+ }
90
+ if (editor.kind === 'trust-bundle-export') {
91
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Trust bundle export not confirmed. Type yes, then press Enter.');
92
+ return dispatch(
93
+ `/trust bundle export ${quoteSlashCommandArg(readField('path'))} --yes`,
94
+ 'Opening trust bundle export',
95
+ 'The workspace handed a confirmed trust bundle export command to the shell-owned command router.',
96
+ 'safe',
97
+ );
98
+ }
99
+ if (editor.kind === 'trust-bundle-inspect') {
100
+ return dispatch(
101
+ `/trust bundle inspect ${quoteSlashCommandArg(readField('path'))}`,
102
+ 'Opening trust bundle inspection',
103
+ 'The workspace handed a read-only trust bundle inspect command to the shell-owned command router.',
104
+ 'read-only',
105
+ );
106
+ }
107
+ if (editor.kind === 'subscription-bundle-export') {
108
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Subscription bundle export not confirmed. Type yes, then press Enter.');
109
+ return dispatch(
110
+ `/subscription bundle export ${quoteSlashCommandArg(readField('path'))} --yes`,
111
+ 'Opening subscription bundle export',
112
+ 'The workspace handed a confirmed subscription bundle export command to the shell-owned command router.',
113
+ 'safe',
114
+ );
115
+ }
116
+ if (editor.kind === 'subscription-bundle-inspect') {
117
+ return dispatch(
118
+ `/subscription bundle inspect ${quoteSlashCommandArg(readField('path'))}`,
119
+ 'Opening subscription bundle inspection',
120
+ 'The workspace handed a read-only subscription bundle inspect command to the shell-owned command router.',
121
+ 'read-only',
122
+ );
123
+ }
124
+ if (editor.kind === 'voice-enable' || editor.kind === 'voice-disable') {
125
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, `Voice interaction ${editor.kind === 'voice-enable' ? 'enable' : 'disable'} not confirmed. Type yes, then press Enter.`);
126
+ const mode = editor.kind === 'voice-enable' ? 'enable' : 'disable';
127
+ return dispatch(
128
+ `/voice ${mode} --yes`,
129
+ `Opening voice interaction ${mode}`,
130
+ `The workspace handed a confirmed voice ${mode} command to the shell-owned command router.`,
131
+ 'safe',
132
+ );
133
+ }
134
+ if (editor.kind === 'voice-bundle-export') {
135
+ if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Voice bundle export not confirmed. Type yes, then press Enter.');
136
+ return dispatch(
137
+ `/voice bundle export ${quoteSlashCommandArg(readField('path'))} --yes`,
138
+ 'Opening voice bundle export',
139
+ 'The workspace handed a confirmed voice bundle export command to the shell-owned command router.',
140
+ 'safe',
141
+ );
142
+ }
143
+ return dispatch(
144
+ `/voice bundle inspect ${quoteSlashCommandArg(readField('path'))}`,
145
+ 'Opening voice bundle inspection',
146
+ 'The workspace handed a read-only voice bundle inspect command to the shell-owned command router.',
147
+ 'read-only',
148
+ );
149
+ }