@pellux/goodvibes-tui 1.1.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/CHANGELOG.md +85 -21
  2. package/README.md +28 -18
  3. package/docs/foundation-artifacts/operator-contract.json +4045 -1763
  4. package/package.json +2 -2
  5. package/src/audio/spoken-turn-controller.ts +12 -2
  6. package/src/audio/spoken-turn-wiring.ts +2 -1
  7. package/src/cli/help.ts +8 -1
  8. package/src/cli/service-posture.ts +2 -1
  9. package/src/cli/status.ts +2 -1
  10. package/src/cli/surface-command.ts +2 -2
  11. package/src/core/alert-gating.ts +67 -0
  12. package/src/core/approval-alert.ts +72 -0
  13. package/src/core/budget-breach-notifier.ts +106 -0
  14. package/src/core/composer-state.ts +11 -3
  15. package/src/core/conversation-line-cache.ts +27 -3
  16. package/src/core/conversation-rendering.ts +90 -14
  17. package/src/core/conversation.ts +18 -0
  18. package/src/core/focus-tracker.ts +41 -0
  19. package/src/core/long-task-notifier.ts +33 -6
  20. package/src/core/stream-event-wiring.ts +20 -1
  21. package/src/core/system-message-noise.ts +87 -0
  22. package/src/core/system-message-router.ts +104 -51
  23. package/src/core/turn-cancellation.ts +25 -0
  24. package/src/core/turn-event-wiring.ts +72 -3
  25. package/src/daemon/cli.ts +29 -2
  26. package/src/daemon/handlers/register.ts +8 -1
  27. package/src/daemon/service-commands.ts +329 -0
  28. package/src/export/cost-utils.ts +36 -0
  29. package/src/input/autocomplete.ts +27 -1
  30. package/src/input/command-registry.ts +84 -5
  31. package/src/input/commands/checkpoint-runtime.ts +280 -0
  32. package/src/input/commands/codebase-runtime.ts +232 -0
  33. package/src/input/commands/config.ts +43 -3
  34. package/src/input/commands/eval.ts +1 -1
  35. package/src/input/commands/health-runtime.ts +10 -2
  36. package/src/input/commands/image-runtime.ts +112 -0
  37. package/src/input/commands/intelligence-runtime.ts +11 -1
  38. package/src/input/commands/local-auth-runtime.ts +4 -1
  39. package/src/input/commands/local-runtime.ts +9 -3
  40. package/src/input/commands/marketplace-runtime.ts +2 -2
  41. package/src/input/commands/memory.ts +73 -35
  42. package/src/input/commands/operator-panel-runtime.ts +71 -31
  43. package/src/input/commands/planning-runtime.ts +116 -4
  44. package/src/input/commands/platform-sandbox-runtime.ts +1 -6
  45. package/src/input/commands/plugin-runtime.ts +2 -2
  46. package/src/input/commands/policy-dispatch.ts +21 -0
  47. package/src/input/commands/provider-accounts-runtime.ts +1 -1
  48. package/src/input/commands/qrcode-runtime.ts +26 -6
  49. package/src/input/commands/recall-review.ts +35 -0
  50. package/src/input/commands/remote-runtime-setup.ts +5 -3
  51. package/src/input/commands/remote-runtime.ts +3 -3
  52. package/src/input/commands/runtime-services.ts +54 -13
  53. package/src/input/commands/services-runtime.ts +1 -1
  54. package/src/input/commands/session-content.ts +20 -9
  55. package/src/input/commands/session-workflow.ts +16 -1
  56. package/src/input/commands/settings-sync-runtime.ts +16 -4
  57. package/src/input/commands/shell-core.ts +25 -8
  58. package/src/input/commands/skills-runtime.ts +2 -8
  59. package/src/input/commands/subscription-runtime.ts +2 -2
  60. package/src/input/commands/test-runtime.ts +277 -0
  61. package/src/input/commands/websearch-runtime.ts +101 -0
  62. package/src/input/commands/work-plan-runtime.ts +36 -10
  63. package/src/input/commands/workstream-runtime.ts +488 -0
  64. package/src/input/commands.ts +12 -0
  65. package/src/input/config-modal-types.ts +175 -0
  66. package/src/input/config-modal.ts +592 -0
  67. package/src/input/feed-context-factory.ts +10 -8
  68. package/src/input/handler-command-route.ts +37 -20
  69. package/src/input/handler-content-actions.ts +17 -2
  70. package/src/input/handler-feed-routes.ts +74 -114
  71. package/src/input/handler-feed.ts +79 -27
  72. package/src/input/handler-interactions.ts +1 -3
  73. package/src/input/handler-modal-routes.ts +136 -6
  74. package/src/input/handler-modal-stack.ts +14 -7
  75. package/src/input/handler-modal-token-routes.ts +16 -49
  76. package/src/input/handler-onboarding-daemon-adopt.ts +149 -0
  77. package/src/input/handler-onboarding.ts +71 -59
  78. package/src/input/handler-picker-routes.ts +26 -102
  79. package/src/input/handler-shortcuts.ts +74 -14
  80. package/src/input/handler-types.ts +2 -6
  81. package/src/input/handler-ui-state.ts +10 -22
  82. package/src/input/handler.ts +12 -29
  83. package/src/input/keybindings.ts +23 -8
  84. package/src/input/model-picker-types.ts +24 -6
  85. package/src/input/model-picker.ts +77 -2
  86. package/src/input/onboarding/onboarding-runtime-status.ts +10 -1
  87. package/src/input/onboarding/onboarding-wizard-apply.ts +8 -1
  88. package/src/input/onboarding/onboarding-wizard-constants.ts +4 -1
  89. package/src/input/onboarding/onboarding-wizard-network-adopt.ts +136 -0
  90. package/src/input/onboarding/onboarding-wizard-steps.ts +9 -6
  91. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  92. package/src/input/panel-integration-actions.ts +9 -170
  93. package/src/input/panel-mouse-geometry.ts +97 -0
  94. package/src/input/panel-paste-flood-guard.ts +86 -0
  95. package/src/input/selection-modal.ts +11 -0
  96. package/src/input/session-picker-modal.ts +44 -4
  97. package/src/input/settings-modal-data.ts +146 -2
  98. package/src/input/settings-modal-mutations.ts +6 -4
  99. package/src/input/settings-modal-types.ts +4 -2
  100. package/src/main.ts +49 -51
  101. package/src/panels/agent-inspector-shared.ts +2 -1
  102. package/src/panels/base-panel.ts +22 -1
  103. package/src/panels/builtin/agent.ts +21 -107
  104. package/src/panels/builtin/development.ts +15 -61
  105. package/src/panels/builtin/knowledge.ts +8 -32
  106. package/src/panels/builtin/operations.ts +84 -428
  107. package/src/panels/builtin/session.ts +21 -112
  108. package/src/panels/builtin/shared.ts +18 -46
  109. package/src/panels/builtin-modals.ts +218 -0
  110. package/src/panels/builtin-panels.ts +5 -0
  111. package/src/panels/cost-tracker-panel.ts +36 -10
  112. package/src/panels/diff-panel.ts +12 -43
  113. package/src/panels/eval-registry.ts +60 -0
  114. package/src/panels/fleet-deep-link.ts +31 -0
  115. package/src/panels/fleet-panel-format.ts +62 -0
  116. package/src/panels/fleet-panel-worktree-detail.ts +48 -0
  117. package/src/panels/fleet-panel.ts +758 -0
  118. package/src/panels/fleet-read-model.ts +520 -0
  119. package/src/panels/fleet-steer.ts +125 -0
  120. package/src/panels/fleet-stop.ts +153 -0
  121. package/src/panels/fleet-tabs.ts +230 -0
  122. package/src/panels/fleet-transcript.ts +356 -0
  123. package/src/panels/index.ts +7 -31
  124. package/src/panels/modals/hooks-modal.ts +187 -0
  125. package/src/panels/modals/keybindings-modal.ts +166 -0
  126. package/src/panels/modals/knowledge-modal.ts +158 -0
  127. package/src/panels/modals/local-auth-modal.ts +132 -0
  128. package/src/panels/modals/marketplace-modal.ts +218 -0
  129. package/src/panels/modals/memory-modal.ts +180 -0
  130. package/src/panels/modals/modal-surface-helpers.ts +54 -0
  131. package/src/panels/modals/modal-theme.ts +42 -0
  132. package/src/panels/modals/pairing-modal.ts +163 -0
  133. package/src/panels/modals/planning-modal.ts +304 -0
  134. package/src/panels/modals/plugins-modal.ts +174 -0
  135. package/src/panels/modals/policy-modal.ts +256 -0
  136. package/src/panels/modals/provider-health-modal.ts +136 -0
  137. package/src/panels/modals/remote-modal.ts +115 -0
  138. package/src/panels/modals/sandbox-modal.ts +150 -0
  139. package/src/panels/modals/security-modal.ts +217 -0
  140. package/src/panels/modals/services-modal.ts +179 -0
  141. package/src/panels/modals/settings-sync-modal.ts +142 -0
  142. package/src/panels/modals/skills-modal.ts +189 -0
  143. package/src/panels/modals/subscription-modal.ts +172 -0
  144. package/src/panels/modals/work-plan-modal.ts +177 -0
  145. package/src/panels/panel-confirm-overlay.ts +72 -0
  146. package/src/panels/panel-manager.ts +123 -9
  147. package/src/panels/polish-core.ts +38 -25
  148. package/src/panels/project-planning-answer-actions.ts +8 -11
  149. package/src/panels/skills-panel.ts +7 -51
  150. package/src/panels/types.ts +37 -0
  151. package/src/permissions/hunk-selection.ts +179 -0
  152. package/src/permissions/prompt.ts +216 -13
  153. package/src/renderer/autocomplete-overlay.ts +28 -2
  154. package/src/renderer/compaction-history-modal.ts +19 -3
  155. package/src/renderer/compaction-preview.ts +13 -2
  156. package/src/renderer/compaction-quality.ts +100 -0
  157. package/src/renderer/compositor.ts +2 -3
  158. package/src/renderer/config-modal.ts +95 -0
  159. package/src/renderer/conversation-overlays.ts +10 -17
  160. package/src/renderer/fleet-tab-strip.ts +56 -0
  161. package/src/renderer/footer-tips.ts +15 -3
  162. package/src/renderer/fullscreen-primitives.ts +32 -22
  163. package/src/renderer/git-status.ts +43 -1
  164. package/src/renderer/help-overlay.ts +2 -2
  165. package/src/renderer/layout.ts +0 -4
  166. package/src/renderer/markdown.ts +7 -3
  167. package/src/renderer/modal-factory.ts +25 -20
  168. package/src/renderer/model-workspace.ts +62 -4
  169. package/src/renderer/overlay-box.ts +21 -17
  170. package/src/renderer/panel-workspace-bar.ts +8 -2
  171. package/src/renderer/process-indicator.ts +14 -3
  172. package/src/renderer/selection-modal-overlay.ts +6 -1
  173. package/src/renderer/session-picker-modal.ts +196 -3
  174. package/src/renderer/settings-modal-helpers.ts +2 -0
  175. package/src/renderer/settings-modal.ts +7 -0
  176. package/src/renderer/shell-surface.ts +8 -1
  177. package/src/renderer/status-glyphs.ts +14 -15
  178. package/src/renderer/system-message.ts +15 -3
  179. package/src/renderer/terminal-bg-probe.ts +339 -0
  180. package/src/renderer/terminal-escapes.ts +20 -0
  181. package/src/renderer/theme-mode-config.ts +67 -0
  182. package/src/renderer/theme.ts +91 -1
  183. package/src/renderer/thinking.ts +11 -3
  184. package/src/renderer/tool-call.ts +15 -9
  185. package/src/renderer/tool-result-summary.ts +148 -0
  186. package/src/renderer/turn-injection.ts +133 -0
  187. package/src/renderer/ui-factory.ts +154 -85
  188. package/src/renderer/ui-primitives.ts +30 -129
  189. package/src/runtime/bootstrap-command-context.ts +27 -1
  190. package/src/runtime/bootstrap-command-parts.ts +41 -10
  191. package/src/runtime/bootstrap-core.ts +47 -15
  192. package/src/runtime/bootstrap-hook-bridge.ts +7 -0
  193. package/src/runtime/bootstrap-shell.ts +48 -17
  194. package/src/runtime/bootstrap.ts +129 -22
  195. package/src/runtime/code-index-services.ts +135 -0
  196. package/src/runtime/legacy-daemon-migration.ts +516 -0
  197. package/src/runtime/memory-fold.ts +26 -0
  198. package/src/runtime/onboarding/derivation.ts +7 -2
  199. package/src/runtime/onboarding/snapshot.ts +27 -1
  200. package/src/runtime/onboarding/types.ts +31 -1
  201. package/src/runtime/operator-token-cleanup.ts +82 -1
  202. package/src/runtime/orchestrator-core-services.ts +59 -0
  203. package/src/runtime/process-lifecycle.ts +3 -1
  204. package/src/runtime/resume-notice.ts +209 -0
  205. package/src/runtime/services.ts +98 -46
  206. package/src/runtime/session-inbound-inputs.ts +252 -0
  207. package/src/runtime/session-spine-transport.ts +64 -0
  208. package/src/runtime/terminal-output-guard.ts +15 -8
  209. package/src/runtime/ui-services.ts +27 -3
  210. package/src/runtime/workstream-services.ts +327 -0
  211. package/src/runtime/wrfc-persistence.ts +124 -17
  212. package/src/shell/blocking-input.ts +68 -4
  213. package/src/shell/recovery-input-helpers.ts +170 -1
  214. package/src/shell/ui-openers.ts +171 -26
  215. package/src/utils/format-duration.ts +8 -18
  216. package/src/utils/splash-lines.ts +1 -1
  217. package/src/utils/terminal-width.ts +52 -0
  218. package/src/version.ts +1 -1
  219. package/src/panels/agent-inspector-panel.ts +0 -786
  220. package/src/panels/approval-panel.ts +0 -252
  221. package/src/panels/automation-control-panel.ts +0 -479
  222. package/src/panels/cockpit-panel.ts +0 -481
  223. package/src/panels/cockpit-read-model.ts +0 -238
  224. package/src/panels/communication-panel.ts +0 -256
  225. package/src/panels/control-plane-panel.ts +0 -470
  226. package/src/panels/debug-panel.ts +0 -615
  227. package/src/panels/docs-panel.ts +0 -384
  228. package/src/panels/eval-panel.ts +0 -627
  229. package/src/panels/file-explorer-panel.ts +0 -673
  230. package/src/panels/file-preview-panel.ts +0 -517
  231. package/src/panels/hooks-panel.ts +0 -401
  232. package/src/panels/incident-review-panel.ts +0 -406
  233. package/src/panels/intelligence-panel.ts +0 -383
  234. package/src/panels/knowledge-graph-panel.ts +0 -515
  235. package/src/panels/marketplace-panel.ts +0 -399
  236. package/src/panels/memory-panel.ts +0 -558
  237. package/src/panels/ops-control-panel.ts +0 -329
  238. package/src/panels/ops-strategy-panel.ts +0 -321
  239. package/src/panels/orchestration-panel.ts +0 -465
  240. package/src/panels/panel-list-panel.ts +0 -566
  241. package/src/panels/plan-dashboard-panel.ts +0 -707
  242. package/src/panels/policy-panel.ts +0 -517
  243. package/src/panels/project-planning-panel.ts +0 -731
  244. package/src/panels/provider-health-panel.ts +0 -678
  245. package/src/panels/provider-health-tracker.ts +0 -310
  246. package/src/panels/provider-health-views.ts +0 -567
  247. package/src/panels/qr-panel.ts +0 -280
  248. package/src/panels/remote-panel.ts +0 -534
  249. package/src/panels/routes-panel.ts +0 -241
  250. package/src/panels/sandbox-panel.ts +0 -456
  251. package/src/panels/security-panel.ts +0 -447
  252. package/src/panels/services-panel.ts +0 -329
  253. package/src/panels/session-browser-panel.ts +0 -496
  254. package/src/panels/settings-sync-panel.ts +0 -398
  255. package/src/panels/subscription-panel.ts +0 -342
  256. package/src/panels/symbol-outline-panel.ts +0 -619
  257. package/src/panels/system-messages-panel.ts +0 -364
  258. package/src/panels/tasks-panel.ts +0 -608
  259. package/src/panels/thinking-panel.ts +0 -333
  260. package/src/panels/tool-inspector-panel.ts +0 -537
  261. package/src/panels/work-plan-panel.ts +0 -540
  262. package/src/panels/worktree-panel.ts +0 -360
  263. package/src/panels/wrfc-panel.ts +0 -790
  264. package/src/renderer/agent-detail-modal.ts +0 -466
  265. package/src/renderer/live-tail-modal.ts +0 -156
  266. package/src/renderer/process-modal.ts +0 -671
  267. package/src/renderer/qr-renderer.ts +0 -120
