@pellux/goodvibes-agent 0.1.117 → 1.0.1

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 (255) hide show
  1. package/CHANGELOG.md +20 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176093 -171065
  5. package/docs/README.md +11 -5
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +3 -3
  8. package/docs/getting-started.md +29 -15
  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 +44 -9
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +2 -5
  16. package/src/agent/channel-delivery.ts +201 -0
  17. package/src/agent/media-generation.ts +159 -0
  18. package/src/agent/memory-prompt.ts +0 -1
  19. package/src/agent/note-registry.ts +329 -0
  20. package/src/agent/operator-actions.ts +343 -0
  21. package/src/agent/persona-registry.ts +15 -14
  22. package/src/agent/record-labels.ts +107 -0
  23. package/src/agent/reminder-schedule-format.ts +33 -24
  24. package/src/agent/reminder-schedule.ts +26 -25
  25. package/src/agent/routine-registry.ts +13 -12
  26. package/src/agent/routine-schedule-args.ts +2 -1
  27. package/src/agent/routine-schedule-format.ts +77 -53
  28. package/src/agent/routine-schedule-promotion.ts +34 -32
  29. package/src/agent/routine-schedule-receipts.ts +28 -26
  30. package/src/agent/runtime-profile-starters.ts +2 -2
  31. package/src/agent/runtime-profile.ts +18 -17
  32. package/src/agent/skill-registry.ts +25 -24
  33. package/src/cli/agent-knowledge-args.ts +5 -1
  34. package/src/cli/agent-knowledge-command.ts +39 -33
  35. package/src/cli/agent-knowledge-format.ts +80 -67
  36. package/src/cli/agent-knowledge-methods.ts +1 -1
  37. package/src/cli/agent-knowledge-runtime.ts +32 -26
  38. package/src/cli/bundle-command.ts +13 -8
  39. package/src/cli/config-overrides.ts +37 -36
  40. package/src/cli/external-runtime.ts +10 -4
  41. package/src/cli/help.ts +29 -11
  42. package/src/cli/local-library-command.ts +159 -73
  43. package/src/cli/management-commands.ts +98 -62
  44. package/src/cli/management.ts +52 -26
  45. package/src/cli/memory-command.ts +66 -32
  46. package/src/cli/parser.ts +37 -24
  47. package/src/cli/profiles-command.ts +52 -35
  48. package/src/cli/provider-auth-routes.ts +2 -1
  49. package/src/cli/routines-command.ts +59 -39
  50. package/src/cli/service-posture.ts +6 -6
  51. package/src/cli/status.ts +46 -121
  52. package/src/core/conversation-message-snapshot.ts +131 -0
  53. package/src/input/agent-workspace-activation.ts +33 -7
  54. package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
  55. package/src/input/agent-workspace-basic-command-editors.ts +30 -10
  56. package/src/input/agent-workspace-categories.ts +276 -64
  57. package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
  58. package/src/input/agent-workspace-channel-command-editors.ts +23 -5
  59. package/src/input/agent-workspace-channels.ts +35 -2
  60. package/src/input/agent-workspace-command-editor.ts +18 -2
  61. package/src/input/agent-workspace-config-reader.ts +16 -0
  62. package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
  63. package/src/input/agent-workspace-editors.ts +140 -2
  64. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  65. package/src/input/agent-workspace-knowledge-url-editor.ts +4 -11
  66. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  67. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  68. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  69. package/src/input/agent-workspace-local-operations.ts +218 -0
  70. package/src/input/agent-workspace-local-selection.ts +75 -0
  71. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  72. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  73. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  74. package/src/input/agent-workspace-memory-editor.ts +2 -2
  75. package/src/input/agent-workspace-navigation.ts +38 -2
  76. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  77. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  78. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  79. package/src/input/agent-workspace-panel-route.ts +43 -0
  80. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  81. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  82. package/src/input/agent-workspace-search.ts +169 -0
  83. package/src/input/agent-workspace-setup.ts +22 -11
  84. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  85. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  86. package/src/input/agent-workspace-snapshot.ts +112 -13
  87. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  88. package/src/input/agent-workspace-token.ts +18 -2
  89. package/src/input/agent-workspace-types.ts +92 -4
  90. package/src/input/agent-workspace-voice-media.ts +3 -6
  91. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  92. package/src/input/agent-workspace.ts +136 -208
  93. package/src/input/command-registry.ts +4 -1
  94. package/src/input/commands/agent-local-library-args.ts +52 -0
  95. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  96. package/src/input/commands/agent-skills-runtime.ts +87 -99
  97. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  98. package/src/input/commands/brief-runtime.ts +25 -24
  99. package/src/input/commands/channels-runtime.ts +145 -31
  100. package/src/input/commands/delegation-runtime.ts +29 -23
  101. package/src/input/commands/experience-runtime.ts +6 -4
  102. package/src/input/commands/guidance-runtime.ts +4 -4
  103. package/src/input/commands/health-runtime.ts +140 -115
  104. package/src/input/commands/knowledge.ts +57 -56
  105. package/src/input/commands/local-provider-runtime.ts +36 -18
  106. package/src/input/commands/local-runtime.ts +138 -16
  107. package/src/input/commands/local-setup-review.ts +7 -7
  108. package/src/input/commands/mcp-runtime.ts +118 -50
  109. package/src/input/commands/notify-runtime.ts +38 -9
  110. package/src/input/commands/operator-actions-runtime.ts +138 -0
  111. package/src/input/commands/operator-runtime.ts +6 -17
  112. package/src/input/commands/personas-runtime.ts +49 -59
  113. package/src/input/commands/planning-runtime.ts +1 -1
  114. package/src/input/commands/platform-access-runtime.ts +29 -29
  115. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  116. package/src/input/commands/qrcode-runtime.ts +45 -6
  117. package/src/input/commands/recall-bundle.ts +11 -11
  118. package/src/input/commands/recall-capture.ts +13 -11
  119. package/src/input/commands/recall-query.ts +29 -21
  120. package/src/input/commands/recall-review.ts +2 -1
  121. package/src/input/commands/routines-runtime.ts +63 -72
  122. package/src/input/commands/schedule-runtime.ts +33 -20
  123. package/src/input/commands/security-runtime.ts +4 -4
  124. package/src/input/commands/session-content.ts +80 -78
  125. package/src/input/commands/session-workflow.ts +132 -93
  126. package/src/input/commands/session.ts +3 -174
  127. package/src/input/commands/shell-core.ts +32 -17
  128. package/src/input/commands/subscription-runtime.ts +53 -179
  129. package/src/input/commands/tasks-runtime.ts +20 -20
  130. package/src/input/commands/work-plan-runtime.ts +33 -8
  131. package/src/input/commands.ts +2 -2
  132. package/src/input/feed-context-factory.ts +2 -1
  133. package/src/input/file-picker.ts +3 -2
  134. package/src/input/handler-command-route.ts +4 -7
  135. package/src/input/handler-content-actions.ts +89 -1
  136. package/src/input/handler-feed-routes.ts +19 -12
  137. package/src/input/handler-feed.ts +6 -3
  138. package/src/input/handler-interactions.ts +7 -5
  139. package/src/input/handler-modal-stack.ts +3 -3
  140. package/src/input/handler-onboarding.ts +24 -80
  141. package/src/input/handler-shortcuts.ts +15 -4
  142. package/src/input/handler.ts +47 -17
  143. package/src/input/input-history.ts +5 -6
  144. package/src/input/keybindings.ts +22 -11
  145. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  146. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  147. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  148. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  149. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  150. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  151. package/src/input/profile-picker-modal.ts +31 -12
  152. package/src/input/session-picker-modal.ts +22 -4
  153. package/src/input/settings-modal-behavior.ts +0 -3
  154. package/src/input/settings-modal-subscriptions.ts +3 -3
  155. package/src/input/settings-modal-types.ts +2 -13
  156. package/src/input/settings-modal.ts +6 -52
  157. package/src/input/submission-intent.ts +0 -1
  158. package/src/input/submission-router.ts +3 -3
  159. package/src/main.ts +18 -8
  160. package/src/panels/approval-panel.ts +8 -8
  161. package/src/panels/automation-control-panel.ts +2 -2
  162. package/src/panels/base-panel.ts +1 -1
  163. package/src/panels/builtin/agent.ts +1 -1
  164. package/src/panels/builtin/operations.ts +1 -10
  165. package/src/panels/builtin/session.ts +9 -9
  166. package/src/panels/builtin/shared.ts +2 -2
  167. package/src/panels/cost-tracker-panel.ts +1 -1
  168. package/src/panels/docs-panel.ts +5 -3
  169. package/src/panels/index.ts +0 -1
  170. package/src/panels/knowledge-panel.ts +6 -5
  171. package/src/panels/memory-panel.ts +7 -6
  172. package/src/panels/panel-list-panel.ts +36 -80
  173. package/src/panels/project-planning-panel.ts +18 -11
  174. package/src/panels/provider-account-snapshot.ts +51 -25
  175. package/src/panels/provider-accounts-panel.ts +33 -18
  176. package/src/panels/provider-health-domains.ts +45 -4
  177. package/src/panels/provider-health-panel.ts +5 -4
  178. package/src/panels/qr-panel.ts +1 -1
  179. package/src/panels/schedule-panel.ts +9 -17
  180. package/src/panels/security-panel.ts +8 -8
  181. package/src/panels/session-browser-panel.ts +10 -10
  182. package/src/panels/subscription-panel.ts +3 -3
  183. package/src/panels/system-messages-panel.ts +1 -1
  184. package/src/panels/tasks-panel.ts +20 -13
  185. package/src/panels/tool-inspector-panel.ts +19 -12
  186. package/src/panels/work-plan-panel.ts +5 -5
  187. package/src/planning/project-planning-coordinator.ts +1 -1
  188. package/src/provider-auth-route-display.ts +9 -0
  189. package/src/renderer/agent-workspace-style.ts +34 -0
  190. package/src/renderer/agent-workspace.ts +228 -52
  191. package/src/renderer/autocomplete-overlay.ts +25 -6
  192. package/src/renderer/bookmark-modal.ts +19 -4
  193. package/src/renderer/buffer.ts +4 -2
  194. package/src/renderer/context-inspector.ts +50 -13
  195. package/src/renderer/diff.ts +1 -1
  196. package/src/renderer/file-picker-overlay.ts +19 -6
  197. package/src/renderer/help-overlay.ts +106 -33
  198. package/src/renderer/history-search-overlay.ts +19 -4
  199. package/src/renderer/live-tail-modal.ts +27 -5
  200. package/src/renderer/mcp-workspace.ts +164 -50
  201. package/src/renderer/model-picker-overlay.ts +58 -2
  202. package/src/renderer/model-workspace.ts +104 -20
  203. package/src/renderer/process-modal.ts +27 -6
  204. package/src/renderer/profile-picker-modal.ts +20 -4
  205. package/src/renderer/search-overlay.ts +25 -5
  206. package/src/renderer/selection-modal-overlay.ts +46 -14
  207. package/src/renderer/session-picker-modal.ts +18 -1
  208. package/src/renderer/settings-modal-helpers.ts +2 -40
  209. package/src/renderer/settings-modal.ts +83 -50
  210. package/src/renderer/tool-call.ts +20 -11
  211. package/src/runtime/agent-runtime-events.ts +6 -6
  212. package/src/runtime/bootstrap-command-context.ts +7 -1
  213. package/src/runtime/bootstrap-command-parts.ts +9 -7
  214. package/src/runtime/bootstrap-core.ts +19 -1
  215. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  216. package/src/runtime/bootstrap-shell.ts +4 -4
  217. package/src/runtime/bootstrap.ts +31 -22
  218. package/src/runtime/connected-host-auth.ts +7 -2
  219. package/src/runtime/diagnostics/panels/index.ts +2 -2
  220. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  221. package/src/runtime/index.ts +2 -1
  222. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  223. package/src/runtime/onboarding/apply.ts +80 -79
  224. package/src/runtime/onboarding/derivation.ts +5 -8
  225. package/src/runtime/onboarding/snapshot.ts +0 -15
  226. package/src/runtime/onboarding/types.ts +8 -19
  227. package/src/runtime/onboarding/verify.ts +32 -10
  228. package/src/runtime/operator-token-cleanup.ts +1 -1
  229. package/src/runtime/services.ts +91 -22
  230. package/src/runtime/store/selectors/index.ts +3 -3
  231. package/src/runtime/store/state.ts +1 -4
  232. package/src/runtime/surface-feature-flags.ts +41 -6
  233. package/src/runtime/ui-read-models.ts +3 -4
  234. package/src/runtime/ui-services.ts +6 -6
  235. package/src/shell/blocking-input.ts +2 -1
  236. package/src/shell/ui-openers.ts +3 -13
  237. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  238. package/src/tools/agent-channel-send-tool.ts +133 -0
  239. package/src/tools/agent-context-policy.ts +1 -1
  240. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  241. package/src/tools/agent-knowledge-tool.ts +170 -0
  242. package/src/tools/agent-local-registry-tool.ts +269 -69
  243. package/src/tools/agent-media-generate-tool.ts +133 -0
  244. package/src/tools/agent-notify-tool.ts +143 -0
  245. package/src/tools/agent-operator-action-tool.ts +137 -0
  246. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  247. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  248. package/src/tools/agent-tool-policy-guard.ts +8 -8
  249. package/src/tools/agent-work-plan-tool.ts +256 -0
  250. package/src/version.ts +1 -1
  251. package/src/input/commands/policy-dispatch.ts +0 -339
  252. package/src/input/commands/policy.ts +0 -13
  253. package/src/panels/panel-picker.ts +0 -105
  254. package/src/panels/policy-panel.ts +0 -308
  255. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -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);
