@pellux/goodvibes-agent 1.4.4 → 1.5.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 (230) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +52 -7
  3. package/dist/package/main.js +7491 -12253
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +1 -1
  6. package/docs/getting-started.md +2 -2
  7. package/docs/release-and-publishing.md +1 -1
  8. package/docs/tools-and-commands.md +5 -5
  9. package/package.json +4 -2
  10. package/release/live-verification/live-verification.json +13 -13
  11. package/release/live-verification/live-verification.md +15 -15
  12. package/release/performance-snapshot.json +2 -2
  13. package/release/release-notes.md +5 -7
  14. package/release/release-readiness.json +6 -6
  15. package/src/agent/behavior-discovery-summary.ts +4 -18
  16. package/src/agent/calendar-registry.ts +322 -0
  17. package/src/agent/competitive-feature-inventory.ts +268 -130
  18. package/src/agent/document-registry.ts +5 -1
  19. package/src/agent/email/email-service.ts +350 -0
  20. package/src/agent/email/imap-client.ts +596 -0
  21. package/src/agent/email/smtp-client.ts +453 -0
  22. package/src/agent/ics-calendar.ts +662 -0
  23. package/src/agent/ics-timezone.ts +172 -0
  24. package/src/agent/markdown-frontmatter.ts +31 -0
  25. package/src/agent/memory-safety.ts +1 -1
  26. package/src/agent/note-registry.ts +3 -9
  27. package/src/agent/persona-discovery.ts +3 -15
  28. package/src/agent/persona-registry.ts +1 -10
  29. package/src/agent/research-source-registry.ts +5 -1
  30. package/src/agent/routine-discovery.ts +3 -15
  31. package/src/agent/runtime-profile.ts +3 -0
  32. package/src/agent/skill-discovery.ts +3 -15
  33. package/src/agent/skill-draft-proposer.ts +203 -0
  34. package/src/agent/skill-draft-runner.ts +201 -0
  35. package/src/agent/skill-registry.ts +36 -1
  36. package/src/agent/skill-standard.ts +99 -0
  37. package/src/agent/vibe-file.ts +7 -22
  38. package/src/cli/completion.ts +1 -1
  39. package/src/cli/config-overrides.ts +10 -1
  40. package/src/cli/redaction.ts +17 -5
  41. package/src/config/provider-model.ts +2 -1
  42. package/src/config/secret-config.ts +13 -6
  43. package/src/core/activity-feed.ts +97 -0
  44. package/src/core/away-digest.ts +161 -0
  45. package/src/core/conversation-rendering.ts +7 -3
  46. package/src/core/conversation.ts +22 -15
  47. package/src/core/hardware-profile.ts +362 -0
  48. package/src/core/last-seen-store.ts +78 -0
  49. package/src/core/plain-language.ts +52 -0
  50. package/src/core/setup-incomplete-hint.ts +90 -0
  51. package/src/core/system-message-router.ts +38 -87
  52. package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
  53. package/src/input/agent-workspace-basic-command-editors.ts +39 -141
  54. package/src/input/agent-workspace-categories.ts +40 -125
  55. package/src/input/agent-workspace-command-editor.ts +4 -0
  56. package/src/input/agent-workspace-host-category.ts +0 -5
  57. package/src/input/agent-workspace-local-editor-submission.ts +3 -1
  58. package/src/input/agent-workspace-navigation.ts +10 -3
  59. package/src/input/agent-workspace-onboarding-actions.ts +132 -0
  60. package/src/input/agent-workspace-onboarding-categories.ts +29 -26
  61. package/src/input/agent-workspace-onboarding-finish.ts +11 -4
  62. package/src/input/agent-workspace-onboarding-state.ts +111 -0
  63. package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
  64. package/src/input/agent-workspace-profile-editors.ts +155 -0
  65. package/src/input/agent-workspace-subscription-editor.ts +7 -0
  66. package/src/input/agent-workspace-types.ts +5 -1
  67. package/src/input/agent-workspace.ts +65 -39
  68. package/src/input/command-registry.ts +18 -5
  69. package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
  70. package/src/input/commands/agent-skills-runtime.ts +60 -3
  71. package/src/input/commands/calendar-runtime.ts +209 -0
  72. package/src/input/commands/channels-runtime.ts +1 -0
  73. package/src/input/commands/command-error.ts +9 -0
  74. package/src/input/commands/compat-runtime.ts +1 -0
  75. package/src/input/commands/config.ts +1 -0
  76. package/src/input/commands/conversation-runtime.ts +1 -1
  77. package/src/input/commands/delegation-runtime.ts +5 -6
  78. package/src/input/commands/email-runtime.ts +387 -0
  79. package/src/input/commands/experience-runtime.ts +17 -4
  80. package/src/input/commands/guidance-runtime.ts +1 -1
  81. package/src/input/commands/health-runtime.ts +6 -1
  82. package/src/input/commands/knowledge-format.ts +73 -0
  83. package/src/input/commands/knowledge.ts +9 -74
  84. package/src/input/commands/local-provider-runtime.ts +2 -1
  85. package/src/input/commands/local-runtime.ts +10 -4
  86. package/src/input/commands/mcp-runtime.ts +7 -0
  87. package/src/input/commands/notify-runtime.ts +17 -1
  88. package/src/input/commands/onboarding-runtime.ts +1 -0
  89. package/src/input/commands/operator-actions-runtime.ts +1 -0
  90. package/src/input/commands/operator-runtime.ts +3 -0
  91. package/src/input/commands/personas-runtime.ts +1 -0
  92. package/src/input/commands/platform-access-runtime.ts +40 -17
  93. package/src/input/commands/product-runtime.ts +6 -1
  94. package/src/input/commands/provider-accounts-runtime.ts +3 -2
  95. package/src/input/commands/qrcode-runtime.ts +1 -0
  96. package/src/input/commands/routines-runtime.ts +1 -0
  97. package/src/input/commands/runtime-services.ts +0 -13
  98. package/src/input/commands/security-runtime.ts +1 -0
  99. package/src/input/commands/session-content.ts +1 -0
  100. package/src/input/commands/shell-core.ts +5 -2
  101. package/src/input/commands/subscription-runtime.ts +33 -9
  102. package/src/input/commands/support-bundle-runtime.ts +8 -1
  103. package/src/input/commands/tasks-runtime.ts +1 -0
  104. package/src/input/commands/tts-runtime.ts +1 -0
  105. package/src/input/commands/vibe-runtime.ts +1 -0
  106. package/src/input/commands.ts +4 -0
  107. package/src/input/feed-context-factory.ts +3 -12
  108. package/src/input/handler-command-route.ts +7 -60
  109. package/src/input/handler-feed-routes.ts +0 -194
  110. package/src/input/handler-feed.ts +2 -54
  111. package/src/input/handler-interactions.ts +0 -2
  112. package/src/input/handler-modal-stack.ts +0 -9
  113. package/src/input/handler-picker-routes.ts +24 -1
  114. package/src/input/handler-shortcuts.ts +11 -40
  115. package/src/input/handler-ui-state.ts +13 -0
  116. package/src/input/handler.ts +8 -35
  117. package/src/input/keybindings.ts +40 -17
  118. package/src/input/model-picker-local-fit.ts +130 -0
  119. package/src/input/shell-passthrough.ts +58 -0
  120. package/src/input/submission-router.ts +0 -5
  121. package/src/main.ts +129 -90
  122. package/src/renderer/activity-sidebar.ts +186 -0
  123. package/src/renderer/agent-workspace-context-lines.ts +5 -48
  124. package/src/renderer/agent-workspace-style.ts +1 -1
  125. package/src/renderer/agent-workspace.ts +14 -2
  126. package/src/renderer/compositor.ts +37 -125
  127. package/src/renderer/conversation-overlays.ts +3 -3
  128. package/src/renderer/help-overlay.ts +7 -5
  129. package/src/renderer/model-workspace.ts +101 -86
  130. package/src/{panels → renderer}/polish.ts +3 -3
  131. package/src/renderer/shell-surface.ts +4 -5
  132. package/src/renderer/status-token.ts +31 -11
  133. package/src/renderer/tab-strip.ts +1 -1
  134. package/src/renderer/tool-call.ts +7 -8
  135. package/src/renderer/tool-labels.ts +92 -0
  136. package/src/renderer/ui-factory.ts +48 -96
  137. package/src/runtime/bootstrap-command-context.ts +0 -5
  138. package/src/runtime/bootstrap-command-parts.ts +6 -15
  139. package/src/runtime/bootstrap-core.ts +34 -13
  140. package/src/runtime/bootstrap-hook-bridge.ts +3 -1
  141. package/src/runtime/bootstrap-shell.ts +3 -50
  142. package/src/runtime/bootstrap.ts +3 -4
  143. package/src/runtime/context.ts +1 -1
  144. package/src/runtime/diagnostics/panels/index.ts +0 -1
  145. package/src/runtime/diagnostics/panels/policy.ts +1 -1
  146. package/src/runtime/execution-ledger.ts +16 -1
  147. package/src/runtime/index.ts +6 -1
  148. package/src/runtime/onboarding/index.ts +1 -0
  149. package/src/runtime/onboarding/onboarding-state.ts +200 -0
  150. package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
  151. package/src/runtime/services.ts +16 -4
  152. package/src/runtime/terminal-output-guard.ts +7 -0
  153. package/src/runtime/tool-permission-safety.ts +1 -1
  154. package/src/runtime/ui/model-picker/data-provider.ts +1 -1
  155. package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
  156. package/src/runtime/ui/model-picker/types.ts +2 -2
  157. package/src/runtime/ui/provider-health/data-provider.ts +3 -3
  158. package/src/runtime/ui/provider-health/types.ts +2 -2
  159. package/src/runtime/ui-services.ts +0 -2
  160. package/src/shell/agent-workspace-fullscreen.ts +0 -1
  161. package/src/shell/autonomy-surfacing.ts +272 -0
  162. package/src/shell/session-continuity-hints.ts +0 -6
  163. package/src/shell/startup-wiring.ts +221 -0
  164. package/src/shell/ui-openers.ts +18 -29
  165. package/src/tools/agent-context-policy.ts +1 -1
  166. package/src/tools/agent-harness-background-processes.ts +4 -4
  167. package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
  168. package/src/tools/agent-harness-command-runner.ts +6 -1
  169. package/src/tools/agent-harness-document-ops.ts +26 -53
  170. package/src/tools/agent-harness-execution-history.ts +1 -13
  171. package/src/tools/agent-harness-execution-posture.ts +0 -15
  172. package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
  173. package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
  174. package/src/tools/agent-harness-metadata.ts +16 -0
  175. package/src/tools/agent-harness-mode-catalog.ts +2 -9
  176. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  177. package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
  178. package/src/tools/agent-harness-tool-schema.ts +13 -14
  179. package/src/tools/agent-harness-tool.ts +27 -23
  180. package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
  181. package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
  182. package/src/tools/agent-workspace-tool.ts +2 -33
  183. package/src/utils/terminal-width.ts +9 -3
  184. package/src/version.ts +1 -1
  185. package/src/input/agent-workspace-panel-route.ts +0 -44
  186. package/src/input/panel-integration-actions.ts +0 -26
  187. package/src/panels/approval-panel.ts +0 -149
  188. package/src/panels/automation-control-panel.ts +0 -212
  189. package/src/panels/base-panel.ts +0 -254
  190. package/src/panels/builtin/agent.ts +0 -58
  191. package/src/panels/builtin/knowledge.ts +0 -26
  192. package/src/panels/builtin/operations.ts +0 -121
  193. package/src/panels/builtin/session.ts +0 -138
  194. package/src/panels/builtin/shared.ts +0 -275
  195. package/src/panels/builtin/usage.ts +0 -21
  196. package/src/panels/builtin-panels.ts +0 -23
  197. package/src/panels/confirm-state.ts +0 -61
  198. package/src/panels/context-visualizer-panel.ts +0 -204
  199. package/src/panels/cost-tracker-panel.ts +0 -444
  200. package/src/panels/docs-panel.ts +0 -285
  201. package/src/panels/index.ts +0 -25
  202. package/src/panels/knowledge-panel.ts +0 -417
  203. package/src/panels/memory-panel.ts +0 -226
  204. package/src/panels/panel-list-panel.ts +0 -464
  205. package/src/panels/panel-manager.ts +0 -570
  206. package/src/panels/provider-accounts-panel.ts +0 -233
  207. package/src/panels/provider-health-domains.ts +0 -208
  208. package/src/panels/provider-health-panel.ts +0 -720
  209. package/src/panels/provider-health-tracker.ts +0 -115
  210. package/src/panels/provider-stats-panel.ts +0 -366
  211. package/src/panels/qr-panel.ts +0 -207
  212. package/src/panels/schedule-panel.ts +0 -321
  213. package/src/panels/scrollable-list-panel.ts +0 -491
  214. package/src/panels/search-focus.ts +0 -32
  215. package/src/panels/security-panel.ts +0 -295
  216. package/src/panels/session-browser-panel.ts +0 -395
  217. package/src/panels/session-maintenance.ts +0 -125
  218. package/src/panels/subscription-panel.ts +0 -263
  219. package/src/panels/system-messages-panel.ts +0 -230
  220. package/src/panels/tasks-panel.ts +0 -344
  221. package/src/panels/thinking-panel.ts +0 -304
  222. package/src/panels/token-budget-panel.ts +0 -475
  223. package/src/panels/tool-inspector-panel.ts +0 -436
  224. package/src/panels/types.ts +0 -54
  225. package/src/renderer/panel-composite.ts +0 -158
  226. package/src/renderer/panel-tab-bar.ts +0 -69
  227. package/src/renderer/panel-workspace-bar.ts +0 -42
  228. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  229. package/src/tools/agent-harness-panel-metadata.ts +0 -211
  230. /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
