@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
@@ -7,10 +7,11 @@
7
7
 
8
8
  import type { Line } from '../types/grid.ts';
9
9
  import type { SettingsModal, SettingEntry, FlagEntry, McpEntry, SubscriptionEntry, SettingsCategory } from '../input/settings-modal.ts';
10
- import { isExternalDaemonOwnedSettingKey, SETTINGS_CATEGORIES, SETTINGS_CATEGORY_GROUPS } from '../input/settings-modal.ts';
10
+ import { isExternalHostOwnedSettingKey, SETTINGS_CATEGORIES, SETTINGS_CATEGORY_GROUPS } from '../input/settings-modal.ts';
11
11
  import { getDisplayWidth, wrapText } from '../utils/terminal-width.ts';
12
12
  import { CATEGORY_LABELS, describeUiRouting, formatValue, getSettingLabel, inferSubscriptionRouteReason, valueColor } from './settings-modal-helpers.ts';
13
13
  import { isSecretConfigKey } from '../config/secret-config.ts';
14
+ import { formatProviderAuthRouteId } from '../provider-auth-route-display.ts';
14
15
  import { GLYPHS } from './ui-primitives.ts';
15
16
  import {
16
17
  clamp,
@@ -30,34 +31,23 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
30
31
  behavior: 'Day-to-day shell behavior: approval posture, compaction, history, guidance, notifications, stale-context warnings, return context, and Human-in-the-Loop mode.',
31
32
  storage: 'Local storage posture, including secret storage policy and maximum artifact size for Agent Knowledge, artifacts, and document ingestion.',
32
33
  permissions: 'Permission mode and tool-class policy. These settings decide whether the shell prompts before read/write/exec/network/agent actions.',
33
- orchestration: 'Agent orchestration limits and recursion controls.',
34
- wrfc: 'WRFC is external to normal Agent operation. Review these compatibility values only for explicit GoodVibes TUI build delegation.',
35
34
  helper: 'Helper model defaults used by helper subsystems when they do not use the main chat route.',
36
35
  tts: 'Text-to-speech provider, voice, and optional spoken-turn LLM overrides.',
37
- service: 'Connected-service installation posture. Agent shows these compatibility keys for inspection only and does not install, start, stop, restart, or autostart anything.',
38
- controlPlane: 'Connected-service API settings. Agent uses these settings for access and does not mutate bind posture.',
39
- httpListener: 'Inbound event endpoint settings owned by connected GoodVibes services. Agent inspects readiness and does not expose endpoints.',
40
- web: 'External browser companion settings. Agent does not own browser hosting or network bind lifecycle.',
41
- batch: 'Batch execution settings reported from connected GoodVibes services. Agent does not own remote queue provisioning.',
42
36
  automation: 'Scheduled and automated run settings, concurrency, timeout, catch-up, cooldown, and retention behavior.',
43
- watchers: 'File/process watcher heartbeat, polling, and recovery-window behavior.',
44
- runtime: 'Connected-service guardrails such as companion chat limiter and event bus listener caps.',
45
37
  telemetry: 'Telemetry payload policy.',
46
38
  cache: 'Provider and model cache behavior, TTL, and hit-rate monitoring.',
47
39
  mcp: 'MCP server trust and scope review. Trust changes can expose local files, tools, databases, browsers, or remote automation depending on the server.',
48
40
  surfaces: 'Messaging and notification channel accounts such as Slack, Discord, ntfy, Telegram, chat bridges, and delivery providers.',
49
- release: 'Release-channel preference.',
50
- danger: 'High-impact service switches. Agent renders service-owned switches read-only; change them outside Agent.',
41
+ release: 'Update-channel preference.',
51
42
  tools: 'Tool LLM and helper model routing. Empty provider/model values inherit the active chat route unless a specific helper/tool route is set.',
52
- flags: 'Feature flags are SDK gates. They are separate from normal config keys because they enable or disable staged behavior.',
53
- network: 'Read-only view of connected GoodVibes API, inbound-event, and browser companion bind posture plus editable Agent network settings.',
43
+ flags: 'Feature controls for optional behavior that can be enabled or disabled separately from normal configuration.',
54
44
  };
55
45
 
56
46
  const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
57
47
  'behavior.hitlMode': {
58
48
  quiet: 'Minimize operational interruptions and surface fewer Human-in-the-Loop prompts.',
59
49
  balanced: 'Show important Human-in-the-Loop prompts without turning routine work into noise.',
60
- operator: 'Surface more operational detail for users actively supervising agents, tools, services, and automation.',
50
+ operator: 'Surface more operational detail for users actively supervising agents, tools, connected-host posture, and automation.',
61
51
  },