@@ -16,6 +16,7 @@ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
16
16
  import type { ForensicsRegistry } from '@/runtime/index.ts';
17
17
  import type { PolicyRuntimeState } from '@/runtime/index.ts';
18
18
  import type { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
19
+ import type { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
19
20
  import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
20
21
  import type { MemoryRegistry } from '@pellux/goodvibes-sdk/platform/state';
21
22
  import type { IntegrationHelperService } from '@/runtime/index.ts';
@@ -61,6 +62,10 @@ export type CreateBootstrapCommandContextOptions = {
61
62
  mcpRegistry: McpRegistry;
62
63
  voiceProviderRegistry?: VoiceProviderRegistry;
63
64
  voiceService?: VoiceService;
65
+ /** B31: direct-command consumers (`/search`, `/image`) of already-constructed RuntimeServices. */
66
+ webSearchService?: import('@pellux/goodvibes-sdk/platform/web-search').WebSearchService;
67
+ mediaProviders?: import('@pellux/goodvibes-sdk/platform/media').MediaProviderRegistry;
68
+ artifactStore?: import('@pellux/goodvibes-sdk/platform/artifacts').ArtifactStore;
64
69
  forensicsRegistry: ForensicsRegistry;
65
70
  policyRuntimeState: PolicyRuntimeState;
66
71
  readModels: UiReadModels;
@@ -68,6 +73,7 @@ export type CreateBootstrapCommandContextOptions = {
68
73
  remoteRuntime?: RemoteCommandService;
69
74
  planRuntime?: PlanRuntimeService;
70
75
  fileUndoManager: FileUndoManager;
76
+ workspaceCheckpointManager?: WorkspaceCheckpointManager;
71
77
  memoryRegistry?: MemoryRegistry;
72
78
  integrationHelpers?: IntegrationHelperService;
73
79
  automationManager?: ShellAutomationManagerRuntimeService;
@@ -115,6 +121,11 @@ export type CreateBootstrapCommandContextOptions = {
115
121
  wrfcController?: import('@pellux/goodvibes-sdk/platform/agents').WrfcController;
116
122
  componentHealthMonitor: import('@/runtime/index.ts').ComponentHealthMonitor;
117
123
  hydrateSessionUsage?: () => void;
124
+ workstreamEngine?: import('./workstream-services.ts').WorkstreamCommandService;
125
+ codeIndexStore?: import('@pellux/goodvibes-sdk/platform/state').CodeIndexStore;
126
+ codeIndexReindexScheduler?: import('@pellux/goodvibes-sdk/platform/state').CodeIndexReindexScheduler;
127
+ isPassiveCodeInjectionFlagEnabled?: () => boolean;
128
+ getMainSessionTurnInjections?: () => readonly import('../renderer/turn-injection.ts').TurnInjectionEntry[];
118
129
  };
119
130
 
120
131
  export function createBootstrapCommandContext(
@@ -132,6 +143,9 @@ export function createBootstrapCommandContext(
132
143
  mcpRegistry,
133
144
  voiceProviderRegistry,
134
145
  voiceService,
146
+ webSearchService,
147
+ mediaProviders,
148
+ artifactStore,
135
149
  forensicsRegistry,
136
150
  policyRuntimeState,
137
151
  readModels,
@@ -139,6 +153,7 @@ export function createBootstrapCommandContext(
139
153
  remoteRuntime,
140
154
  planRuntime,
141
155
  fileUndoManager,
156
+ workspaceCheckpointManager,
142
157
  memoryRegistry,
143
158
  integrationHelpers,
144
159
  automationManager,
@@ -169,6 +184,11 @@ export function createBootstrapCommandContext(
169
184
  wrfcController,
170
185
  changeTracker,
171
186
  hydrateSessionUsage,
187
+ workstreamEngine,
188
+ codeIndexStore,
189
+ codeIndexReindexScheduler,
190
+ isPassiveCodeInjectionFlagEnabled,
191
+ getMainSessionTurnInjections,
172
192
  planManager,
173
193
  adaptivePlanner,
174
194
  sessionOrchestration,
@@ -226,6 +246,11 @@ export function createBootstrapCommandContext(
226
246
  wrfcController,
227
247
  changeTracker,
228
248
  hydrateSessionUsage,
249
+ workstreamEngine,
250
+ codeIndexStore,
251
+ codeIndexReindexScheduler,
252
+ isPassiveCodeInjectionFlagEnabled,
253
+ getMainSessionTurnInjections,
229
254
  });
230
255
  const provider = createBootstrapCommandProviderSection({
231
256
  providerRegistry,
@@ -236,6 +261,7 @@ export function createBootstrapCommandContext(
236
261
  const workspace = createBootstrapCommandWorkspaceSection({
237
262
  keybindingsManager,
238
263
  fileUndoManager,
264
+ workspaceCheckpointManager,
239
265
  panelManager,
240
266
  profileManager,
241
267
  bookmarkManager,
@@ -243,7 +269,7 @@ export function createBootstrapCommandContext(
243
269
  projectPlanningProjectId,
244
270
  workPlanStore,
245
271
  }, shellServices);
246
- const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService }, shellServices);
272
+ const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, webSearchService, mediaProviders, artifactStore }, shellServices);
247
273
  const extensions = createBootstrapCommandExtensionsSection({
248
274
  toolRegistry,
249
275
  mcpRegistry,
@@ -5,7 +5,7 @@ import type { ConversationManager } from '../core/conversation';
5
5
  import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
6
6
  import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
7
7
  import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
8
- import type { PanelManager } from '../panels/panel-manager.ts';
8
+ import type { PanelManager, PanelDeepLinkTarget } from '../panels/panel-manager.ts';
9
9
  import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
10
10
  import type { OpsApi } from '@/runtime/index.ts';
11
11
  import type { MutableRuntimeState } from '@/runtime/index.ts';
@@ -16,7 +16,8 @@ import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/pe
16
16
  import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
17
17
  import type { ForensicsRegistry } from '@/runtime/index.ts';
18
18
  import type { PolicyRuntimeState } from '@/runtime/index.ts';
19
- import type { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
19
+ import type { CodeIndexStore, FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
20
+ import type { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
20
21
  import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
21
22
  import type { MemoryRegistry } from '@pellux/goodvibes-sdk/platform/state';
22
23
  import type { IntegrationHelperService } from '@/runtime/index.ts';
@@ -79,11 +80,16 @@ export interface BootstrapCommandSectionOptions {
79
80
  readonly mcpRegistry: McpRegistry;
80
81
  readonly voiceProviderRegistry?: VoiceProviderRegistry;
81
82
  readonly voiceService?: VoiceService;
83
+ /** B31: direct-command consumers (`/search`, `/image`) of already-constructed RuntimeServices. */
84
+ readonly webSearchService?: import('@pellux/goodvibes-sdk/platform/web-search').WebSearchService;
85
+ readonly mediaProviders?: import('@pellux/goodvibes-sdk/platform/media').MediaProviderRegistry;
86
+ readonly artifactStore?: import('@pellux/goodvibes-sdk/platform/artifacts').ArtifactStore;
82
87
  readonly forensicsRegistry: ForensicsRegistry;
83
88
  readonly policyRuntimeState: PolicyRuntimeState;
84
89
  readonly readModels: UiReadModels;
85
90
  readonly shellPaths: ShellPathService;
86
91
  readonly fileUndoManager: FileUndoManager;
92
+ readonly workspaceCheckpointManager?: WorkspaceCheckpointManager;
87
93
  readonly memoryRegistry?: MemoryRegistry;
88
94
  readonly integrationHelpers?: IntegrationHelperService;
89
95
  readonly knowledgeService?: KnowledgeService;
@@ -110,6 +116,11 @@ export interface BootstrapCommandSectionOptions {
110
116
  readonly wrfcController?: import('@pellux/goodvibes-sdk/platform/agents').WrfcController;
111
117
  readonly changeTracker?: import('@pellux/goodvibes-sdk/platform/sessions').SessionChangeTracker;
112
118
  readonly hydrateSessionUsage?: () => void;
119
+ readonly workstreamEngine?: import('./workstream-services.ts').WorkstreamCommandService;
120
+ readonly codeIndexStore?: CodeIndexStore;
121
+ readonly codeIndexReindexScheduler?: import('@pellux/goodvibes-sdk/platform/state').CodeIndexReindexScheduler;
122
+ readonly isPassiveCodeInjectionFlagEnabled?: () => boolean;
123
+ readonly getMainSessionTurnInjections?: () => readonly import('../renderer/turn-injection.ts').TurnInjectionEntry[];
113
124
  readonly agentManager?: ShellAgentManagerService;
114
125
  readonly modeManager?: ShellModeManagerService;
115
126
  readonly automationManager?: ShellAutomationManagerRuntimeService;
@@ -181,9 +192,16 @@ export function createBootstrapCommandActions(
181
192
  localUserAuthManager,
182
193
  } = options;
183
194
 
184
- const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
185
- panelManager.open(panelId, pane);
186
- panelManager.show();
195
+ const showPanel = (panelId: string, pane?: 'top' | 'bottom', target?: PanelDeepLinkTarget) => {
196
+ // W6.1 (the purge): a MIGRATE-TO-MODAL id resolves to a modal, not a panel.
197
+ // panelManager.open() fires the injected openModal callback and returns a
198
+ // no-op sentinel — so skip panelManager.show() (which would reveal an empty
199
+ // panel workspace behind the modal) when this id redirects. Keeps every
200
+ // showPanel-based front-door (openHooksPanel/openSecurityPanel/… and the
201
+ // migrated command runtimes) opening the modal cleanly.
202
+ const redirected = panelManager.getModalRedirect(panelId) !== undefined;
203
+ panelManager.open(panelId, pane, target);
204
+ if (!redirected) panelManager.show();
187
205
  requestRender();
188
206
  };
189
207
 
@@ -279,11 +297,15 @@ export function createBootstrapCommandActions(
279
297
  openMemoryPanel: () => {
280
298
  showPanel('memory');
281
299
  },
300
+ // W6.1: remote/subscription migrated to config-modal surfaces. open() hits
301
+ // the modal redirect and invokes the openModal callback — do NOT go through
302
+ // showPanel here, which would additionally reveal + focus an (empty) panel
303
+ // workspace behind the fullscreen modal.
282
304
  openRemotePanel: () => {
283
- showPanel('remote');
305
+ panelManager.open('remote');
284
306
  },
285
307
  openSubscriptionPanel: () => {
286
- showPanel('subscription');
308
+ panelManager.open('subscription');
287
309
  },
288
310
  openLocalAuthMaskedEntry: (kind, username) => {
289
311
  showPanel('local-auth');
@@ -301,7 +323,7 @@ export function createBootstrapCommandActions(
301
323
  export function createBootstrapCommandSessionSection(
302
324
  options: Pick<
303
325
  BootstrapCommandSectionOptions,
304
- 'conversation' | 'runtime' | 'sessionManager' | 'sessionMemoryStore' | 'sessionLineageTracker' | 'wrfcController' | 'changeTracker' | 'hydrateSessionUsage'
326
+ 'conversation' | 'runtime' | 'sessionManager' | 'sessionMemoryStore' | 'sessionLineageTracker' | 'wrfcController' | 'changeTracker' | 'hydrateSessionUsage' | 'workstreamEngine' | 'codeIndexStore' | 'codeIndexReindexScheduler' | 'isPassiveCodeInjectionFlagEnabled' | 'getMainSessionTurnInjections'
305
327
  >,
306
328
  ): BootstrapCommandSessionSection {
307
329
  return {
@@ -313,6 +335,11 @@ export function createBootstrapCommandSessionSection(
313
335
  wrfcController: options.wrfcController,
314
336
  changeTracker: options.changeTracker,
315
337
  hydrateSessionUsage: options.hydrateSessionUsage,
338
+ workstreamEngine: options.workstreamEngine,
339
+ codeIndexStore: options.codeIndexStore,
340
+ codeIndexReindexScheduler: options.codeIndexReindexScheduler,
341
+ isPassiveCodeInjectionFlagEnabled: options.isPassiveCodeInjectionFlagEnabled,
342
+ getMainSessionTurnInjections: options.getMainSessionTurnInjections,
316
343
  };
317
344
  }
318
345
 
@@ -333,7 +360,7 @@ export function createBootstrapCommandProviderSection(
333
360
  export function createBootstrapCommandWorkspaceSection(
334
361
  options: Pick<
335
362
  BootstrapCommandSectionOptions,
336
- 'keybindingsManager' | 'fileUndoManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
363
+ 'keybindingsManager' | 'fileUndoManager' | 'workspaceCheckpointManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
337
364
  | 'projectPlanningService' | 'projectPlanningProjectId' | 'workPlanStore'
338
365
  >,
339
366
  shellServices: BootstrapCommandShellServices,
@@ -341,6 +368,7 @@ export function createBootstrapCommandWorkspaceSection(
341
368
  return {
342
369
  keybindingsManager: options.keybindingsManager,
343
370
  fileUndoManager: options.fileUndoManager,
371
+ workspaceCheckpointManager: options.workspaceCheckpointManager,
344
372
  panelManager: options.panelManager,
345
373
  profileManager: options.profileManager,
346
374
  bookmarkManager: options.bookmarkManager,
@@ -354,7 +382,7 @@ export function createBootstrapCommandWorkspaceSection(
354
382
  export function createBootstrapCommandPlatformSection(
355
383
  options: Pick<
356
384
  BootstrapCommandSectionOptions,
357
- 'configManager' | 'voiceProviderRegistry' | 'voiceService'
385
+ 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
358
386
  >,
359
387
  shellServices: BootstrapCommandShellServices,
360
388
  ): BootstrapCommandPlatformSection {
@@ -363,6 +391,9 @@ export function createBootstrapCommandPlatformSection(
363
391
  configManager: options.configManager,
364
392
  voiceProviderRegistry: options.voiceProviderRegistry,
365
393
  voiceService: options.voiceService,
394
+ webSearchService: options.webSearchService,
395
+ mediaProviders: options.mediaProviders,
396
+ artifactStore: options.artifactStore,
366
397
  ...shellServices.platform,
367
398
  };
368
399
  }
@@ -7,7 +7,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
9
  import { Notifier } from '@pellux/goodvibes-sdk/platform/integrations';
10
- import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
11
10
  import { Compositor } from '../renderer/compositor.ts';
12
11
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
13
12
  import type { SystemMessageRouter } from '../core/system-message-router.ts';
@@ -33,7 +32,9 @@ import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.t
33
32
  import { join } from 'node:path';
34
33
  import { installWrfcAgentToolGuard } from '../tools/wrfc-agent-guard.ts';
35
34
  import { createWrfcPersistence, type WrfcPersistence } from './wrfc-persistence.ts';
36
- import type { SystemMessagePriority } from '../panels/system-messages-panel.ts';
35
+ import type { SystemMessagePriority } from '../core/system-message-router.ts';
36
+ import { SessionSpineClient, SessionUnionCache, TUI_SPINE_PARTICIPANT } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
37
+ import { SessionInboundInputPoller, createBootstrapInboundInputPoller } from './session-inbound-inputs.ts';
37
38
 
38
39
  // ---------------------------------------------------------------------------
39
40
  // Pre-router buffer
@@ -115,6 +116,12 @@ export interface BootstrapCoreState {
115
116
  readonly requestRender: () => void;
116
117
  readonly setRenderRequest: (fn: () => void) => void;
117
118
  readonly runtimeSessionIdRef: { value: string };
119
+ /** Cross-surface identity mirror; permanently dormant for embedded/local-only (docs/decisions/2026-07-06-session-spine-mode-branch-is-permanent.md), activated by bootstrap.ts only for an adopted 'external' daemon. */
120
+ readonly sessionSpine: SessionSpineClient;
121
+ /** D3: inbound steer/follow-up delivery; dormant until bootstrap.ts activates it. */
122
+ readonly sessionInboundInputs: SessionInboundInputPoller;
123
+ /** Cache-backed read facade; bootstrap.ts drives its mode (embedded/external/local-only) from the same HostServiceMode as the spine above. */
124
+ readonly sessionUnionCache: SessionUnionCache;
118
125
  /**
119
126
  * WRFC chain persistence — call `rehydrate()` once after the SystemMessageRouter
120
127
  * is wired so interrupted chains from a previous process are surfaced to the operator.
@@ -128,17 +135,8 @@ export type CompanionMessagePayload = Extract<SessionEvent, { type: 'COMPANION_M
128
135
  // Operator narration of inbound channel events
129
136
  // ---------------------------------------------------------------------------
130
137
 
131
- /**
132
- * Narrate an inbound channel event to the operator via the SystemMessageRouter.
133
- *
134
- * When an external surface (GitHub, Slack, ntfy, etc.) triggers an agent turn,
135
- * this function produces a human-readable system message so the operator can
136
- * observe which event caused the turn. Returns null for internal/companion
137
- * sources that do not need operator narration.
138
- *
139
- * @param event - The normalized inbound event descriptor.
140
- * @returns A narration string, or null if no narration is appropriate.
141
- */
138
+ /** Narrate an inbound channel event (GitHub, Slack, ntfy, etc.) that triggered an
139
+ * agent turn, via the SystemMessageRouter null for internal/companion sources. */
142
140
  export function narrateInboundEvent(event: {
143
141
  source: string;
144
142
  metadata: Readonly<Record<string, unknown>> | undefined;
@@ -294,6 +292,12 @@ export async function initializeBootstrapCore(
294
292
  surfaceRegistry,
295
293
  watcherRegistry,
296
294
  } = services;
295
+ // Permanently dormant for embedded/local-only (nothing to mirror to); bootstrap.ts activates it only for an adopted 'external' daemon.
296
+ const sessionSpine = new SessionSpineClient({ participant: TUI_SPINE_PARTICIPANT, recordKind: 'tui' });
297
+ // Cache-backed read facade over the local broker (passthrough until bootstrap.ts marks it
298
+ // embedded, or activates the adopted-daemon wire union for 'external').
299
+ // selfSessionIds keeps local authoritative for our own wire-mirrored session even when local/wire ids diverge (D-TUI-1).
300
+ const sessionUnionCache = new SessionUnionCache({ local: sharedSessionBroker, selfSessionIds: () => sessionSpine.mirroredSessionIds });
297
301
 
298
302
  routeBindings.attachRuntime({ runtimeBus, runtimeStore: store });
299
303
  surfaceRegistry.attachRuntime(store);
@@ -325,6 +329,7 @@ export async function initializeBootstrapCore(
325
329
  const uiServices = createUiRuntimeServices(services, {
326
330
  forensicsRegistry,
327
331
  getControlPlaneRecentEvents,
332
+ sessionUnionCache,
328
333
  });
329
334
 
330
335
  const conversation = new ConversationManager(() => {
@@ -428,6 +433,10 @@ export async function initializeBootstrapCore(
428
433
  } catch (err) {
429
434
  logger.error('Render threw; next requestRender will reschedule', { error: String(err) });
430
435
  }
436
+ // Debounced spine heartbeat on turn/render activity (no-op while dormant, i.e.
437
+ // embedded/local-only): a cheap synchronous no-op unless its own internal window has
438
+ // elapsed (at most one wire call per heartbeatMinIntervalMs) — safe on the hot path.
439
+ sessionSpine.heartbeat(runtimeSessionIdRef.value);
431
440
  };
432
441
  const requestRender = (): void => {
433
442
  if (renderScheduled) return;
@@ -635,12 +644,27 @@ export async function initializeBootstrapCore(
635
644
  },
636
645
  ));
637
646
 
647
+ // D3: inbound steer delivery — see createBootstrapInboundInputPoller's doc comment.
648
+ const sessionInboundInputs = createBootstrapInboundInputPoller({
649
+ runtimeSessionIdRef, routeOrBuffer, orchestratorHandleUserInputRef, conversation, requestRender,
650
+ });
651
+
638
652
  providerRegistry.startWatching(runtimeBus);
639
653
 
654
+ // W2.3: attach the SAME WebhookNotifier instance that `/notify add|remove|clear`
655
+ // (notify-runtime.ts) keeps live via ctx.services.webhookNotifier, rather than
656
+ // constructing a second, boot-time-only instance here. Before this fix, a
657
+ // webhook URL added mid-session reached long-task notifications (which read
658
+ // ctx.services.webhookNotifier directly) but never reached this instance's
659
+ // AGENT_FAILED/WORKFLOW_CHAIN_FAILED/WORKFLOW_CHAIN_PASSED runtime-bus
660
+ // listeners until restart — and if the session started with zero URLs
661
+ // configured, attachToRuntimeBus was never even called, so those listeners
662
+ // never existed at all for the rest of the session. Always attaching
663
+ // (regardless of initial URL count) and seeding the shared instance fixes
664
+ // both: `send()` is already a safe no-op with zero URLs configured.
640
665
  const webhookUrls = (configManager.getCategory('notifications') as { webhookUrls?: string[] }).webhookUrls ?? [];
641
666
  if (webhookUrls.length > 0) {
642
- const webhookNotifier = WebhookNotifier.fromConfig(webhookUrls);
643
- webhookNotifier.attachToRuntimeBus(runtimeBus);
667
+ services.webhookNotifier.setUrls(webhookUrls);
644
668
  domainDispatch.syncIntegration({
645
669
  id: 'webhooks',
646
670
  displayName: 'Webhooks',
@@ -652,6 +676,7 @@ export async function initializeBootstrapCore(
652
676
  meta: { urlCount: webhookUrls.length },
653
677
  }, 'bootstrap.webhooks');
654
678
  }
679
+ services.webhookNotifier.attachToRuntimeBus(runtimeBus);
655
680
 
656
681
  const notifier = await Notifier.fromConfig(services.serviceRegistry);
657
682
  const queueStatuses = notifier.getQueueStatus();
@@ -714,6 +739,10 @@ export async function initializeBootstrapCore(
714
739
  lastSeenAt: Date.now(),
715
740
  },
716
741
  }).catch((err) => { logger.debug('session broker create session failed at bootstrap', { err }); });
742
+ // Fire-and-forget spine mirror — a permanent parallel-write posture alongside (never
743
+ // instead of) the still-authoritative local SharedSessionBroker above. Dormant/queued
744
+ // until bootstrap.ts's deferred task activates it for an adopted 'external' daemon.
745
+ sessionSpine.register({ sessionId: runtime.sessionId, project: services.workingDirectory, title: 'Terminal UI session' });
717
746
 
718
747
  domainDispatch.syncSessionState({
719
748
  id: userSessionId,
@@ -764,5 +793,8 @@ export async function initializeBootstrapCore(
764
793
  },
765
794
  runtimeSessionIdRef,
766
795
  wrfcPersistence,
796
+ sessionSpine,
797
+ sessionInboundInputs,
798
+ sessionUnionCache,
767
799
  };
768
800
  }
@@ -9,6 +9,7 @@ import { HelperModel } from '@pellux/goodvibes-sdk/platform/config';
9
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
+ import type { SessionSpineClient } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
12
13
  import type { SessionManager } from '@pellux/goodvibes-sdk/platform/sessions';
13
14
  import type { PanelManager } from '../panels/panel-manager.ts';
14
15
  import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
@@ -22,6 +23,10 @@ export interface ResumeSessionOptions {
22
23
  readonly requestRender: () => void;
23
24
  readonly onSessionIdChanged?: (sessionId: string) => void;
24
25
  readonly sharedSessionBroker: Pick<SharedSessionBroker, 'reopenSession'>;
26
+ /** S3c: fire-and-forget daemon-spine mirror. Reopen (not register) is the
27
+ * ONLY resume-time verb — see the SDK session-spine client.ts header doc. */
28
+ readonly sessionSpine: Pick<SessionSpineClient, 'reopen'>;
29
+ readonly project: string;
25
30
  readonly writeLastSessionPointer: (sessionId: string) => void;
26
31
  readonly hookDispatcher: HookDispatcher;
27
32
  readonly sessionManager: SessionManager;
@@ -75,6 +80,8 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
75
80
  if (meta?.provider) options.runtime.provider = meta.provider;
76
81
  options.writeLastSessionPointer(sessionId);
77
82
  void options.sharedSessionBroker.reopenSession(sessionId).catch((err) => { logger.debug('session broker reopen session failed', { err }); });
83
+ // S3c: fire-and-forget spine mirror (reopen:true — the user resume verb).
84
+ options.sessionSpine.reopen({ sessionId, project: options.project, title: options.conversation.title || meta.title });
78
85
  options.conversation.log(`Resumed session: ${sessionId}`, { fg: '135' });
79
86
  const reopenedPanels: string[] = [];
80
87
  if (meta.returnContext?.openPanels?.length) {
@@ -1,4 +1,5 @@
1
1
  import { join } from 'node:path';
2
+ import { readBudgetAlertUsd, BUDGET_ALERT_USD_DEFAULT } from '../export/cost-utils.ts';
2
3
  import { sumConversationUsage, type ConversationManager } from '../core/conversation';
3
4
  import type { Orchestrator } from '../core/orchestrator';
4
5
  import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
@@ -15,7 +16,6 @@ import { GitStatusProvider } from '../renderer/git-status.ts';
15
16
  import type { GitHeaderInfo } from '../renderer/git-status.ts';
16
17
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
17
18
  import { registerBuiltinPanels } from '../panels/builtin-panels.ts';
18
- import { SystemMessagesPanel } from '../panels/system-messages-panel.ts';
19
19
  import { createSystemMessageRouter, type SystemMessageRouter } from '../core/system-message-router.ts';
20
20
  import { getConfigSnapshot } from '../config/index.ts';
21
21
  import { createBootstrapCommandContext } from './bootstrap-command-context.ts';
@@ -32,6 +32,7 @@ import type { PolicyRuntimeState } from '@/runtime/index.ts';
32
32
  import type { TaskManager } from '@/runtime/index.ts';
33
33
  import type { UiRuntimeServices } from './ui-services.ts';
34
34
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
35
+ import type { SessionSpineClient } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
35
36
 
36
37
  export interface BootstrapShellState {
37
38
  readonly commandRegistry: CommandRegistry;
@@ -40,11 +41,6 @@ export interface BootstrapShellState {
40
41
  readonly lastGitInfoRef: { value: GitHeaderInfo | undefined };
41
42
  readonly inputHistory: InputHistory;
42
43
  readonly systemMessageRouter: SystemMessageRouter;
43
- /**
44
- * Wire the agent detail modal opener after InputHandler is constructed.
45
- * Call with `(id) => input.agentDetailModal.open(id)` from main.ts.
46
- */
47
- readonly setOpenAgentDetail: (fn: (agentId: string) => void) => void;
48
44
  }
49
45
 
50
46
  export interface BootstrapShellOptions {
@@ -52,6 +48,8 @@ export interface BootstrapShellOptions {
52
48
  readonly runtimeBus: RuntimeEventBus;
53
49
  readonly runtimeStore: RuntimeStore;
54
50
  readonly services: RuntimeServices;
51
+ /** S3c: dormant until bootstrap.ts activates it for an adopted 'external' daemon. */
52
+ readonly sessionSpine: SessionSpineClient;
55
53
  readonly conversation: ConversationManager;
56
54
  readonly runtime: MutableRuntimeState;
57
55
  readonly orchestrator: Orchestrator;
@@ -75,6 +73,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
75
73
  runtimeBus,
76
74
  runtimeStore,
77
75
  services,
76
+ sessionSpine,
78
77
  conversation,
79
78
  runtime,
80
79
  orchestrator,
@@ -92,7 +91,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
92
91
  completeModelSelectionSideEffect,
93
92
  } = options;
94
93
 
95
- const systemMessagesPanel = new SystemMessagesPanel(configManager, services.componentHealthMonitor);
96
94
  // W0.9: after any resume seam replays historical messages into `conversation`,
97
95
  // the freshly-constructed `orchestrator` still has its zeroed default usage
98
96
  // (SDK gap — Orchestrator.usage is never persisted/reseeded). Recompute it
@@ -109,6 +107,8 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
109
107
  requestRender,
110
108
  onSessionIdChanged,
111
109
  sharedSessionBroker: services.sessionBroker,
110
+ sessionSpine,
111
+ project: services.workingDirectory,
112
112
  writeLastSessionPointer,
113
113
  hookDispatcher: services.hookDispatcher,
114
114
  sessionManager: services.sessionManager,
@@ -138,16 +138,22 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
138
138
  runtimeBus,
139
139
  });
140
140
 
141
- const openAgentDetailRef: { fn: (agentId: string) => void } = { fn: (_agentId: string) => {} };
142
-
143
141
  // WO-139: initial cost-budget alert threshold (USD; 0/unset = disabled).
144
142
  // Once the session starts, the real control surface is the CostTrackerPanel
145
143
  // itself — the in-panel 'b' key and /cost budget <usd> both call
146
- // CostTrackerPanel.setBudgetThreshold() directly on the live panel instance.
144
+ // CostTrackerPanel.setBudgetThreshold() directly on the live panel instance,
145
+ // which (W2.3) now writes through to the behavior.budgetAlertUsd config key
146
+ // so the background budget-breach notifier reads the same value. The env
147
+ // var remains a first-run convenience only: it seeds the config key when
148
+ // that key has never been set, so it doesn't silently override a value the
149
+ // user has already configured in a prior session.
147
150
  const parsedBudgetThreshold = Number(process.env.GOODVIBES_COST_BUDGET_USD);
148
151
  const initialCostBudgetThreshold = Number.isFinite(parsedBudgetThreshold) && parsedBudgetThreshold > 0
149
152
  ? parsedBudgetThreshold
150
153
  : 0;
154
+ if (initialCostBudgetThreshold > 0 && readBudgetAlertUsd((k) => configManager.get(k as Parameters<typeof configManager.get>[0])) === BUDGET_ALERT_USD_DEFAULT) {
155
+ configManager.set('behavior.budgetAlertUsd' as Parameters<typeof configManager.set>[0], initialCostBudgetThreshold as never);
156
+ }
151
157
 
152
158
  let commandContextRef: CommandContext | null = null;
153
159
  registerBuiltinPanels(services.panelManager, {
@@ -175,14 +181,14 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
175
181
  forensicsRegistry,
176
182
  policyRuntimeState,
177
183
  approvalBroker: services.approvalBroker,
178
- sessionBroker: services.sessionBroker,
184
+ // S3d: panels read the cross-surface union facade, not the raw local broker.
185
+ sessionBroker: uiServices.sessions.sessionBroker,
179
186
  automationManager: services.automationManager,
180
187
  getControlPlaneRecentEvents,
181
188
  tokenAuditor: services.tokenAuditor,
182
189
  componentHealthMonitor: services.componentHealthMonitor,
183
190
  worktreeRegistry: services.worktreeRegistry,
184
191
  sandboxSessionRegistry: services.sandboxSessionRegistry,
185
- systemMessagesPanel,
186
192
  memoryRegistry: services.memoryRegistry,
187
193
  uiServices,
188
194
  pluginManager: services.pluginManager,
@@ -190,7 +196,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
190
196
  hookActivityTracker: services.hookActivityTracker,
191
197
  hookWorkbench: services.hookWorkbench,
192
198
  mcpRegistry: services.mcpRegistry,
193
- openAgentDetail: (agentId: string) => openAgentDetailRef.fn(agentId),
194
199
  daemonHomeDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
195
200
  opsApi,
196
201
  planRuntime,
@@ -203,13 +208,21 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
203
208
 
204
209
  const systemMessageRouter = createSystemMessageRouter(
205
210
  conversation,
206
- systemMessagesPanel,
207
211
  (kind) => {
208
212
  const ui = getConfigSnapshot(configManager).ui;
209
213
  if (kind === 'wrfc') return ui.wrfcMessages;
210
214
  if (kind === 'operational') return ui.operationalMessages;
211
215
  return ui.systemMessages;
212
216
  },
217
+ {
218
+ // Suppress stale WRFC replay re-notifications for chains that can no
219
+ // longer act — gone (killed/removed → getChain null) or terminal
220
+ // (passed/failed). (UX-B item 1c.)
221
+ isChainTerminal: (chainId) => {
222
+ const chain = services.wrfcController.getChain(chainId);
223
+ return chain === null || chain.state === 'passed' || chain.state === 'failed';
224
+ },
225
+ },
213
226
  );
214
227
  orchestrator.setSystemMessageRouter(systemMessageRouter);
215
228
 
@@ -233,6 +246,9 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
233
246
  mcpRegistry: services.mcpRegistry,
234
247
  voiceProviderRegistry: services.voiceProviders,
235
248
  voiceService: services.voiceService,
249
+ webSearchService: services.webSearchService,
250
+ mediaProviders: services.mediaProviders,
251
+ artifactStore: services.artifactStore,
236
252
  forensicsRegistry,
237
253
  policyRuntimeState,
238
254
  readModels: uiServices.readModels,
@@ -240,6 +256,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
240
256
  remoteRuntime,
241
257
  planRuntime,
242
258
  fileUndoManager: services.fileUndoManager,
259
+ workspaceCheckpointManager: services.workspaceCheckpointManager,
243
260
  memoryRegistry: services.memoryRegistry,
244
261
  integrationHelpers: services.integrationHelpers,
245
262
  automationManager: services.automationManager,
@@ -268,6 +285,13 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
268
285
  sessionMemoryStore: services.sessionMemoryStore,
269
286
  sessionLineageTracker: services.sessionLineageTracker,
270
287
  wrfcController: services.wrfcController,
288
+ workstreamEngine: services.workstreamCommands,
289
+ codeIndexStore: services.codeIndexStore,
290
+ codeIndexReindexScheduler: services.codeIndexReindexScheduler,
291
+ isPassiveCodeInjectionFlagEnabled: () => services.featureFlags.isEnabled('agent-passive-code-injection'),
292
+ // Wave 5 (wo805): expose the MAIN session's per-turn passive-injection ring
293
+ // so `/recall injections` (no agent id) renders it — see recall-review.ts.
294
+ getMainSessionTurnInjections: () => orchestrator.getTurnInjections(),
271
295
  changeTracker: services.sessionChangeTracker,
272
296
  planManager: services.planManager,
273
297
  adaptivePlanner: services.adaptivePlanner,
@@ -302,6 +326,16 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
302
326
  lastGitInfoRef.value = info;
303
327
  requestRender();
304
328
  }).catch(() => { /* non-fatal */ });
329
+ // W1.6 FIX 2: the header's git segment otherwise only refreshes on
330
+ // TURN_COMPLETED/TOOL_SUCCEEDED/TOOL_FAILED (see turn-event-wiring.ts's
331
+ // refreshGit()) — if the user runs `git init` externally and never submits
332
+ // another turn, the header stays stuck on the startup-time fallback
333
+ // indefinitely. Poll at the same 5s cadence GitPanel already uses for its
334
+ // own self-poll (git-panel.ts) so the two mechanisms are cadence-consistent.
335
+ gitStatusProvider.startPolling(5_000, (info) => {
336
+ lastGitInfoRef.value = info;
337
+ requestRender();
338
+ });
305
339
 
306
340
  const saveHistory = configManager.get('behavior.saveHistory') as boolean;
307
341
  const inputHistory = new InputHistory({
@@ -316,8 +350,5 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
316
350
  lastGitInfoRef,
317
351
  inputHistory,
318
352
  systemMessageRouter,
319
- setOpenAgentDetail: (fn: (agentId: string) => void) => {
320
- openAgentDetailRef.fn = fn;
321
- },
322
353
  };
323
354
  }