@@ -88,11 +88,11 @@ export function registerAgentRuntimeEvents(options: AgentRuntimeEventBridgeOptio
88
88
  const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
89
89
  const taskSnippet = formatAgentTask(record.task);
90
90
  withRouter(getSystemMessageRouter, (router) => {
91
- router.low(`[Agent task] ${record.template} ${payload.agentId.slice(-8)} completed in ${durationSeconds}s: "${taskSnippet}"`);
91
+ router.low(`[Delegated task] ${record.template} ${payload.agentId.slice(-8)} completed in ${durationSeconds}s "${taskSnippet}"`);
92
92
  });
93
93
  queueConversationFollowUp?.({
94
94
  key: `agent:${payload.agentId}:completed`,
95
- summary: `${record.template} agent ${payload.agentId.slice(-8)} completed "${taskSnippet}" in ${durationSeconds}s after ${record.toolCallCount} tool calls.`,
95
+ summary: `${record.template} delegated task ${payload.agentId.slice(-8)} completed "${taskSnippet}" in ${durationSeconds}s after ${record.toolCallCount} tool calls.`,
96
96
  });
97
97
  }
98
98
  requestRender();
@@ -103,11 +103,11 @@ export function registerAgentRuntimeEvents(options: AgentRuntimeEventBridgeOptio
103
103
  const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
104
104
  const taskSnippet = formatAgentTask(record.task);
105
105
  withRouter(getSystemMessageRouter, (router) => {
106
- router.low(`[Agent task] ${record.template} ${payload.agentId.slice(-8)} failed in ${durationSeconds}s: ${payload.error.slice(0, 80)}`);
106
+ router.low(`[Delegated task] ${record.template} ${payload.agentId.slice(-8)} failed in ${durationSeconds}s ${payload.error.slice(0, 80)}`);
107
107
  });
108
108
  queueConversationFollowUp?.({
109
109
  key: `agent:${payload.agentId}:failed`,
110
- summary: `${record.template} agent ${payload.agentId.slice(-8)} failed while working on "${taskSnippet}": ${payload.error.slice(0, 120)}`,
110
+ summary: `${record.template} delegated task ${payload.agentId.slice(-8)} failed while working on "${taskSnippet}" ${payload.error.slice(0, 120)}`,
111
111
  });
112
112
  }