62
52
  'behavior.guidanceMode': {
63
53
  off: 'Do not add extra guidance beyond direct command output.',
@@ -74,26 +64,6 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
74
64
  require_secure: 'Require secure secret storage and reject plaintext fallback.',
75
65
  plaintext_allowed: 'Allow plaintext fallback when secure storage is unavailable.',
76
66
  },
77
- 'batch.mode': {
78
- off: 'Keep runtime work on the immediate local path.',
79
- explicit: 'Use batch only when callers explicitly request batch execution.',
80
- 'eligible-by-default': 'Allow eligible runtime work to use the batch path unless callers opt out.',
81
- },
82
- 'controlPlane.hostMode': {
83
- localhost: 'Bind only to this computer.',
84
- network: 'Bind for LAN access using the default network host.',
85
- custom: 'Use the explicit host value in the related host setting.',
86
- },
87
- 'httpListener.hostMode': {
88
- localhost: 'Bind only to this computer.',
89
- network: 'Bind for LAN event delivery using the default network host.',
90
- custom: 'Use the explicit host value in the related host setting.',
91
- },
92
- 'web.hostMode': {
93
- localhost: 'Serve the browser UI only on this computer.',
94
- network: 'Serve the browser UI on the LAN.',
95
- custom: 'Use the explicit host value in the related host setting.',
96
- },
97
67
  'ui.systemMessages': {
98
68
  panel: 'Show system messages in panels only.',
99
69
  conversation: 'Show system messages inline in the transcript.',
@@ -104,11 +74,6 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
104
74
  conversation: 'Show operational messages inline in the transcript.',
105
75
  both: 'Show operational messages in both panels and the transcript.',
106
76
  },