@@ -3,9 +3,10 @@ import { LAYOUT, TOOL_STATUS } from './layout.ts';
3
3
  import { getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
4
4
  import type { ToolCall } from '@pellux/goodvibes-sdk/platform/types';
5
5
  import { stripDangerousAnsi } from './ansi-sanitize.ts';
6
+ import { friendlyToolLabel } from './tool-labels.ts';
6
7
 
7
8
  const TOOL_NAME_MIN_WIDTH = 8;
8
- const TOOL_NAME_MAX_WIDTH = 20;
9
+ const TOOL_NAME_MAX_WIDTH = 30;
9
10
 
10
11
  function isRecord(value: unknown): value is Record<string, unknown> {
11
12
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
@@ -137,11 +138,11 @@ function extractKeyArg(toolCall: ToolCall): string {
137
138
  if (url) return url;
138
139
  }
139
140
  // Agent
140
- if (typeof args.task === 'string') return args.task.slice(0, 40);
141
+ if (typeof args.task === 'string') return [...args.task].slice(0, 40).join('');
141
142
  if (typeof args.mode === 'string') return args.mode;
142
143
  // Fallback: first string value
143
144
  for (const val of Object.values(args)) {
144
- if (typeof val === 'string' && val.length > 0) return val.slice(0, 40);
145
+ if (typeof val === 'string' && val.length > 0) return [...val].slice(0, 40).join('');
145
146
  }
146
147
  return '';
147
148
  }
@@ -200,13 +201,11 @@ export function renderToolCallBlock(
200
201
  }
201
202
  col += 2; // icon + space
202
203
 
203
- // Tool name — extract short name for long MCP tool names, but keep a readable dynamic width.
204
- const rawName = toolCall.name.includes('__')
205
- ? toolCall.name.split('__').pop()!
206
- : toolCall.name;
204
+ // Human phrase for the tool ("Searching the web") instead of the raw name.
205
+ const rawName = friendlyToolLabel(toolCall.name);
207
206
  const keyArg = stripDangerousAnsi(extractKeyArg(toolCall));
208
207
  const suffixText = status === 'error' && errorMsg
209
- ? `- ${stripDangerousAnsi(errorMsg).slice(0, 40)}`
208
+ ? `- ${[...stripDangerousAnsi(errorMsg)].slice(0, 40).join('')}`
210
209
  : status === 'done' && resultSummary
211
210
  ? `(${stripDangerousAnsi(resultSummary)})`
212
211
  : '';
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Friendly tool labels — turn internal tool names into the phrase a person
3
+ * would say. Shown on tool-call lines in the conversation; the raw tool name
4
+ * is still discoverable in the Agent workspace tool catalog.
5
+ */
6
+
7
+ const TOOL_LABELS: Record<string, string> = {
8
+ // SDK file/shell/web tools
9
+ read: 'Reading files',
10
+ write: 'Writing a file',
11
+ edit: 'Editing a file',
12
+ exec: 'Running a command',
13
+ fetch: 'Fetching a web page',
14
+ web_search: 'Searching the web',
15
+ find: 'Searching files',
16
+ analyze: 'Analyzing code',
17
+ inspect: 'Inspecting files',
18
+
19
+ // Agent first-class tools
20
+ personal_ops: 'Checking your inbox & calendar',
21
+ research: 'Researching',
22
+ agent_research_runs: 'Researching',
23
+ agent_research_sources: 'Reviewing sources',
24
+ agent_research_report: 'Writing a research report',
25
+ schedule: 'Checking schedules',
26
+ agent_schedule_edit: 'Updating a schedule',
27
+ agent_autonomy_schedule: 'Scheduling background work',
28
+ agent_reminder_schedule: 'Setting a reminder',
29
+ autonomy: 'Checking background work',
30
+ channels: 'Checking message channels',
31
+ agent_channel_send: 'Sending a message',
32
+ notify: 'Sending a notification',
33
+ memory: 'Recalling memory',
34
+ agent_knowledge: 'Searching knowledge',
35
+ agent_knowledge_ingest: 'Saving to knowledge',
36
+ agent_learning_consolidation: 'Consolidating what I learned',
37
+ agent_local_registry: 'Checking notes & routines',
38
+ models: 'Checking models',
39
+ agent_model_compare: 'Comparing models',
40
+ settings: 'Adjusting settings',
41
+ agent_settings_import: 'Importing settings',
42
+ setup: 'Checking setup',
43
+ security: 'Reviewing safety',
44
+ sessions: 'Looking at past conversations',
45
+ computer: 'Using the browser',
46
+ device: 'Checking this device',
47
+ host: 'Checking the assistant service',
48
+ execution: 'Managing background work',
49
+ terminal_process: 'Watching a process',
50
+ support: 'Preparing a support bundle',
51
+ vibe: 'Reading your VIBE profile',
52
+ workspace: 'Driving the workspace',
53
+ agent_harness: 'Checking app internals',
54
+ route: 'Choosing the best route',
55
+ delegation: 'Handing work off',
56
+ audit: 'Reviewing evidence',
57
+ context: 'Reading project context',
58
+ agent_documents: 'Working on a document',
59
+ agent_artifacts: 'Managing saved files',
60
+ agent_media_generate: 'Generating media',
61
+ agent_operator_method: 'Calling the assistant service',
62
+ agent_operator_briefing: 'Preparing a briefing',
63
+ agent_operator_action: 'Running an approved action',
64
+ agent_work_plan: 'Organizing work',
65
+ agent_review_packet_presets: 'Preparing a review packet',
66
+ agent_review_packet_share: 'Sharing a review packet',
67
+ propose_skill_drafts: 'Proposing skill drafts',
68
+ };
69
+
70
+ /**
71
+ * Exported catalog of all registered tool IDs and their human phrases.
72
+ * Tests import this to enumerate the full set of tool IDs for coverage checks.
73
+ */
74
+ export const TOOL_LABELS_CATALOG: Readonly<Record<string, string>> = TOOL_LABELS;
75
+
76
+ function humanize(name: string): string {
77
+ const short = name.includes('__') ? name.split('__').pop()! : name;
78
+ return (short
79
+ .replace(/^agent[_-]/, '')
80
+ .replace(/[_-]+/g, ' ')
81
+ .trim())
82
+ .replace(/^./, (c) => c.toUpperCase());
83
+ }
84
+
85
+ /**
86
+ * Return the human phrase for a tool call, falling back to a humanized
87
+ * version of the raw name for unknown tools (including MCP tools).
88
+ */
89
+ export function friendlyToolLabel(toolName: string): string {
90
+ const short = toolName.includes('__') ? toolName.split('__').pop()! : toolName;
91
+ return TOOL_LABELS[short] ?? TOOL_LABELS[toolName] ?? humanize(toolName);
92
+ }
@@ -215,113 +215,65 @@ export class UIFactory {
215
215
  const bottomLine = createBaseLine();
216
216
  for (let x = 0; x < boxWidth; x++) bottomLine[boxStartX + x] = { char: GLYPHS.surface.bottom, fg: BORDER_COLOR, bg: '', bold: false, dim: false, underline: false, italic: false, strikethrough: false };
217
217
  lines.push(bottomLine);
218
- lines.push(createBaseLine());
219
- const composerTokens: Array<{ text: string; fg: string; bold?: boolean; dim?: boolean }> = [];
220
- if (composerMode) composerTokens.push({ text: ` ${GLYPHS.status.active} ${composerMode} `, fg: '#38bdf8', bold: true });
221
- if (composerPendingRisk && composerPendingRisk !== 'none') {
222
- const riskColor = composerPendingRisk === 'approval-wait'
223
- ? '#f59e0b'
224
- : composerPendingRisk === 'shell'
225
- ? '#ef4444'
226
- : composerPendingRisk === 'remote'
227
- ? '#a78bfa'
228
- : '#f59e0b';
229
- composerTokens.push({ text: ` risk:${composerPendingRisk} `, fg: riskColor, bold: true });
230
- }
231
- if (composerStatus && composerStatus !== 'idle') composerTokens.push({ text: ` state:${composerStatus} `, fg: '244', dim: true });
232
- if (composerFlags && composerFlags.length > 0) composerTokens.push({ text: ` flags:${composerFlags.join(',')} `, fg: '244', dim: true });
233
- if (composerTokens.length > 0) {
234
- const postureLine = createBaseLine();
235
- let px = 2;
236
- for (const token of composerTokens) {
237
- for (const ch of token.text) {
238
- if (px >= width) break;
239
- postureLine[px] = {
240
- char: ch,
241
- fg: token.fg,
242
- bg: '',
243
- bold: token.bold ?? false,
244
- dim: token.dim ?? false,
245
- underline: false,
246
- italic: false,
247
- strikethrough: false,
248
- };
249
- px += getDisplayWidth(ch);
250
- }
251
- if (px >= width) break;
252
- }
253
- lines.push(postureLine);
254
- lines.push(createBaseLine());
255
- }
218
+
219
+ // ── Status line: model · context meter · tokens, with alerts on the right ──
256
220
  const isRecentlyCopied = Date.now() - lastCopyTime < 2000;
257
- // Token usage line
258
- const u = usage as { input?: number; output?: number; cacheRead?: number; cacheWrite?: number; up?: number; down?: number };
221
+ const u = usage as { input?: number; output?: number; up?: number; down?: number };
259
222
  const inp = u.input ?? u.up ?? 0;
260
223
  const out = u.output ?? u.down ?? 0;
261
- const cr = u.cacheRead ?? 0;
262
- const cw = u.cacheWrite ?? 0;
263
- const total = inp + out + cr + cw;
264
- const tokenSep = ` ${GLYPHS.navigation.pipeSeparator} `;
265
- const tokenLine = ` Token Usage [ Input: ${fmtNum(inp)}${tokenSep}Output: ${fmtNum(out)}${tokenSep}Cache Read: ${fmtNum(cr)}${tokenSep}Cache Write: ${fmtNum(cw)}${tokenSep}Total: ${fmtNum(total)} ]`;
266
- const copiedNotice = isRecentlyCopied ? ` [COPIED] ` : '';
267
- const statsLine = ' ' + tokenLine + ' '.repeat(Math.max(0, width - 4 - getDisplayWidth(tokenLine) - getDisplayWidth(copiedNotice))) + copiedNotice;
268
- lines.push(this.stringToLine(statsLine, width, { fg: isRecentlyCopied ? '81' : '244', bold: isRecentlyCopied }));
269
- // Context usage progress bar
224
+ const statusTokens: Array<{ text: string; fg: string; bold?: boolean }> = [];
225
+ if (model) {
226
+ statusTokens.push({ text: provider ? `${model} · ${provider}` : model, fg: '245' });
227
+ }
270
228
  if (contextWindow && contextWindow > 0) {
271
229
  const ctxTokens = lastInputTokens ?? 0;
272
- const label = ' Context Usage: ';
273
- const suffix = ` [ ${fmtNum(ctxTokens)} / ${fmtNum(contextWindow)} ]`;
274
- const barWidth = Math.max(10, Math.min(30, width - getDisplayWidth(label) - getDisplayWidth(suffix) - 8));
275
- const ctxPct = Math.min(1, ctxTokens / contextWindow);
276
- lines.push(createBaseLine());
277
- lines.push(this.createProgressBarLine(label, ctxPct, barWidth, width, suffix));
230
+ const pct = Math.min(100, Math.round((ctxTokens / contextWindow) * 100));
231
+ const filled = Math.round((pct / 100) * 6);
232
+ const meter = GLYPHS.meter.filled.repeat(filled) + GLYPHS.meter.empty.repeat(6 - filled);
233
+ const meterFg = pct >= 85 ? '#ef4444' : pct >= 65 ? '#f59e0b' : '240';
234
+ statusTokens.push({ text: `context ${meter} ${pct}%`, fg: meterFg, bold: pct >= 85 });
235
+ }
236
+ if (inp > 0 || out > 0) {
237
+ statusTokens.push({ text: `↑${fmtNum(inp)} ↓${fmtNum(out)}`, fg: '240' });
238
+ }
239
+ if (composerPendingRisk === 'approval-wait') {
240
+ statusTokens.push({ text: 'waiting for your approval', fg: '#f59e0b', bold: true });
278
241
  }
279
- // Context info line (working dir, model+provider, tools)
280
- if (workingDir || model) {
281
- const home = typeof process !== 'undefined' ? process.env.HOME ?? '' : '';
282
- const displayDir = workingDir && home && workingDir.startsWith(home)
283
- ? '~' + workingDir.slice(home.length)
284
- : workingDir ?? '';
285
- const ctxParts: string[] = [];
286
- if (displayDir) ctxParts.push(displayDir);
287
- if (model) {
288
- ctxParts.push(model + (provider ? ` (${provider})` : ''));
242
+ const rightNotice = isRecentlyCopied
243
+ ? { text: `copied ${GLYPHS.status.success} `, fg: '81', bold: true }
244
+ : dangerMode
245
+ ? { text: '⚠ auto-approve is on ', fg: '#ef4444', bold: true }
246
+ : null;
247
+ const statusLine = createBaseLine();
248
+ let sx = 3;
249
+ const writeStatusText = (text: string, fg: string, bold = false) => {
250
+ for (const ch of text) {
251
+ if (sx >= width - 1) break;
252
+ statusLine[sx] = { char: ch, fg, bg: '', bold, dim: false, underline: false, italic: false, strikethrough: false };
253
+ sx += getDisplayWidth(ch);
254
+ }
255
+ };
256
+ statusTokens.forEach((token, index) => {
257
+ if (index > 0) writeStatusText(` ${GLYPHS.navigation.pipeSeparator} `, '238');
258
+ writeStatusText(token.text, token.fg, token.bold ?? false);
259
+ });
260
+ if (rightNotice) {
261
+ let col = Math.max(sx + 2, width - getDisplayWidth(rightNotice.text));
262
+ for (const ch of rightNotice.text) {
263
+ if (col >= width) break;
264
+ statusLine[col] = { char: ch, fg: rightNotice.fg, bg: '', bold: rightNotice.bold ?? false, dim: false, underline: false, italic: false, strikethrough: false };
265
+ col += getDisplayWidth(ch);
289
266
  }
290
- if (toolCount) ctxParts.push(`${toolCount} tools`);
291
- if (hitlMode) ctxParts.push(`hitl:${hitlMode}`);
292
- if (composerMode) ctxParts.push(`mode:${composerMode}`);
293
- if (composerStatus && composerStatus !== 'idle') ctxParts.push(`status:${composerStatus}`);
294
- if (composerFlags && composerFlags.length > 0) ctxParts.push(composerFlags.join(','));
295
- const ctxLine = ' ' + ctxParts.join(` ${GLYPHS.navigation.pipeSeparator} `);
296
- lines.push(createBaseLine());
297
- lines.push(this.stringToLine(truncateDisplay(ctxLine, width), width, { fg: '240', dim: true }));
298
- lines.push(createBaseLine());
299
267
  }
268
+ lines.push(statusLine);
269
+
270
+ // ── Hints line ──
300
271
  if (showExitNotice) {
301
- const notice = ` !!! Press Ctrl+C again to exit !!! `;
302
- lines.push(this.stringToLine(fitDisplay(notice, width), width, { fg: '196', bold: true }));
272
+ lines.push(this.stringToLine(fitDisplay(' Press Ctrl+C again to exit ', width), width, { fg: '196', bold: true }));
303
273
  } else {
304
- const help = ` /help for commands - Ctrl+C to quit `;
305
- const dangerWarn = dangerMode ? `! DANGER MODE - ALL CHANGES AUTO-APPROVED ` : '';
306
- const helpW = getDisplayWidth(help);
307
- const dangerW = getDisplayWidth(dangerWarn);
308
- const spacerW = Math.max(0, width - helpW - dangerW);
309
- const combinedLine = help + ' '.repeat(spacerW) + dangerWarn;
310
- const line = this.stringToLine(truncateDisplay(combinedLine, width), width, { fg: '240', dim: true });
311
- // Overlay the danger warning in red bold
312
- if (dangerMode && dangerW > 0) {
313
- let col = helpW + spacerW;
314
- for (const ch of dangerWarn) {
315
- if (col >= width) break;
316
- const cw = getDisplayWidth(ch);
317
- line[col] = { char: ch, fg: '#ef4444', bg: '', bold: true, dim: false, underline: false, italic: false, strikethrough: false };
318
- if (cw === 2 && col + 1 < width) line[col + 1] = { ...line[col], char: '' };
319
- col += cw;
320
- }
321
- }
322
- lines.push(line);
274
+ const hints = ` /help commands ${GLYPHS.navigation.pipeSeparator} Ctrl+P settings ${GLYPHS.navigation.pipeSeparator} Ctrl+O activity `;
275
+ lines.push(this.stringToLine(truncateDisplay(hints, width), width, { fg: '240', dim: true }));
323
276
  }
324
- lines.push(createBaseLine());
325
277
  return lines;
326
278
  }
327
279
 
@@ -4,7 +4,6 @@ import type { ConversationManager } from '../core/conversation';
4
4
  import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
5
5
  import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
6
6
  import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
7
- import type { PanelManager } from '../panels/panel-manager.ts';
8
7
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
9
8
  import type { OpsApi } from '@/runtime/index.ts';
10
9
  import type { MutableRuntimeState } from '@/runtime/index.ts';
@@ -116,7 +115,6 @@ export type CreateBootstrapCommandContextOptions = {
116
115
  mcpApi?: McpApi;
117
116
  opsApi?: OpsApi;
118
117
  directTransport?: DirectTransport;
119
- panelManager: PanelManager;
120
118
  worktreeRegistry: WorktreeRegistry;
121
119
  sandboxSessionRegistry: SandboxSessionRegistry;
122
120
  loadSystemPrompt: () => string;
@@ -192,7 +190,6 @@ export function createBootstrapCommandContext(
192
190
  mcpApi,
193
191
  opsApi,
194
192
  directTransport,
195
- panelManager,
196
193
  worktreeRegistry,
197
194
  sandboxSessionRegistry,
198
195
  loadSystemPrompt,
@@ -247,7 +244,6 @@ export function createBootstrapCommandContext(
247
244
  const workspace = createBootstrapCommandWorkspaceSection({
248
245
  keybindingsManager,
249
246
  fileUndoManager,
250
- panelManager,
251
247
  processManager,
252
248
  profileManager,
253
249
  bookmarkManager,
@@ -277,7 +273,6 @@ export function createBootstrapCommandContext(
277
273
  conversation,
278
274
  runtime,
279
275
  requestRender,
280
- panelManager,
281
276
  loadSystemPrompt,
282
277
  activatePlan,
283
278
  requestPermission,
@@ -6,7 +6,6 @@ import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
6
6
  import type { AgentPromptContextReceiptStore } from '../agent/prompt-context-receipts.ts';
7
7
  import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
8
8
  import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
9
- import type { PanelManager } from '../panels/panel-manager.ts';
10
9
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
11
10
  import type { OpsApi } from '@/runtime/index.ts';
12
11
  import type { MutableRuntimeState } from '@/runtime/index.ts';
@@ -62,7 +61,6 @@ export interface BootstrapCommandActionOptions {
62
61
  readonly conversation: ConversationManager;
63
62
  readonly runtime: MutableRuntimeState;
64
63
  readonly requestRender: () => void;
65
- readonly panelManager: PanelManager;
66
64
  readonly loadSystemPrompt: () => string;
67
65
  readonly activatePlan: (planId: string, task: string) => void;
68
66
  readonly requestPermission: PermissionRequestHandler;
@@ -76,7 +74,6 @@ export interface BootstrapCommandSectionOptions {
76
74
  readonly runtime: MutableRuntimeState;
77
75
  readonly keybindingsManager?: KeybindingsManager;
78
76
  readonly processManager?: import('@pellux/goodvibes-sdk/platform/tools').ProcessManager;
79
- readonly panelManager: PanelManager;
80
77
  readonly requestRender: () => void;
81
78
  readonly requestPermission: PermissionRequestHandler;
82
79
  readonly toolRegistry: ToolRegistry;
@@ -158,7 +155,6 @@ export function createBootstrapCommandActions(
158
155
  | 'print'
159
156
  | 'exit'
160
157
  | 'reloadSystemPrompt'
161
- | 'showPanel'
162
158
  | 'openMcpWorkspace'
163
159
  | 'openAgentWorkspace'
164
160
  | 'dismissAgentWorkspace'
@@ -172,17 +168,14 @@ export function createBootstrapCommandActions(
172
168
  conversation,
173
169
  runtime,
174
170
  requestRender,
175
- panelManager,
176
171
  loadSystemPrompt,
177
172
  activatePlan,
178
173
  requestPermission,
179
174
  completeModelSelectionSideEffect,
180
175
  } = options;
181
176
 
182
- const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
183
- void pane;
184
- panelManager.hide();
185
- conversation.log(`Panel route "${panelId}" is handled through Agent Workspace. Use /agent for current operator controls.`, { fg: '214' });
177
+ const pointToWorkspace = (what: string) => {
178
+ conversation.log(`${what} lives in the Agent workspace — press Ctrl+P or run /agent.`, { fg: '214' });
186
179
  requestRender();
187
180
  };
188
181
 
@@ -246,18 +239,17 @@ export function createBootstrapCommandActions(
246
239
  },
247
240
  exit: () => unwiredShellAction('exit'),
248
241
  reloadSystemPrompt: loadSystemPrompt,
249
- showPanel,
250
242
  openMcpWorkspace: () => unwiredShellAction('openMcpWorkspace'),
251
243
  openAgentWorkspace: () => unwiredShellAction('openAgentWorkspace'),
252
244
  dismissAgentWorkspace: () => unwiredShellAction('dismissAgentWorkspace'),
253
245
  openSecurityPanel: () => {
254
- showPanel('security');
246
+ pointToWorkspace('Security review');
255
247
  },
256
248
  openKnowledgePanel: () => {
257
- showPanel('knowledge');
249
+ pointToWorkspace('Knowledge');
258
250
  },
259
251
  openSubscriptionPanel: () => {
260
- showPanel('subscription');
252
+ pointToWorkspace('Provider subscriptions');
261
253
  },
262
254
  };
263
255
  }
@@ -295,7 +287,7 @@ export function createBootstrapCommandProviderSection(
295
287
  export function createBootstrapCommandWorkspaceSection(
296
288
  options: Pick<
297
289
  BootstrapCommandSectionOptions,
298
- 'keybindingsManager' | 'fileUndoManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
290
+ 'keybindingsManager' | 'fileUndoManager' | 'profileManager' | 'bookmarkManager'
299
291
  | 'processManager' | 'projectPlanningService' | 'projectPlanningProjectId' | 'workPlanStore'
300
292
  >,
301
293
  shellServices: BootstrapCommandShellServices,
@@ -303,7 +295,6 @@ export function createBootstrapCommandWorkspaceSection(
303
295
  return {
304
296
  keybindingsManager: options.keybindingsManager,
305
297
  fileUndoManager: options.fileUndoManager,
306
- panelManager: options.panelManager,
307
298
  processManager: options.processManager,
308
299
  profileManager: options.profileManager,
309
300
  bookmarkManager: options.bookmarkManager,
@@ -6,8 +6,8 @@ import { getProviderIdFromModel } from '../config/provider-model.ts';
6
6
  import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
7
7
  import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools';
8
8
  import { PermissionManager, createPermissionConfigReader } from '@pellux/goodvibes-sdk/platform/permissions';
9
- import { Notifier } from '@pellux/goodvibes-sdk/platform/integrations';
10
- import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
9
+ import { Notifier, WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
10
+
11
11
  import { Compositor } from '../renderer/compositor.ts';
12
12
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
13
13
  import type { SystemMessageRouter } from '../core/system-message-router.ts';
@@ -94,6 +94,26 @@ export interface BootstrapCoreState {
94
94
 
95
95
  export type CompanionMessagePayload = Extract<SessionEvent, { type: 'COMPANION_MESSAGE_RECEIVED' }>;
96
96
 
97
+ /**
98
+ * Registers the webhook notifier for the runtime session.
99
+ *
100
+ * Configures the provided WebhookNotifier with the given URL list, attaches it
101
+ * to the runtime bus so it receives SESSION_NOTIFICATION events, and pushes a
102
+ * detach() cleanup into runtimeUnsubs for shutdown. When webhookUrls is empty
103
+ * this function is a complete no-op.
104
+ */
105
+ export function registerWebhookNotifier(
106
+ webhookNotifier: WebhookNotifier,
107
+ webhookUrls: string[],
108
+ runtimeBus: RuntimeEventBus,
109
+ runtimeUnsubs: Array<() => void>,
110
+ ): void {
111
+ if (webhookUrls.length === 0) return;
112
+ webhookNotifier.setUrls(webhookUrls);
113
+ webhookNotifier.attachToRuntimeBus(runtimeBus);
114
+ runtimeUnsubs.push(() => webhookNotifier.detach());
115
+ }
116
+
97
117
  export function companionMessageToOrchestratorInputOptions(
98
118
  payload: CompanionMessagePayload,
99
119
  ): OrchestratorUserInputOptions {
@@ -161,7 +181,7 @@ export async function initializeBootstrapCore(
161
181
  sessionId: userSessionId,
162
182
  authenticatedAt: Date.now(),
163
183
  lastSeenAt: Date.now(),
164
- capabilities: ['session', 'panels', 'commands', 'automation'],
184
+ capabilities: ['session', 'commands', 'automation'],
165
185
  metadata: {
166
186
  product: 'goodvibes-agent',
167
187
  surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
@@ -176,7 +196,6 @@ export async function initializeBootstrapCore(
176
196
  hookDispatcher,
177
197
  hookWorkbench,
178
198
  memoryStore,
179
- panelManager,
180
199
  routeBindings,
181
200
  sessionBroker: sharedSessionBroker,
182
201
  surfaceRegistry,
@@ -215,13 +234,7 @@ export async function initializeBootstrapCore(
215
234
  getControlPlaneRecentEvents,
216
235
  });
217
236
 
218
- const conversation = new ConversationManager(() => {
219
- const width = getTerminalSize(stdout).width;
220
- if (panelManager.isVisible() && panelManager.getAllOpen().length > 0) {
221
- return Math.max(1, panelManager.getLeftWidth(width) - 1);
222
- }
223
- return width;
224
- });
237
+ const conversation = new ConversationManager(() => getTerminalSize(stdout).width);
225
238
  conversation.setConfigManager(configManager);
226
239
  getConversationTitle = () => conversation.title;
227
240
 
@@ -321,6 +334,11 @@ export async function initializeBootstrapCore(
321
334
  });
322
335
 
323
336
  const bootstrapUnsubs: Array<() => void> = [];
337
+ // D5 fix: stop the heartbeat watcher on shutdown so the setInterval is cleared.
338
+ // Registered here (after declaration) rather than inside the watcher block above.
339
+ if (configManager.get('watchers.enabled')) {
340
+ bootstrapUnsubs.push(() => watcherRegistry.stopWatcher('runtime-heartbeat'));
341
+ }
324
342
  await memoryStore.init();
325
343
  bootstrapUnsubs.push(() => {
326
344
  void memoryStore.save();
@@ -420,8 +438,11 @@ export async function initializeBootstrapCore(
420
438
 
421
439
  const webhookUrls = (configManager.getCategory('notifications') as { webhookUrls?: string[] }).webhookUrls ?? [];
422
440
  if (webhookUrls.length > 0) {
423
- const webhookNotifier = WebhookNotifier.fromConfig(webhookUrls);
424
- webhookNotifier.attachToRuntimeBus(runtimeBus);
441
+ // Reuse the services.webhookNotifier instance (constructed no-arg in services.ts).
442
+ // Configure it with the resolved URL list via setUrls(), attach it to the runtime
443
+ // bus so it receives SESSION_NOTIFICATION events, and register detach() in
444
+ // runtimeUnsubs so the bus subscription is cleaned up on shutdown.
445
+ registerWebhookNotifier(services.webhookNotifier, webhookUrls, runtimeBus, runtimeUnsubs);
425
446
  domainDispatch.syncIntegration({
426
447
  id: 'webhooks',
427
448
  displayName: 'Webhooks',
@@ -52,9 +52,11 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
52
52
  options.writeLastSessionPointer(sessionId);
53
53
  void options.sharedSessionBroker.reopenSession(sessionId).catch((err) => { logger.debug('session broker reopen session failed', { err }); });
54
54
  options.conversation.log(`Resumed session: ${sessionId}`, { fg: '135' });
55
- const ignoredPanels = meta.returnContext?.openPanels?.slice(0, 4) ?? [];
56
55
  const returnContextMode = getReturnContextMode(options.configManager);
57
56
  if (returnContextMode !== 'off' && meta.returnContext) {
57
+ // N1 fix: compute ignoredPanels inside the guard so it is only evaluated
58
+ // when returnContext is present and the mode is not 'off'.
59
+ const ignoredPanels = meta.returnContext.openPanels?.slice(0, 4) ?? [];
58
60
  for (const line of formatReturnContextForDisplay(meta.returnContext)) {
59
61
  if (line.startsWith('Open panels:')) continue;
60
62
  options.conversation.log(`Resume: ${line}`, { fg: '244' });
@@ -13,8 +13,7 @@ import { CommandRegistry } from '../input/command-registry.ts';
13
13
  import { registerBuiltinCommands } from '../input/commands.ts';
14
14
  import { InputHistory } from '../input/input-history.ts';
15
15
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
16
- import { registerBuiltinPanels } from '../panels/builtin-panels.ts';
17
- import { SystemMessagesPanel } from '../panels/system-messages-panel.ts';
16
+ import { ActivityFeed } from '../core/activity-feed.ts';
18
17
  import { createSystemMessageRouter, type SystemMessageRouter } from '../core/system-message-router.ts';
19
18
  import { getConfigSnapshot } from '../config/index.ts';
20
19
  import { createBootstrapCommandContext } from './bootstrap-command-context.ts';
@@ -24,7 +23,6 @@ import { loadBootstrapSystemPrompt } from '@/runtime/index.ts';
24
23
  import { createShellPlanRuntime, createShellRemoteCommandService } from '@/runtime/index.ts';
25
24
  import { createRuntimeFoundationClients } from '@/runtime/index.ts';
26
25
  import type { ControlPlaneRecentEvent } from '@pellux/goodvibes-sdk/platform/control-plane';
27
- import type { BuiltinPanelDeps } from '../panels/builtin/shared.ts';
28
26
  import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
29
27
  import type { ForensicsRegistry } from '@/runtime/index.ts';
30
28
  import type { PolicyRuntimeState } from '@/runtime/index.ts';
@@ -125,7 +123,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
125
123
  completeModelSelectionSideEffect,
126
124
  } = options;
127
125
 
128
- const systemMessagesPanel = new SystemMessagesPanel(configManager, services.componentHealthMonitor);
126
+ const activityFeed = new ActivityFeed();
129
127
  const resumeSession = createResumeSessionHandler({
130
128
  runtimeBus,
131
129
  runtime,
@@ -141,54 +139,10 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
141
139
  });
142
140
 
143
141
  let commandContextRef: CommandContext | null = null;
144
- registerBuiltinPanels(services.panelManager, {
145
- configManager,
146
- getOrchestratorUsage: () => orchestrator.usage as { input: number; output: number; cacheRead: number; cacheWrite: number; model?: string },
147
- toolRegistry,
148
- providerRegistry: services.providerRegistry,
149
- contextWindow: services.providerRegistry.getContextWindowForModel(services.providerRegistry.getCurrentModel()),
150
- orchestrator,
151
- getCtxWindow: () => services.providerRegistry.getContextWindowForModel(services.providerRegistry.getCurrentModel()),
152
- resumeSession,
153
- requestRender,
154
- submitPlanningAnswer: (answer) => {
155
- submitPlanningAnswerWithShellFallback(answer, {
156
- getSubmitInput: () => commandContextRef?.submitInput,
157
- addSystemMessage: (message) => conversation.addSystemMessage(message),
158
- requestRender,
159
- });
160
- },
161
- dismissPlanning: () => {
162
- services.panelManager.close('project-planning');
163
- commandContextRef?.focusPrompt?.();
164
- requestRender();
165
- },
166
- forensicsRegistry,
167
- policyRuntimeState,
168
- approvalBroker: services.approvalBroker,
169
- sessionBroker: services.sessionBroker,
170
- automationManager: services.automationManager,
171
- getControlPlaneRecentEvents,
172
- tokenAuditor: services.tokenAuditor,
173
- componentHealthMonitor: services.componentHealthMonitor,
174
- worktreeRegistry: services.worktreeRegistry,
175
- sandboxSessionRegistry: services.sandboxSessionRegistry,
176
- systemMessagesPanel,
177
- memoryRegistry: services.memoryRegistry,
178
- agentKnowledgeService: services.agentKnowledgeService,
179
- uiServices,
180
- pluginManager: services.pluginManager,
181
- hookDispatcher: services.hookDispatcher,
182
- hookActivityTracker: services.hookActivityTracker,
183
- hookWorkbench: services.hookWorkbench,
184
- mcpRegistry: services.mcpRegistry,
185
- connectedHostTokenDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
186
- });
187
- services.panelManager.prewarmRegistered();
188
142
 
189
143
  const systemMessageRouter = createSystemMessageRouter(
190
144
  conversation,
191
- systemMessagesPanel,
145
+ activityFeed,
192
146
  (kind) => {
193
147
  const ui = getConfigSnapshot(configManager).ui;
194
148
  if (kind === 'wrfc') return ui.wrfcMessages;
@@ -287,7 +241,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
287
241
  mcpApi,
288
242
  opsApi,
289
243
  directTransport,
290
- panelManager: services.panelManager,
291
244
  worktreeRegistry: services.worktreeRegistry,
292
245
  sandboxSessionRegistry: services.sandboxSessionRegistry,
293
246
  loadSystemPrompt: () => loadBootstrapSystemPrompt(configManager),