113
113
  requestRender();
@@ -117,9 +117,9 @@ export function registerAgentRuntimeEvents(options: AgentRuntimeEventBridgeOptio
117
117
  agentStatusIntervalRef.value = setInterval(() => {
118
118
  const running = agentManager.list().filter((agent) => agent.status === 'running');
119
119
  if (running.length === 0) return;
120
- const lines = running.map((agent) => ` ${agent.id.slice(-8)}: ${agent.progress ?? agent.status}`);
120
+ const lines = running.map((agent) => ` ${agent.id.slice(-8)} ${agent.progress ?? agent.status}`);
121
121
  withRouter(getSystemMessageRouter, (router) => {
122
- router.low(`[Agent task] ${running.length} running:\n${lines.join('\n')}`);
122
+ router.low(`[Delegated task] ${running.length} running\n${lines.join('\n')}`);
123
123
  });
124
124
  requestRender();
125
125
  }, AGENT_STATUS_INTERVAL_MS);
@@ -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'
@@ -173,7 +176,7 @@ export function createBootstrapCommandActions(
173
176
  const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
174
177
  void pane;
175
178
  panelManager.hide();
176
- conversation.log(`Panel "${panelId}" is deferred in GoodVibes Agent. Use /agent for the operator workspace.`, { fg: '214' });
179
+ conversation.log(`Panel route "${panelId}" is handled through Agent Workspace. Use /agent for current operator controls.`, { fg: '214' });
177
180
  requestRender();
178
181
  };
179
182
 
@@ -201,7 +204,7 @@ export function createBootstrapCommandActions(
201
204
  // Write to tool LLM config keys and enable the tool LLM
202
205
  configManager.set('tools.llmProvider', def.provider);
203
206
  configManager.set('tools.llmModel', key);
204
- configManager.setDynamic('tools.llmEnabled' as never, true);
207
+ configManager.setDynamic('tools.llmEnabled', true);
205
208
  conversation.log(`Tool LLM set to: ${def.displayName} (${def.provider})`, { fg: '135' });
206
209
  } else if (resolvedTarget === 'tts') {
207
210
  configManager.set('tts.llmProvider', def.provider);
@@ -238,9 +241,6 @@ export function createBootstrapCommandActions(
238
241
  exit: () => unwiredShellAction('exit'),
239
242
  reloadSystemPrompt: loadSystemPrompt,
240
243
  showPanel,
241
- openPolicyPanel: () => {
242
- showPanel('policy');
243
- },
244
244
  openMcpWorkspace: () => unwiredShellAction('openMcpWorkspace'),
245
245
  openAgentWorkspace: () => unwiredShellAction('openAgentWorkspace'),
246
246
  openSecurityPanel: () => {
@@ -309,7 +309,7 @@ export function createBootstrapCommandWorkspaceSection(
309
309
  export function createBootstrapCommandPlatformSection(
310
310
  options: Pick<
311
311
  BootstrapCommandSectionOptions,
312
- 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'mediaProviderRegistry'
312
+ 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'mediaProviderRegistry' | 'artifactStore' | 'channelDeliveryRouter'
313
313
  >,
314
314
  shellServices: BootstrapCommandShellServices,
315
315
  ): BootstrapCommandPlatformSection {
@@ -319,6 +319,8 @@ export function createBootstrapCommandPlatformSection(
319
319
  voiceProviderRegistry: options.voiceProviderRegistry,
320
320
  voiceService: options.voiceService,
321
321
  mediaProviderRegistry: options.mediaProviderRegistry,
322
+ artifactStore: options.artifactStore,
323
+ channelDeliveryRouter: options.channelDeliveryRouter,
322
324
  ...shellServices.platform,
323
325
  };
324
326
  }
@@ -29,7 +29,16 @@ import { registerBootstrapHookBridge } from '@/runtime/index.ts';
29
29
  import { createRuntimeServices, type RuntimeServices } from './services.ts';
30
30
  import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
31
31
  import { installAgentToolPolicyGuard } from '../tools/agent-tool-policy-guard.ts';
32
+ import { registerAgentChannelSendTool } from '../tools/agent-channel-send-tool.ts';
33
+ import { registerAgentKnowledgeIngestTool } from '../tools/agent-knowledge-ingest-tool.ts';
34
+ import { registerAgentKnowledgeTool } from '../tools/agent-knowledge-tool.ts';
32
35
  import { registerAgentLocalRegistryTool } from '../tools/agent-local-registry-tool.ts';
36
+ import { registerAgentMediaGenerateTool } from '../tools/agent-media-generate-tool.ts';
37
+ import { registerAgentNotifyTool } from '../tools/agent-notify-tool.ts';
38
+ import { registerAgentOperatorActionTool } from '../tools/agent-operator-action-tool.ts';
39
+ import { registerAgentOperatorBriefingTool } from '../tools/agent-operator-briefing-tool.ts';
40
+ import { registerAgentReminderScheduleTool } from '../tools/agent-reminder-schedule-tool.ts';
41
+ import { registerAgentWorkPlanTool } from '../tools/agent-work-plan-tool.ts';
33
42
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
34
43
  import { registerAgentRuntimeEvents } from './agent-runtime-events.ts';
35
44
 
@@ -139,7 +148,7 @@ export async function initializeBootstrapCore(
139
148
  metadata: {
140
149
  product: 'goodvibes-agent',
141
150
  surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
142
- clientKindNote: 'SDK has no dedicated agent client kind yet; using service for the Agent operator surface.',
151
+ clientKindNote: 'SDK compatibility client kind; GoodVibes Agent remains an interactive operator TUI.',
143
152
  },
144
153
  }, 'bootstrap.control-plane');
145
154
 
@@ -227,7 +236,16 @@ export async function initializeBootstrapCore(
227
236
  overflowHandler: services.overflowHandler,
228
237
  changeTracker: services.sessionChangeTracker,
229
238
  });
239
+ registerAgentKnowledgeIngestTool(toolRegistry, services.shellPaths, configManager);
240
+ registerAgentChannelSendTool(toolRegistry, services.channelDeliveryRouter);
241
+ registerAgentKnowledgeTool(toolRegistry, services.shellPaths, configManager);
230
242
  registerAgentLocalRegistryTool(toolRegistry, services.shellPaths, services.memoryRegistry);
243
+ registerAgentMediaGenerateTool(toolRegistry, services.mediaProviders, services.artifactStore);
244
+ registerAgentNotifyTool(toolRegistry, configManager, services.webhookNotifier);
245
+ registerAgentOperatorActionTool(toolRegistry, services.shellPaths, configManager);
246
+ registerAgentOperatorBriefingTool(toolRegistry, services.shellPaths, configManager);
247
+ registerAgentReminderScheduleTool(toolRegistry, services.shellPaths, configManager);
248
+ registerAgentWorkPlanTool(toolRegistry, services.workPlanStore);
231
249
  installAgentToolPolicyGuard(toolRegistry, {
232
250
  getLastUserMessage: () => conversation.getLastUserMessage(),
233
251
  });
@@ -10,9 +10,9 @@ import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
10
10
  import { formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
11
11
  import type { SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
12
12
  import type { SessionManager } from '@pellux/goodvibes-sdk/platform/sessions';
13
- import type { PanelManager } from '../panels/panel-manager.ts';
14
13
  import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
15
14
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
15
+ import { readConversationMessageSnapshots } from '../core/conversation-message-snapshot.ts';
16
16
 
17
17
  export interface ResumeSessionOptions {
18
18
  readonly runtimeBus: RuntimeEventBus;
@@ -24,7 +24,6 @@ export interface ResumeSessionOptions {
24
24
  readonly writeLastSessionPointer: (sessionId: string) => void;
25
25
  readonly hookDispatcher: HookDispatcher;
26
26
  readonly sessionManager: SessionManager;
27
- readonly panelManager: PanelManager;
28
27
  readonly configManager: Pick<ConfigManager, 'get' | 'getCategory'>;
29
28
  readonly providerRegistry: Pick<ProviderRegistry, 'get' | 'getCurrentModel' | 'getForModel' | 'require'>;
30
29
  }
@@ -42,7 +41,7 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
42
41
  turnCount: messages.length,
43
42
  });
44
43
  options.conversation.fromJSON({
45
- messages: messages as Parameters<typeof options.conversation.fromJSON>[0]['messages'],
44
+ messages: readConversationMessageSnapshots(messages),
46
45
  title: meta.title,
47
46
  titleSource: meta.titleSource,
48
47
  });
@@ -53,28 +52,18 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
53
52
  options.writeLastSessionPointer(sessionId);
54
53
  void options.sharedSessionBroker.reopenSession(sessionId).catch((err) => { logger.debug('session broker reopen session failed', { err }); });
55
54
  options.conversation.log(`Resumed session: ${sessionId}`, { fg: '135' });
56
- const reopenedPanels: string[] = [];
57
- if (meta.returnContext?.openPanels?.length) {
58
- for (const panelId of meta.returnContext.openPanels.slice(0, 4)) {
59
- try {
60
- options.panelManager.open(panelId);
61
- reopenedPanels.push(panelId);
62
- } catch {
63
- // Ignore unavailable panels during restore.
64
- }
65
- }
66
- if (reopenedPanels.length > 0) options.panelManager.show();
67
- }
55
+ const ignoredPanels = meta.returnContext?.openPanels?.slice(0, 4) ?? [];
68
56
  const returnContextMode = getReturnContextMode(options.configManager);
69
57
  if (returnContextMode !== 'off' && meta.returnContext) {
70
58
  for (const line of formatReturnContextForDisplay(meta.returnContext)) {
59
+ if (line.startsWith('Open panels:')) continue;
71
60
  options.conversation.log(`Resume: ${line}`, { fg: '244' });
72
61
  }
73
- if (reopenedPanels.length > 0) {
74
- options.conversation.log(`Resume: Reopened panels: ${reopenedPanels.join(', ')}`, { fg: '244' });
62
+ if (ignoredPanels.length > 0) {
63
+ options.conversation.log(`Resume: Saved panel state ignored: ${ignoredPanels.join(', ')}. Open the Agent workspace for current operator controls.`, { fg: '244' });
75
64
  }
76
65
  if ((meta.returnContext.remoteRunners?.length ?? 0) > 0) {
77
- options.conversation.log('Resume: Remote runner recovery belongs outside Agent; delegate explicit build/fix/review recovery from Agent.', { fg: '244' });
66
+ options.conversation.log('Resume: Remote build-host recovery belongs outside Agent; delegate explicit build/fix/review recovery from Agent.', { fg: '244' });
78
67
  }
79
68
  if (returnContextMode === 'assisted') {
80
69
  const helperModel = new HelperModel({
@@ -133,7 +133,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
133
133
  writeLastSessionPointer,
134
134
  hookDispatcher: services.hookDispatcher,
135
135
  sessionManager: services.sessionManager,
136
- panelManager: services.panelManager,
137
136
  configManager,
138
137
  providerRegistry: services.providerRegistry,
139
138
  });
@@ -180,7 +179,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
180
179
  hookActivityTracker: services.hookActivityTracker,
181
180
  hookWorkbench: services.hookWorkbench,
182
181
  mcpRegistry: services.mcpRegistry,
183
- daemonHomeDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
182
+ connectedHostTokenDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
184
183
  });
185
184
  services.panelManager.prewarmRegistered();
186
185
 
@@ -198,9 +197,8 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
198
197
 
199
198
  const commandRegistry = new CommandRegistry();
200
199
  registerBuiltinCommands(commandRegistry);
201
- type RuntimeFoundationInput = Parameters<typeof createRuntimeFoundationClients>[0];
202
200
  const foundationClients = createRuntimeFoundationClients({
203
- runtimeServices: services as unknown as RuntimeFoundationInput['runtimeServices'],
201
+ runtimeServices: services,
204
202
  tasksReadModel: uiServices.readModels.tasks,
205
203
  taskManager,
206
204
  opsControlPlane,
@@ -236,6 +234,8 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
236
234
  voiceProviderRegistry: services.voiceProviders,
237
235
  voiceService: services.voiceService,
238
236
  mediaProviderRegistry: services.mediaProviders,
237
+ artifactStore: services.artifactStore,
238
+ channelDeliveryRouter: services.channelDeliveryRouter,
239
239
  forensicsRegistry,
240
240
  policyRuntimeState,
241
241
  readModels: uiServices.readModels,
@@ -45,14 +45,23 @@ import { buildReviewedMemoryPrompt } from '../agent/memory-prompt.ts';
45
45
 
46
46
  const GOODVIBES_AGENT_OPERATOR_POLICY = [
47
47
  '## GoodVibes Agent Operator Policy',
48
- '- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only connected-host/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
48
+ '- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure Agent-local state, use read-only connected-host/operator routes, and take safe non-destructive actions without creating separate Agent jobs or GoodVibes TUI delegations.',
49
49
  '- GoodVibes Agent connects to a GoodVibes host owned outside this package. Do not start, stop, restart, install, expose, or mutate connected-host network/listener posture from Agent.',
50
- '- Use the `agent_local_registry` tool when a durable memory, reusable persona, skill, skill bundle, or routine would improve future work. Keep those records local, non-secret, source/provenance tagged, and reviewable. Review memory with a confidence score when it should shape future turns. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
51
- '- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
52
- '- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
53
- '- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request WRFC only for explicit build/fix/review work or when the user explicitly asks for WRFC/agent review.',
54
- '- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, execution isolation UX, and the WRFC owner chain.',
55
- '- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or spawning sibling local agents.',
50
+ '- Use the `agent_operator_briefing` tool for read-only main-conversation summaries of connected work plan, approvals, automation, schedules, and scheduler capacity. This tool must not call mutation routes, connected-host lifecycle routes, default knowledge, non-Agent knowledge spaces, separate Agent job creation, or GoodVibes TUI delegation.',
51
+ '- When the user explicitly asks Agent to approve, deny, or cancel a specific approval, run/pause/resume a specific automation job, cancel/retry a specific automation run, or run a specific schedule, use the `agent_operator_action` tool with confirm:true and the original user request. It can call only its allowlisted public operator routes and must not create, edit, delete, or discover automation definitions.',
52
+ '- Use the `agent_work_plan` tool to keep the visible Agent-local work plan current while working in the main conversation. Create, inspect, and update local work items proactively when useful. Removing items or clearing completed items requires an explicit user request and confirm:true.',
53
+ '- Use the `agent_knowledge` tool for Agent Knowledge status, ask, and search from the main conversation. It must use only /api/goodvibes-agent/knowledge/* and must fail closed instead of falling back to default knowledge or non-Agent knowledge spaces.',
54
+ '- When the user explicitly asks Agent to add, import, remember, or ingest a URL, URL-list file, local file, bookmarks file, browser history, or connector input into Agent Knowledge, use the `agent_knowledge_ingest` tool with confirm:true and the original user request. It must write only to /api/goodvibes-agent/knowledge/* ingest routes and never to default knowledge or non-Agent knowledge spaces.',
55
+ '- Use the `agent_local_registry` tool when a scratchpad note, durable memory, reusable persona, skill, skill bundle, or routine would improve later work. Keep those records Agent-local, non-secret, source/provenance tagged, and reviewable. Notes are for temporary/source-triage context; promote them explicitly into memory, skills, personas, routines, or Agent Knowledge only when that is the correct durable home. Review memory with a confidence score when it should shape later turns. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
56
+ '- When the user explicitly asks Agent to generate an image, video, or other media artifact, use the `agent_media_generate` tool with confirm:true and the original user request. Generated media is stored as artifacts; do not print base64, call default knowledge, use non-Agent knowledge spaces, send channels, create separate Agent jobs, or request GoodVibes TUI delegation for media generation.',
57
+ '- When the user explicitly asks Agent to send an alert, message, or notification to configured notification targets, use the `agent_notify` tool with confirm:true and the original user request. Do not infer external notifications from vague suggestions, and never create channel routes or account authorizations from the main conversation.',
58
+ '- When the user explicitly asks Agent to send one message to a specific configured channel, route, webhook, or link target, use the `agent_channel_send` tool with confirm:true and the original user request. It can deliver one message through configured delivery strategies, but must not create routes, authorize accounts, manage connected-host hosting, use default knowledge, use non-Agent knowledge spaces, create separate Agent jobs, or request GoodVibes TUI delegation.',
59
+ '- When the user explicitly asks for a reminder or asks Agent to schedule a reminder, use the `agent_reminder_schedule` tool with confirm:true and the original user request. That creates one connected schedules.create reminder on the external GoodVibes host. Do not infer reminders from vague suggestions or routine startup, and never create local scheduler jobs.',
60
+ '- GoodVibes TUI delegation is never the default Agent reasoning path. Do not delegate planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
61
+ '- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to create coding-role Agent jobs or batch job roots from Agent.',
62
+ '- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request delegated review only for explicit build/fix/review work or when the user explicitly asks for delegated Agent review.',
63
+ '- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, execution isolation UX, and delegated review coordination.',
64
+ '- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or creating sibling Agent jobs.',
56
65
  ].join('\n');
57
66
 
58
67
  function joinPromptParts(...parts: Array<string | null | undefined>): string {
@@ -126,7 +135,7 @@ export type BootstrapContext = RuntimeContext & {
126
135
  * 1. Config, caches, keybindings
127
136
  * 2. Runtime event bus, conversation, compositor, selection
128
137
  * 3. Tool registry + agent wiring
129
- * 4. Runtime bus subscriptions (WRFC, subagent, hook bridge)
138
+ * 4. Runtime bus subscriptions (delegation, subagent, hook bridge)
130
139
  * 5. Providers, webhooks, PermissionManager, HookDispatcher
131
140
  * 6. Orchestrator and Agent-local task read models
132
141
  * 7. MCP auto-connect + workspace/panel manager
@@ -295,7 +304,7 @@ export async function bootstrapRuntime(
295
304
  },
296
305
  };
297
306
 
298
- // ── Phase 7: External services + deferred startup ──────────────────────
307
+ // ── Phase 7: Connected-host posture + deferred startup ────────────────
299
308
 
300
309
  const deferredStartup = createDeferredStartupCoordinator();
301
310
 
@@ -310,7 +319,7 @@ export async function bootstrapRuntime(
310
319
  return `http://${urlHost}:${port}`;
311
320
  };
312
321
 
313
- const createExternalAgentServiceStatus = (
322
+ const createAgentDependencyStatus = (
314
323
  service: 'daemon' | 'httpListener',
315
324
  ): HostServiceStatus => {
316
325
  const host = String(configManager.get(service === 'daemon' ? 'controlPlane.host' : 'httpListener.host') ?? '127.0.0.1');
@@ -321,7 +330,7 @@ export async function bootstrapRuntime(
321
330
  port,
322
331
  baseUrl: formatHostServiceBaseUrl(host, port),
323
332
  reason: service === 'daemon'
324
- ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
333
+ ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart it.'
325
334
  : 'GoodVibes Agent does not own listener lifecycle.',
326
335
  };
327
336
  };
@@ -330,15 +339,15 @@ export async function bootstrapRuntime(
330
339
 
331
340
  const hostServiceIsBlocked = (status: HostServiceStatus): boolean => status.mode === 'blocked';
332
341
 
333
- const inspectExternalServices = () => {
342
+ const inspectAgentDependencies = () => {
334
343
  const daemonStatus = externalServices.daemonStatus;
335
344
  const httpListenerStatus = externalServices.httpListenerStatus;
336
345
  return {
337
- daemonRunning: hostServiceIsActive(daemonStatus),
338
- daemonPortInUse: hostServiceIsBlocked(daemonStatus),
346
+ connectedHostRunning: hostServiceIsActive(daemonStatus),
347
+ connectedHostPortInUse: hostServiceIsBlocked(daemonStatus),
339
348
  httpListenerRunning: hostServiceIsActive(httpListenerStatus),
340
349
  httpListenerPortInUse: hostServiceIsBlocked(httpListenerStatus),
341
- daemonStatus,
350
+ connectedHostStatus: daemonStatus,
342
351
  httpListenerStatus,
343
352
  };
344
353
  };
@@ -346,8 +355,8 @@ export async function bootstrapRuntime(
346
355
  let externalServices: ExternalServicesHandle = {
347
356
  daemonServer: null,
348
357
  httpListener: null,
349
- daemonStatus: createExternalAgentServiceStatus('daemon'),
350
- httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
358
+ daemonStatus: createAgentDependencyStatus('daemon'),
359
+ httpListenerStatus: createAgentDependencyStatus('httpListener'),
351
360
  listRecentControlPlaneEvents: () => [],
352
361
  async stop(): Promise<void> {},
353
362
  };
@@ -355,16 +364,16 @@ export async function bootstrapRuntime(
355
364
  externalServices: NonNullable<typeof uiServices.platform.externalServices>;
356
365
  };
357
366
  platformExternalServices.externalServices = {
358
- inspect: inspectExternalServices,
367
+ inspect: inspectAgentDependencies,
359
368
  restart: async () => {
360
369
  externalServices = {
361
370
  ...externalServices,
362
- daemonStatus: createExternalAgentServiceStatus('daemon'),
363
- httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
371
+ daemonStatus: createAgentDependencyStatus('daemon'),
372
+ httpListenerStatus: createAgentDependencyStatus('httpListener'),
364
373
  };
365
374
  systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart the connected GoodVibes host. Start it from GoodVibes TUI or the owning host, then refresh status.');
366
375
  requestRender();
367
- return inspectExternalServices();
376
+ return inspectAgentDependencies();
368
377
  },
369
378
  };
370
379
  deferredStartup.schedule({
@@ -440,7 +449,7 @@ export async function bootstrapRuntime(
440
449
  bootstrapUnsubs.push(() => mcpAutoReload.stop());
441
450
  if (configManager.get('automation.enabled')) {
442
451
  logger.warn('Local automation startup is disabled in GoodVibes Agent; use connected-host observability instead.');
443
- systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit connected-host actions.');
452
+ systemMessageRouter.low('[Startup] Local automation execution is disabled in GoodVibes Agent; use read-only automation observability or explicit connected-host actions.');
444
453
  }
445
454
 
446
455
  // ── Phase 12: Session:start lifecycle hook ─────────────────────────────
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { existsSync, readFileSync } from 'node:fs';
2
3
  import { join } from 'node:path';
3
4
 
@@ -32,11 +33,15 @@ export function readConnectedHostOperatorToken(homeDirectory: string): Connected
32
33
  }
33
34
  }
34
35
 
36
+ export function connectedHostOperatorTokenFingerprint(token: string): string {
37
+ return createHash('sha256').update(token).digest('hex').slice(0, 12);
38
+ }
39
+
35
40
  export function connectedHostTokenRequiredMessage(path: string): string {
36
41
  return [
37
42
  'Connected-host operator token is required.',
38
- ` token path: ${path}`,
43
+ ` token path ${path}`,
39
44
  ' Agent does not create or rotate connected-host auth tokens.',
40
- ' Start or repair the owning GoodVibes host, then rerun this command.',
45
+ ' Provision or repair connected-host access through the owning GoodVibes host, then rerun this command.',
41
46
  ].join('\n');
42
47
  }
@@ -12,8 +12,8 @@ export type { InspectableDomain } from '@/runtime/index.ts';
12
12
  export { HealthPanel } from '@/runtime/index.ts';
13
13
  export { DivergencePanel } from '@/runtime/index.ts';
14
14
  export { ReplayPanel } from '@/runtime/index.ts';
15
- export { PolicyPanel } from './policy.ts';
16
- export type { PolicyPanelSnapshot } from './policy.ts';
15
+ export { PolicyDiagnosticsPanel } from './policy.ts';
16
+ export type { PolicyDiagnosticsSnapshot } from './policy.ts';
17
17
  export { ToolContractsPanel } from '@/runtime/index.ts';
18
18
  export { TransportPanel } from '@/runtime/index.ts';
19
19
  export type { TransportPanelSnapshot } from '@/runtime/index.ts';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Policy diagnostics panel data provider.
2
+ * Policy diagnostics data provider.
3
3
  *
4
4
  * Wraps a `PolicyRegistry` and optionally a `DivergencePanel` to expose
5
5
  * combined policy state (current bundle, candidate, simulation status,
@@ -24,7 +24,7 @@ import { logger } from '@pellux/goodvibes-sdk/platform/utils';
24
24
  /**
25
25
  * A point-in-time snapshot of policy state for diagnostics rendering.
26
26
  */
27
- export interface PolicyPanelSnapshot {
27
+ export interface PolicyDiagnosticsSnapshot {
28
28
  /** The currently enforced bundle, or null if no policy is active. */
29
29
  current: PolicyBundleVersion | null;
30
30
  /** The pending candidate bundle, or null if none loaded. */
@@ -48,12 +48,12 @@ export interface PolicyPanelSnapshot {
48
48
  }
49
49
 
50
50
  /**
51
- * PolicyPanel — diagnostics data provider for the policy registry.
51
+ * PolicyDiagnosticsPanel — diagnostics data provider for the policy registry.
52
52
  *
53
53
  * Usage:
54
54
  * ```ts
55
55
  * const registry = new PolicyRegistry();
56
- * const panel = new PolicyPanel(registry, divergencePanel);
56
+ * const panel = new PolicyDiagnosticsPanel(registry, divergencePanel);
57
57
  *
58
58
  * panel.subscribe(() => {
59
59
  * const snap = panel.getSnapshot();
@@ -67,7 +67,7 @@ export interface PolicyPanelSnapshot {
67
67
  * panel.dispose();
68
68
  * ```
69
69
  */
70
- export class PolicyPanel {
70
+ export class PolicyDiagnosticsPanel {
71
71
  private readonly _registry: PolicyRegistry;
72
72
  private readonly _divergencePanel: DivergencePanel | null;
73
73
  private readonly _config: PanelConfig;
@@ -118,7 +118,7 @@ export class PolicyPanel {
118
118
  /**
119
119
  * getSnapshot — Returns the current combined policy + divergence snapshot.
120
120
  */
121
- public getSnapshot(): PolicyPanelSnapshot {
121
+ public getSnapshot(): PolicyDiagnosticsSnapshot {
122
122
  const current = this._registry.getCurrent();
123
123
  const candidate = this._registry.getCandidate();
124
124
  const rawHistory = this._registry.getHistory();
@@ -170,7 +170,7 @@ export class PolicyPanel {
170
170
  try {
171
171
  cb();
172
172
  } catch (err) {
173
- logger.warn(`[PolicyPanel] subscriber error: ${err}`);
173
+ logger.warn(`[PolicyDiagnosticsPanel] subscriber error: ${err}`);
174
174
  }
175
175
  }
176
176
  }
@@ -112,7 +112,7 @@ function agentExternalHostStatus(
112
112
  port,
113
113
  baseUrl: `http://${host}:${port}`,
114
114
  reason: service === 'daemon'
115
- ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
115
+ ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart it.'
116
116
  : 'GoodVibes Agent does not own listener lifecycle.',
117
117
  };
118
118
  }
@@ -437,6 +437,7 @@ export const summarizeWorktreeOwnership = shell.summarizeWorktreeOwnership;
437
437
  export const listPersistedWorktreeMeta = shell.listPersistedWorktreeMeta;
438
438
  export const getPersistedWorktreeMeta = shell.getPersistedWorktreeMeta;
439
439
  export const reviewWorktreeAttachments = shell.reviewWorktreeAttachments;
440
+ export const WorktreeRegistry = shell.WorktreeRegistry;
440
441
 
441
442
  export type MutableRuntimeState = Shell.MutableRuntimeState;
442
443
  export type ProviderAccountRecord = Shell.ProviderAccountRecord;