107
- 'ui.wrfcMessages': {
108
- panel: 'Show explicit delegated-build WRFC messages in panels only.',
109
- conversation: 'Show explicit delegated-build WRFC messages inline in the transcript.',
110
- both: 'Show explicit delegated-build WRFC messages in both panels and the transcript.',
111
- },
112
77
  'surfaces.telegram.mode': {
113
78
  webhook: 'Receive Telegram updates through externally hosted delivery.',
114
79
  polling: 'Poll Telegram for updates from the configured account.',
@@ -148,14 +113,13 @@ function buildSettingContext(modal: SettingsModal, entry: SettingEntry): string[
148
113
  ];
149
114
 
150
115
  if (entry.locked) lines.push(`Locked: ${entry.lockReason ?? 'This setting is locked by a higher-priority layer.'}`);
151
- if (entry.conflict) lines.push(`Conflict: inspect with /settings and resolve service-owned sync state in the owning host.`);
116
+ if (entry.conflict) lines.push(`Conflict: inspect with /settings and resolve host-owned sync state in the owning host.`);
152
117
 
153
118
  lines.push('', entry.setting.description);
154
119
 
155
120
  if (
156
121
  entry.setting.key === 'ui.systemMessages'
157
122
  || entry.setting.key === 'ui.operationalMessages'
158
- || entry.setting.key === 'ui.wrfcMessages'
159
123
  ) {
160
124
  lines.push(`Routing meaning: ${describeUiRouting(String(entry.currentValue))}.`);
161
125
  }
@@ -194,8 +158,12 @@ function buildSettingContext(modal: SettingsModal, entry: SettingEntry): string[
194
158
  return lines;
195
159
  }
196
160
 
161
+ function formatSubscriptionRoute(route: SubscriptionEntry['activeRoute'] | SubscriptionEntry['preferredRoute']): string {
162
+ return route ? formatProviderAuthRouteId(route) : 'n/a';
163
+ }
164
+
197
165
  function buildFlagContext(entry: FlagEntry | null): string[] {
198
- if (!entry) return ['Feature flags', 'No feature flag is selected.'];
166
+ if (!entry) return ['Feature Controls', 'No feature control is selected.'];
199
167
  return [
200
168
  entry.flag.name,
201
169
  `ID: ${entry.flag.id}`,
@@ -209,7 +177,7 @@ function buildFlagContext(entry: FlagEntry | null): string[] {
209
177
  '',
210
178
  entry.flag.runtimeToggleable
211
179
  ? 'Impact: changes apply immediately and are also persisted as an override when they differ from the default.'
212
- : 'Impact: this flag is persisted as an override and requires restart before startup-only code sees the new state.',
180
+ : 'Impact: this override is saved for the next Agent launch or owning-host reload, depending on who owns the flag.',
213
181
  ];
214
182
  }
215
183
 
@@ -248,14 +216,14 @@ function buildSubscriptionContext(modal: SettingsModal, entry: SubscriptionEntry
248
216
  ? modal.subscriptionLogoutConfirmationTarget === entry.provider
249
217
  ? `Press Enter again to sign out ${entry.provider}. Move selection or close config to cancel.`
250
218
  : 'Press Enter to review sign-out for this provider session.'
251
- : `Use /subscription login ${entry.provider} start to begin OAuth sign-in for this provider.`;
219
+ : `Open Agent Workspace -> Setup and choose Start subscription login for ${entry.provider}.`;
252
220
  return [
253
221
  entry.provider,
254
222
  `State: ${entry.state}`,
255
223
  ...(routeReason ? [routeReason] : []),
256
224
  logout,
257
- `Active route: ${entry.activeRoute ?? 'n/a'}`,
258
- `Preferred route: ${entry.preferredRoute ?? 'n/a'}`,
225
+ `Active route: ${formatSubscriptionRoute(entry.activeRoute)}`,
226
+ `Preferred route: ${formatSubscriptionRoute(entry.preferredRoute)}`,
259
227
  `OAuth configured: ${entry.oauthConfigured ? 'yes' : 'no'}`,
260
228
  `Freshness: ${entry.authFreshness ?? 'n/a'}`,
261
229
  `Expires: ${expires}`,
@@ -390,10 +358,10 @@ function renderFlagRows(modal: SettingsModal, width: number, height: number): st
390
358
  const nameWidth = clamp(Math.floor(width * 0.40), 24, 58);
391
359
  const stateWidth = 10;
392
360
  const tierWidth = 6;
393
- const runtimeWidth = 9;
361
+ const runtimeWidth = 10;
394
362
  const defaultWidth = 9;
395
363
  const idWidth = Math.max(12, width - nameWidth - stateWidth - tierWidth - runtimeWidth - defaultWidth - 14);
396
- rows.push(` ${padDisplay('Feature Flag', nameWidth)} ${padDisplay('State', stateWidth)} ${padDisplay('Tier', tierWidth)} ${padDisplay('Runtime', runtimeWidth)} ${padDisplay('Default', defaultWidth)} ${padDisplay('ID', idWidth)}`);
364
+ rows.push(` ${padDisplay('Feature Flag', nameWidth)} ${padDisplay('State', stateWidth)} ${padDisplay('Tier', tierWidth)} ${padDisplay('Applies', runtimeWidth)} ${padDisplay('Default', defaultWidth)} ${padDisplay('ID', idWidth)}`);
397
365
  const visibleCount = Math.max(1, height - 2);
398
366
  const window = stableWindow(items.length, selectedIndex, visibleCount);
399
367
  if (window.start > 0) rows.push(`${GLYPHS.navigation.moreAbove} ${window.start} more flag(s) above`);
@@ -401,7 +369,7 @@ function renderFlagRows(modal: SettingsModal, width: number, height: number): st
401
369
  const entry = items[index]!;
402
370
  const selected = index === selectedIndex;
403
371
  const marker = selected ? (modal.focusPane === 'settings' ? GLYPHS.navigation.selected : '•') : ' ';
404
- rows.push(`${marker} ${padDisplay(entry.flag.name, nameWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(String(entry.flag.tier), tierWidth)} ${padDisplay(entry.flag.runtimeToggleable ? 'yes' : 'restart', runtimeWidth)} ${padDisplay(entry.flag.defaultState, defaultWidth)} ${padDisplay(entry.flag.id, idWidth)}`);
372
+ rows.push(`${marker} ${padDisplay(entry.flag.name, nameWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(String(entry.flag.tier), tierWidth)} ${padDisplay(entry.flag.runtimeToggleable ? 'now' : 'next run', runtimeWidth)} ${padDisplay(entry.flag.defaultState, defaultWidth)} ${padDisplay(entry.flag.id, idWidth)}`);
405
373
  }
406
374
  if (window.end < items.length) rows.push(`${GLYPHS.navigation.moreBelow} ${items.length - window.end} more flag(s) below`);
407
375
  return rows.slice(0, height);
@@ -450,7 +418,7 @@ function renderSubscriptionRows(modal: SettingsModal, width: number, height: num
450
418
  const entry = items[index]!;
451
419
  const selected = index === selectedIndex;
452
420
  const marker = selected ? (modal.focusPane === 'settings' ? GLYPHS.navigation.selected : '•') : ' ';
453
- rows.push(`${marker} ${padDisplay(entry.provider, providerWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(entry.activeRoute ?? 'n/a', routeWidth)} ${padDisplay(entry.authFreshness ?? 'n/a', freshnessWidth)} ${padDisplay(entry.oauthConfigured ? 'yes' : 'no', oauthWidth)} ${padDisplay(inferSubscriptionRouteReason(entry) ?? '', noteWidth)}`);
421
+ rows.push(`${marker} ${padDisplay(entry.provider, providerWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(formatSubscriptionRoute(entry.activeRoute), routeWidth)} ${padDisplay(entry.authFreshness ?? 'n/a', freshnessWidth)} ${padDisplay(entry.oauthConfigured ? 'yes' : 'no', oauthWidth)} ${padDisplay(inferSubscriptionRouteReason(entry) ?? '', noteWidth)}`);
454
422
  }
455
423
  if (window.end < items.length) rows.push(`${GLYPHS.navigation.moreBelow} ${items.length - window.end} more subscription provider(s) below`);
456
424
  return rows.slice(0, height);
@@ -464,7 +432,6 @@ function renderControlRows(modal: SettingsModal, width: number, height: number):
464
432
  }
465
433
 
466
434
  function rowColorForSetting(modal: SettingsModal, rowText: string): string {
467
- if (modal.currentCategory === 'danger') return PALETTE.bad;
468
435
  if (rowText.startsWith(GLYPHS.navigation.selected)) return PALETTE.text;
469
436
  const selected = modal.getSelected();
470
437
  if (!selected) return PALETTE.text;
@@ -478,19 +445,85 @@ function footerText(modal: SettingsModal): string {
478
445
  if (modal.currentCategory === 'mcp') return 'Focus settings · Up/Down server · Left categories · Tab pane · Enter edit trust · Esc close';
479
446
  if (modal.currentCategory === 'flags') return 'Focus feature flags · Up/Down flag · Left categories · Tab pane · Enter/Space toggle · Esc close';
480
447
  const selected = modal.getSelected();
481
- if (selected && isExternalDaemonOwnedSettingKey(selected.setting.key)) {
482
- return 'Read-only connected-service setting · Change from GoodVibes TUI or the owning host · Esc close';
448
+ if (selected && isExternalHostOwnedSettingKey(selected.setting.key)) {
449
+ return 'Read-only connected-host setting · Change from GoodVibes TUI or the owning host · Esc close';
483
450
  }
484
451
  return 'Focus settings · Up/Down setting · Left categories · Tab pane · Enter/Space edit/toggle · R reset · Esc close';
485
452
  }
486
453
 
454
+ export function renderSettingsModalPackageText(): string {
455
+ const lines: string[] = [
456
+ 'Configuration Workspace / Settings',
457
+ 'Categories',
458
+ 'Setting',
459
+ 'Value',
460
+ 'Type',
461
+ 'Source',
462
+ 'Default',
463
+ 'Feature Flag',
464
+ 'State',
465
+ 'Tier',
466
+ 'Applies',
467
+ 'Server',
468
+ 'Trust',
469
+ 'Status',
470
+ 'Scope',
471
+ 'Provider',
472
+ 'Route',
473
+ 'Freshness',
474
+ 'OAuth',
475
+ 'Note',
476
+ 'No settings in this category.',
477
+ 'No feature flags registered.',
478
+ 'No MCP servers registered.',
479
+ 'No provider subscriptions available or configured.',
480
+ 'No setting is selected in this category.',
481
+ 'No feature control is selected.',
482
+ 'No MCP server is selected.',
483
+ 'No subscription provider is selected.',
484
+ 'Trust meanings:',
485
+ 'constrained: keep MCP activity inside declared paths/hosts and prompt on risk.',
486
+ 'ask-on-risk: allow routine MCP operations but ask before risky behavior.',
487
+ 'allow-all: allow unrestricted MCP operations for this server after explicit confirmation.',
488
+ 'blocked: prevent this MCP server from being used.',
489
+ 'Possible values:',
490
+ 'true: enabled or allowed for this setting.',
491
+ 'false: disabled or not allowed for this setting.',
492
+ 'Secret handling: raw values entered here are stored through the secret manager and the config receives a goodvibes:// secret reference. Empty input clears the config value.',
493
+ 'Editing: Enter opens inline edit, then type the value and press Enter to save. Arrow keys only navigate.',
494
+ 'Editing: Enter opens inline edit. Delete the current text to save an empty value when that is valid for the setting.',
495
+ 'Enter Confirm edit · Esc Cancel edit · text keys edit the selected field',
496
+ 'Focus categories · Up/Down choose · Right/Enter settings · Tab pane · Esc close',
497
+ 'Focus settings · Up/Down provider · Left categories · Tab pane · Enter review/sign out · Esc close',
498
+ 'Focus settings · Up/Down server · Left categories · Tab pane · Enter edit trust · Esc close',
499
+ 'Focus feature flags · Up/Down flag · Left categories · Tab pane · Enter/Space toggle · Esc close',
500
+ 'Read-only connected-host setting · Change from GoodVibes TUI or the owning host · Esc close',
501
+ 'Focus settings · Up/Down setting · Left categories · Tab pane · Enter/Space edit/toggle · R reset · Esc close',
502
+ ];
503
+
504
+ for (const group of SETTINGS_CATEGORY_GROUPS) {
505
+ lines.push(group.label);
506
+ for (const category of group.categories) {
507
+ lines.push(category, CATEGORY_LABELS[category], CATEGORY_INFO[category]);
508
+ }
509
+ }
510
+
511
+ for (const [key, values] of Object.entries(ENUM_VALUE_DESCRIPTIONS)) {
512
+ lines.push(key);
513
+ for (const [value, description] of Object.entries(values)) {
514
+ lines.push(value, description);
515
+ }
516
+ }
517
+
518
+ return lines.join('\n');
519
+ }
520
+
487
521
  export function renderSettingsModal(
488
522
  modal: SettingsModal,
489
523
  width: number,
490
524
  viewportHeight = 24,
491
525
  ): Line[] {
492
526
  const notices = [
493
- ...(modal.lastSaveTriggeredRestart ? [`Owning host must restart ${modal.lastSaveTriggeredRestart}`] : []),
494
527
  ...(modal.lastSettingEffectMessage ? [modal.lastSettingEffectMessage] : []),
495
528
  ];
496
529
  const metrics = getFullscreenWorkspaceMetrics({ width, height: viewportHeight });
@@ -20,7 +20,7 @@ export function classifySystemMessage(content: string): SystemMessageType {
20
20
  if (/FAILED|cascade abort/i.test(content)) return 'error';
21
21
  // Review failed to reach threshold → warning (yellow, retry in progress)
22
22
  if (/spawning a fix agent/i.test(content)) return 'warning';
23
- // All other WRFC messages (started, passed, auto-committed, gate passed, review ok) → info
23
+ // All other explicit delegated review/build messages classify as info.
24
24
  return 'info';
25
25
  }
26
26
 
@@ -7,6 +7,16 @@ import { stripDangerousAnsi } from './ansi-sanitize.ts';
7
7
  const TOOL_NAME_MIN_WIDTH = 8;
8
8
  const TOOL_NAME_MAX_WIDTH = 20;
9
9
 
10
+ function isRecord(value: unknown): value is Record<string, unknown> {
11
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
12
+ }
13
+
14
+ function readStringField(value: unknown, field: string): string | null {
15
+ if (!isRecord(value)) return null;
16
+ const fieldValue = value[field];
17
+ return typeof fieldValue === 'string' ? fieldValue : null;
18
+ }
19
+
10
20
  function writeStyledText(
11
21
  line: Line,
12
22
  startCol: number,
@@ -100,32 +110,31 @@ function extractKeyArg(toolCall: ToolCall): string {
100
110
  if (Array.isArray(args.files) && args.files.length > 0) {
101
111
  const first = args.files[0];
102
112
  if (typeof first === 'string') return first;
103
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).path === 'string')
104
- return (first as Record<string, unknown>).path as string;
113
+ const path = readStringField(first, 'path');
114
+ if (path) return path;
105
115
  }
106
116
  // Exec
107
117
  if (typeof args.command === 'string') return args.command;
108
118
  if (typeof args.cmd === 'string') return args.cmd;
109
119
  if (Array.isArray(args.commands) && args.commands.length > 0) {
110
120
  const first = args.commands[0];
111
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).cmd === 'string')
112
- return (first as Record<string, unknown>).cmd as string;
121
+ const cmd = readStringField(first, 'cmd');
122
+ if (cmd) return cmd;
113
123
  }
114
124
  // Find/grep
115
125
  if (typeof args.pattern === 'string') return args.pattern;
116
126
  if (Array.isArray(args.queries) && args.queries.length > 0) {
117
127
  const first = args.queries[0];
118
- if (first && typeof first === 'object') {
119
- const firstRecord = first as Record<string, unknown>;
120
- if (typeof firstRecord.query === 'string') return firstRecord.query;
121
- if (typeof firstRecord.pattern === 'string') return firstRecord.pattern;
122
- }
128
+ const query = readStringField(first, 'query');
129
+ if (query) return query;
130
+ const pattern = readStringField(first, 'pattern');
131
+ if (pattern) return pattern;
123
132
  }
124
133
  // Fetch
125
134
  if (Array.isArray(args.urls) && args.urls.length > 0) {
126
135
  const first = args.urls[0];
127
- if (first && typeof first === 'object' && typeof (first as Record<string, unknown>).url === 'string')
128
- return (first as Record<string, unknown>).url as string;
136
+ const url = readStringField(first, 'url');
137
+ if (url) return url;
129
138
  }
130
139
  // Agent
131
140
  if (typeof args.task === 'string') return args.task.slice(0, 40);
@@ -0,0 +1,129 @@
1
+ import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
2
+ import type { ConversationFollowUpItem } from '@pellux/goodvibes-sdk/platform/core';
3
+ import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
4
+ import type {
5
+ AgentEvent,
6
+ ProviderEvent,
7
+ RuntimeEventBus,
8
+ } from '@/runtime/index.ts';
9
+ import type { createDomainDispatch } from './store/index.ts';
10
+
11
+ const AGENT_STATUS_INTERVAL_MS = 30_000;
12
+
13
+ export interface AgentRuntimeMessageRouter {
14
+ low(message: string): void;
15
+ high(message: string): void;
16
+ }
17
+
18
+ export interface AgentRuntimeEventBridgeOptions {
19
+ readonly runtimeBus: RuntimeEventBus;
20
+ readonly domainDispatch: ReturnType<typeof createDomainDispatch>;
21
+ readonly getSystemMessageRouter: () => AgentRuntimeMessageRouter | null;
22
+ readonly queueConversationFollowUp?: (item: ConversationFollowUpItem) => void;
23
+ readonly requestRender: () => void;
24
+ readonly configManager: ConfigManager;
25
+ readonly agentManager: AgentManager;
26
+ }
27
+
28
+ function withRouter(
29
+ getSystemMessageRouter: () => AgentRuntimeMessageRouter | null,
30
+ action: (router: AgentRuntimeMessageRouter) => void,
31
+ ): void {
32
+ const router = getSystemMessageRouter();
33
+ if (router) action(router);
34
+ }
35
+
36
+ function formatAgentTask(task: string): string {
37
+ return task.length > 50 ? `${task.slice(0, 50)}...` : task;
38
+ }
39
+
40
+ export function registerAgentRuntimeEvents(options: AgentRuntimeEventBridgeOptions): {
41
+ unsubs: Array<() => void>;
42
+ agentStatusIntervalRef: { value: ReturnType<typeof setInterval> | null };
43
+ } {
44
+ const {
45
+ runtimeBus,
46
+ domainDispatch,
47
+ getSystemMessageRouter,
48
+ queueConversationFollowUp,
49
+ requestRender,
50
+ agentManager,
51
+ } = options;
52
+ const unsubs: Array<() => void> = [];
53
+
54
+ unsubs.push(runtimeBus.onDomain('turn', (env) => {
55
+ domainDispatch.dispatchTurnEvent(env.payload);
56
+ }));
57
+ unsubs.push(runtimeBus.onDomain('agents', (env) => {
58
+ domainDispatch.dispatchAgentEvent(env.payload);
59
+ }));
60
+ unsubs.push(runtimeBus.onDomain('orchestration', (env) => {
61
+ domainDispatch.dispatchOrchestrationEvent(env.payload);
62
+ }));
63
+ unsubs.push(runtimeBus.onDomain('communication', (env) => {
64
+ domainDispatch.dispatchCommunicationEvent(env.payload);
65
+ }));
66
+ unsubs.push(runtimeBus.onDomain('compaction', (env) => {
67
+ domainDispatch.dispatchCompactionEvent(env.payload);
68
+ }));
69
+ unsubs.push(runtimeBus.onDomain('transport', (env) => {
70
+ domainDispatch.dispatchTransportEvent(env.payload);
71
+ }));
72
+
73
+ unsubs.push(runtimeBus.on<Extract<ProviderEvent, { type: 'MODEL_FALLBACK' }>>('MODEL_FALLBACK', ({ payload }) => {
74
+ withRouter(getSystemMessageRouter, (router) => {
75
+ router.high(`[Model] ${payload.from} exhausted across all providers. Automatically falling back to ${payload.to} via ${payload.provider}.`);
76
+ });
77
+ requestRender();
78
+ }));
79
+ unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_STREAM_DELTA' }>>('AGENT_STREAM_DELTA', () => {
80
+ requestRender();
81
+ }));
82
+ unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_PROGRESS' }>>('AGENT_PROGRESS', () => {
83
+ requestRender();
84
+ }));
85
+ unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_COMPLETED' }>>('AGENT_COMPLETED', ({ payload }) => {
86
+ const record = agentManager.getStatus(payload.agentId);
87
+ if (record) {
88
+ const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
89
+ const taskSnippet = formatAgentTask(record.task);
90
+ withRouter(getSystemMessageRouter, (router) => {
91
+ router.low(`[Delegated task] ${record.template} ${payload.agentId.slice(-8)} completed in ${durationSeconds}s "${taskSnippet}"`);
92
+ });
93
+ queueConversationFollowUp?.({
94
+ key: `agent:${payload.agentId}:completed`,
95
+ summary: `${record.template} delegated task ${payload.agentId.slice(-8)} completed "${taskSnippet}" in ${durationSeconds}s after ${record.toolCallCount} tool calls.`,
96
+ });
97
+ }
98
+ requestRender();
99
+ }));
100
+ unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_FAILED' }>>('AGENT_FAILED', ({ payload }) => {
101
+ const record = agentManager.getStatus(payload.agentId);
102
+ if (record && record.status !== 'cancelled') {
103
+ const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
104
+ const taskSnippet = formatAgentTask(record.task);
105
+ withRouter(getSystemMessageRouter, (router) => {
106
+ router.low(`[Delegated task] ${record.template} ${payload.agentId.slice(-8)} failed in ${durationSeconds}s ${payload.error.slice(0, 80)}`);
107
+ });
108
+ queueConversationFollowUp?.({
109
+ key: `agent:${payload.agentId}:failed`,
110
+ summary: `${record.template} delegated task ${payload.agentId.slice(-8)} failed while working on "${taskSnippet}" ${payload.error.slice(0, 120)}`,
111
+ });
112
+ }
113
+ requestRender();
114
+ }));
115
+
116
+ const agentStatusIntervalRef = { value: null as ReturnType<typeof setInterval> | null };
117
+ agentStatusIntervalRef.value = setInterval(() => {
118
+ const running = agentManager.list().filter((agent) => agent.status === 'running');
119
+ if (running.length === 0) return;
120
+ const lines = running.map((agent) => ` ${agent.id.slice(-8)} ${agent.progress ?? agent.status}`);
121
+ withRouter(getSystemMessageRouter, (router) => {
122
+ router.low(`[Delegated task] ${running.length} running\n${lines.join('\n')}`);
123
+ });
124
+ requestRender();
125
+ }, AGENT_STATUS_INTERVAL_MS);
126
+ agentStatusIntervalRef.value.unref?.();
127
+
128
+ return { unsubs, agentStatusIntervalRef };
129
+ }
@@ -39,6 +39,8 @@ import type { PeerClient } from '@/runtime/index.ts';
39
39
  import type { DirectTransport } from '@/runtime/index.ts';
40
40
  import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
41
41
  import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media';
42
+ import type { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
43
+ import type { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
42
44
  import {
43
45
  createBootstrapCommandActions,
44
46
  createBootstrapCommandClientsSection,
@@ -63,6 +65,8 @@ export type CreateBootstrapCommandContextOptions = {
63
65
  voiceProviderRegistry?: VoiceProviderRegistry;
64
66
  voiceService?: VoiceService;
65
67
  mediaProviderRegistry?: MediaProviderRegistry;
68
+ artifactStore?: ArtifactStore;
69
+ channelDeliveryRouter?: ChannelDeliveryRouter;
66
70
  forensicsRegistry: ForensicsRegistry;
67
71
  policyRuntimeState: PolicyRuntimeState;
68
72
  readModels: UiReadModels;
@@ -133,6 +137,8 @@ export function createBootstrapCommandContext(
133
137
  voiceProviderRegistry,
134
138
  voiceService,
135
139
  mediaProviderRegistry,
140
+ artifactStore,
141
+ channelDeliveryRouter,
136
142
  forensicsRegistry,
137
143
  policyRuntimeState,
138
144
  readModels,
@@ -240,7 +246,7 @@ export function createBootstrapCommandContext(
240
246
  projectPlanningProjectId,
241
247
  workPlanStore,
242
248
  }, shellServices);
243
- const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, mediaProviderRegistry }, shellServices);
249
+ const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, mediaProviderRegistry, artifactStore, channelDeliveryRouter }, shellServices);
244
250
  const extensions = createBootstrapCommandExtensionsSection({
245
251
  toolRegistry,
246
252
  mcpRegistry,
@@ -42,6 +42,8 @@ import type { PeerClient } from '@/runtime/index.ts';
42
42
  import type { DirectTransport } from '@/runtime/index.ts';
43
43
  import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
44
44
  import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media';
45
+ import type { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
46
+ import type { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
45
47
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
46
48
 
47
49
  export type BootstrapCommandSessionSection = CommandContext['session'];
@@ -79,6 +81,8 @@ export interface BootstrapCommandSectionOptions {
79
81
  readonly voiceProviderRegistry?: VoiceProviderRegistry;
80
82
  readonly voiceService?: VoiceService;
81
83
  readonly mediaProviderRegistry?: MediaProviderRegistry;
84
+ readonly artifactStore?: ArtifactStore;
85
+ readonly channelDeliveryRouter?: ChannelDeliveryRouter;
82
86
  readonly forensicsRegistry: ForensicsRegistry;
83
87
  readonly policyRuntimeState: PolicyRuntimeState;
84
88
  readonly readModels: UiReadModels;
@@ -150,7 +154,6 @@ export function createBootstrapCommandActions(
150
154
  | 'exit'
151
155
  | 'reloadSystemPrompt'
152
156
  | 'showPanel'
153
- | 'openPolicyPanel'
154
157
  | 'openMcpWorkspace'
155
158
  | 'openAgentWorkspace'
156
159
  | 'openSecurityPanel'
@@ -171,8 +174,9 @@ export function createBootstrapCommandActions(
171
174
  } = options;
172
175
 
173
176
  const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
174
- panelManager.open(panelId, pane);
175
- panelManager.show();
177
+ void pane;
178
+ panelManager.hide();
179
+ conversation.log(`Panel route "${panelId}" is handled through Agent Workspace. Use /agent for current operator controls.`, { fg: '214' });
176
180
  requestRender();
177
181
  };
178
182
 
@@ -200,7 +204,7 @@ export function createBootstrapCommandActions(
200
204
  // Write to tool LLM config keys and enable the tool LLM
201
205
  configManager.set('tools.llmProvider', def.provider);
202
206
  configManager.set('tools.llmModel', key);
203
- configManager.setDynamic('tools.llmEnabled' as never, true);
207
+ configManager.setDynamic('tools.llmEnabled', true);
204
208
  conversation.log(`Tool LLM set to: ${def.displayName} (${def.provider})`, { fg: '135' });
205
209
  } else if (resolvedTarget === 'tts') {
206
210
  configManager.set('tts.llmProvider', def.provider);
@@ -237,9 +241,6 @@ export function createBootstrapCommandActions(
237
241
  exit: () => unwiredShellAction('exit'),
238
242
  reloadSystemPrompt: loadSystemPrompt,
239
243
  showPanel,
240
- openPolicyPanel: () => {
241
- showPanel('policy');
242
- },
243
244
  openMcpWorkspace: () => unwiredShellAction('openMcpWorkspace'),
244
245
  openAgentWorkspace: () => unwiredShellAction('openAgentWorkspace'),
245
246
  openSecurityPanel: () => {
@@ -308,7 +309,7 @@ export function createBootstrapCommandWorkspaceSection(
308
309
  export function createBootstrapCommandPlatformSection(
309
310
  options: Pick<
310
311
  BootstrapCommandSectionOptions,
311
- 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'mediaProviderRegistry'
312
+ 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'mediaProviderRegistry' | 'artifactStore' | 'channelDeliveryRouter'
312
313
  >,
313
314
  shellServices: BootstrapCommandShellServices,
314
315
  ): BootstrapCommandPlatformSection {
@@ -318,6 +319,8 @@ export function createBootstrapCommandPlatformSection(
318
319
  voiceProviderRegistry: options.voiceProviderRegistry,
319
320
  voiceService: options.voiceService,
320
321
  mediaProviderRegistry: options.mediaProviderRegistry,
322
+ artifactStore: options.artifactStore,
323
+ channelDeliveryRouter: options.channelDeliveryRouter,
321
324
  ...shellServices.platform,
322
325
  };
323
326
  }