@pellux/goodvibes-tui 1.1.0 → 1.7.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 (194) hide show
  1. package/CHANGELOG.md +85 -21
  2. package/README.md +20 -11
  3. package/docs/foundation-artifacts/operator-contract.json +1 -1
  4. package/package.json +2 -2
  5. package/src/core/alert-gating.ts +67 -0
  6. package/src/core/approval-alert.ts +72 -0
  7. package/src/core/budget-breach-notifier.ts +106 -0
  8. package/src/core/conversation-rendering.ts +19 -0
  9. package/src/core/conversation.ts +18 -0
  10. package/src/core/focus-tracker.ts +41 -0
  11. package/src/core/long-task-notifier.ts +33 -6
  12. package/src/core/system-message-router.ts +37 -51
  13. package/src/core/turn-cancellation.ts +20 -0
  14. package/src/core/turn-event-wiring.ts +64 -3
  15. package/src/export/cost-utils.ts +36 -0
  16. package/src/input/command-registry.ts +38 -1
  17. package/src/input/commands/checkpoint-runtime.ts +280 -0
  18. package/src/input/commands/codebase-runtime.ts +192 -0
  19. package/src/input/commands/eval.ts +1 -1
  20. package/src/input/commands/health-runtime.ts +1 -1
  21. package/src/input/commands/image-runtime.ts +112 -0
  22. package/src/input/commands/intelligence-runtime.ts +11 -1
  23. package/src/input/commands/local-auth-runtime.ts +4 -1
  24. package/src/input/commands/local-runtime.ts +9 -3
  25. package/src/input/commands/marketplace-runtime.ts +2 -2
  26. package/src/input/commands/memory.ts +6 -1
  27. package/src/input/commands/operator-panel-runtime.ts +40 -24
  28. package/src/input/commands/planning-runtime.ts +26 -3
  29. package/src/input/commands/platform-sandbox-runtime.ts +1 -6
  30. package/src/input/commands/plugin-runtime.ts +2 -2
  31. package/src/input/commands/policy-dispatch.ts +21 -0
  32. package/src/input/commands/provider-accounts-runtime.ts +1 -1
  33. package/src/input/commands/qrcode-runtime.ts +3 -3
  34. package/src/input/commands/recall-review.ts +35 -0
  35. package/src/input/commands/remote-runtime.ts +3 -3
  36. package/src/input/commands/runtime-services.ts +54 -13
  37. package/src/input/commands/services-runtime.ts +1 -1
  38. package/src/input/commands/session-workflow.ts +16 -1
  39. package/src/input/commands/settings-sync-runtime.ts +1 -1
  40. package/src/input/commands/shell-core.ts +15 -7
  41. package/src/input/commands/skills-runtime.ts +2 -8
  42. package/src/input/commands/subscription-runtime.ts +2 -2
  43. package/src/input/commands/test-runtime.ts +277 -0
  44. package/src/input/commands/websearch-runtime.ts +101 -0
  45. package/src/input/commands/work-plan-runtime.ts +36 -10
  46. package/src/input/commands/workstream-runtime.ts +338 -0
  47. package/src/input/commands.ts +12 -0
  48. package/src/input/config-modal-types.ts +161 -0
  49. package/src/input/config-modal.ts +377 -0
  50. package/src/input/feed-context-factory.ts +7 -8
  51. package/src/input/handler-command-route.ts +27 -17
  52. package/src/input/handler-feed-routes.ts +61 -23
  53. package/src/input/handler-feed.ts +47 -23
  54. package/src/input/handler-interactions.ts +1 -3
  55. package/src/input/handler-modal-routes.ts +65 -0
  56. package/src/input/handler-modal-stack.ts +3 -5
  57. package/src/input/handler-modal-token-routes.ts +16 -49
  58. package/src/input/handler-picker-routes.ts +11 -94
  59. package/src/input/handler-shortcuts.ts +24 -14
  60. package/src/input/handler-types.ts +2 -6
  61. package/src/input/handler-ui-state.ts +10 -22
  62. package/src/input/handler.ts +6 -28
  63. package/src/input/keybindings.ts +22 -8
  64. package/src/input/model-picker-types.ts +24 -6
  65. package/src/input/model-picker.ts +58 -0
  66. package/src/input/panel-integration-actions.ts +9 -170
  67. package/src/input/settings-modal-data.ts +95 -0
  68. package/src/input/settings-modal-mutations.ts +6 -4
  69. package/src/main.ts +24 -27
  70. package/src/panels/agent-inspector-shared.ts +2 -1
  71. package/src/panels/base-panel.ts +22 -1
  72. package/src/panels/builtin/agent.ts +21 -107
  73. package/src/panels/builtin/development.ts +15 -61
  74. package/src/panels/builtin/knowledge.ts +8 -32
  75. package/src/panels/builtin/operations.ts +84 -428
  76. package/src/panels/builtin/session.ts +21 -112
  77. package/src/panels/builtin/shared.ts +9 -43
  78. package/src/panels/builtin-modals.ts +218 -0
  79. package/src/panels/builtin-panels.ts +5 -0
  80. package/src/panels/cost-tracker-panel.ts +36 -10
  81. package/src/panels/diff-panel.ts +12 -43
  82. package/src/panels/eval-registry.ts +60 -0
  83. package/src/panels/fleet-panel.ts +800 -0
  84. package/src/panels/fleet-read-model.ts +477 -0
  85. package/src/panels/fleet-steer.ts +92 -0
  86. package/src/panels/fleet-stop.ts +125 -0
  87. package/src/panels/fleet-tabs.ts +230 -0
  88. package/src/panels/fleet-transcript.ts +356 -0
  89. package/src/panels/index.ts +7 -31
  90. package/src/panels/modals/hooks-modal.ts +187 -0
  91. package/src/panels/modals/keybindings-modal.ts +151 -0
  92. package/src/panels/modals/knowledge-modal.ts +158 -0
  93. package/src/panels/modals/local-auth-modal.ts +132 -0
  94. package/src/panels/modals/marketplace-modal.ts +218 -0
  95. package/src/panels/modals/memory-modal.ts +180 -0
  96. package/src/panels/modals/modal-surface-helpers.ts +54 -0
  97. package/src/panels/modals/modal-theme.ts +36 -0
  98. package/src/panels/modals/pairing-modal.ts +144 -0
  99. package/src/panels/modals/planning-modal.ts +282 -0
  100. package/src/panels/modals/plugins-modal.ts +174 -0
  101. package/src/panels/modals/policy-modal.ts +256 -0
  102. package/src/panels/modals/provider-health-modal.ts +136 -0
  103. package/src/panels/modals/remote-modal.ts +115 -0
  104. package/src/panels/modals/sandbox-modal.ts +150 -0
  105. package/src/panels/modals/security-modal.ts +217 -0
  106. package/src/panels/modals/services-modal.ts +179 -0
  107. package/src/panels/modals/settings-sync-modal.ts +142 -0
  108. package/src/panels/modals/skills-modal.ts +189 -0
  109. package/src/panels/modals/subscription-modal.ts +172 -0
  110. package/src/panels/modals/work-plan-modal.ts +149 -0
  111. package/src/panels/panel-confirm-overlay.ts +72 -0
  112. package/src/panels/panel-manager.ts +108 -5
  113. package/src/panels/project-planning-answer-actions.ts +4 -2
  114. package/src/panels/skills-panel.ts +7 -51
  115. package/src/panels/types.ts +13 -0
  116. package/src/permissions/hunk-selection.ts +179 -0
  117. package/src/permissions/prompt.ts +60 -4
  118. package/src/renderer/compaction-history-modal.ts +19 -3
  119. package/src/renderer/compaction-preview.ts +13 -2
  120. package/src/renderer/compaction-quality.ts +100 -0
  121. package/src/renderer/config-modal.ts +81 -0
  122. package/src/renderer/conversation-overlays.ts +10 -17
  123. package/src/renderer/fleet-tab-strip.ts +56 -0
  124. package/src/renderer/footer-tips.ts +10 -2
  125. package/src/renderer/git-status.ts +40 -0
  126. package/src/renderer/help-overlay.ts +2 -2
  127. package/src/renderer/model-workspace.ts +44 -1
  128. package/src/renderer/panel-workspace-bar.ts +8 -2
  129. package/src/renderer/turn-injection.ts +114 -0
  130. package/src/runtime/bootstrap-command-context.ts +21 -1
  131. package/src/runtime/bootstrap-command-parts.ts +34 -7
  132. package/src/runtime/bootstrap-core.ts +14 -4
  133. package/src/runtime/bootstrap-shell.ts +29 -16
  134. package/src/runtime/bootstrap.ts +11 -17
  135. package/src/runtime/code-index-services.ts +112 -0
  136. package/src/runtime/orchestrator-core-services.ts +49 -0
  137. package/src/runtime/process-lifecycle.ts +3 -1
  138. package/src/runtime/services.ts +91 -43
  139. package/src/runtime/ui-services.ts +8 -0
  140. package/src/runtime/workstream-services.ts +195 -0
  141. package/src/shell/blocking-input.ts +22 -1
  142. package/src/shell/ui-openers.ts +129 -17
  143. package/src/utils/format-duration.ts +8 -18
  144. package/src/utils/splash-lines.ts +1 -1
  145. package/src/version.ts +1 -1
  146. package/src/panels/agent-inspector-panel.ts +0 -786
  147. package/src/panels/approval-panel.ts +0 -252
  148. package/src/panels/automation-control-panel.ts +0 -479
  149. package/src/panels/cockpit-panel.ts +0 -481
  150. package/src/panels/cockpit-read-model.ts +0 -238
  151. package/src/panels/communication-panel.ts +0 -256
  152. package/src/panels/control-plane-panel.ts +0 -470
  153. package/src/panels/debug-panel.ts +0 -615
  154. package/src/panels/docs-panel.ts +0 -384
  155. package/src/panels/eval-panel.ts +0 -627
  156. package/src/panels/file-explorer-panel.ts +0 -673
  157. package/src/panels/file-preview-panel.ts +0 -517
  158. package/src/panels/hooks-panel.ts +0 -401
  159. package/src/panels/incident-review-panel.ts +0 -406
  160. package/src/panels/intelligence-panel.ts +0 -383
  161. package/src/panels/knowledge-graph-panel.ts +0 -515
  162. package/src/panels/marketplace-panel.ts +0 -399
  163. package/src/panels/memory-panel.ts +0 -558
  164. package/src/panels/ops-control-panel.ts +0 -329
  165. package/src/panels/ops-strategy-panel.ts +0 -321
  166. package/src/panels/orchestration-panel.ts +0 -465
  167. package/src/panels/panel-list-panel.ts +0 -566
  168. package/src/panels/plan-dashboard-panel.ts +0 -707
  169. package/src/panels/policy-panel.ts +0 -517
  170. package/src/panels/project-planning-panel.ts +0 -731
  171. package/src/panels/provider-health-panel.ts +0 -678
  172. package/src/panels/provider-health-tracker.ts +0 -310
  173. package/src/panels/provider-health-views.ts +0 -567
  174. package/src/panels/qr-panel.ts +0 -280
  175. package/src/panels/remote-panel.ts +0 -534
  176. package/src/panels/routes-panel.ts +0 -241
  177. package/src/panels/sandbox-panel.ts +0 -456
  178. package/src/panels/security-panel.ts +0 -447
  179. package/src/panels/services-panel.ts +0 -329
  180. package/src/panels/session-browser-panel.ts +0 -496
  181. package/src/panels/settings-sync-panel.ts +0 -398
  182. package/src/panels/subscription-panel.ts +0 -342
  183. package/src/panels/symbol-outline-panel.ts +0 -619
  184. package/src/panels/system-messages-panel.ts +0 -364
  185. package/src/panels/tasks-panel.ts +0 -608
  186. package/src/panels/thinking-panel.ts +0 -333
  187. package/src/panels/tool-inspector-panel.ts +0 -537
  188. package/src/panels/work-plan-panel.ts +0 -540
  189. package/src/panels/worktree-panel.ts +0 -360
  190. package/src/panels/wrfc-panel.ts +0 -790
  191. package/src/renderer/agent-detail-modal.ts +0 -466
  192. package/src/renderer/live-tail-modal.ts +0 -156
  193. package/src/renderer/process-modal.ts +0 -671
  194. 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,9 @@ 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
+ getMainSessionTurnInjections?: () => readonly import('../renderer/turn-injection.ts').TurnInjectionEntry[];
118
127
  };
119
128
 
120
129
  export function createBootstrapCommandContext(
@@ -132,6 +141,9 @@ export function createBootstrapCommandContext(
132
141
  mcpRegistry,
133
142
  voiceProviderRegistry,
134
143
  voiceService,
144
+ webSearchService,
145
+ mediaProviders,
146
+ artifactStore,
135
147
  forensicsRegistry,
136
148
  policyRuntimeState,
137
149
  readModels,
@@ -139,6 +151,7 @@ export function createBootstrapCommandContext(
139
151
  remoteRuntime,
140
152
  planRuntime,
141
153
  fileUndoManager,
154
+ workspaceCheckpointManager,
142
155
  memoryRegistry,
143
156
  integrationHelpers,
144
157
  automationManager,
@@ -169,6 +182,9 @@ export function createBootstrapCommandContext(
169
182
  wrfcController,
170
183
  changeTracker,
171
184
  hydrateSessionUsage,
185
+ workstreamEngine,
186
+ codeIndexStore,
187
+ getMainSessionTurnInjections,
172
188
  planManager,
173
189
  adaptivePlanner,
174
190
  sessionOrchestration,
@@ -226,6 +242,9 @@ export function createBootstrapCommandContext(
226
242
  wrfcController,
227
243
  changeTracker,
228
244
  hydrateSessionUsage,
245
+ workstreamEngine,
246
+ codeIndexStore,
247
+ getMainSessionTurnInjections,
229
248
  });
230
249
  const provider = createBootstrapCommandProviderSection({
231
250
  providerRegistry,
@@ -236,6 +255,7 @@ export function createBootstrapCommandContext(
236
255
  const workspace = createBootstrapCommandWorkspaceSection({
237
256
  keybindingsManager,
238
257
  fileUndoManager,
258
+ workspaceCheckpointManager,
239
259
  panelManager,
240
260
  profileManager,
241
261
  bookmarkManager,
@@ -243,7 +263,7 @@ export function createBootstrapCommandContext(
243
263
  projectPlanningProjectId,
244
264
  workPlanStore,
245
265
  }, shellServices);
246
- const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService }, shellServices);
266
+ const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, webSearchService, mediaProviders, artifactStore }, shellServices);
247
267
  const extensions = createBootstrapCommandExtensionsSection({
248
268
  toolRegistry,
249
269
  mcpRegistry,
@@ -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,9 @@ 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 getMainSessionTurnInjections?: () => readonly import('../renderer/turn-injection.ts').TurnInjectionEntry[];
113
122
  readonly agentManager?: ShellAgentManagerService;
114
123
  readonly modeManager?: ShellModeManagerService;
115
124
  readonly automationManager?: ShellAutomationManagerRuntimeService;
@@ -182,8 +191,15 @@ export function createBootstrapCommandActions(
182
191
  } = options;
183
192
 
184
193
  const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
194
+ // W6.1 (the purge): a MIGRATE-TO-MODAL id resolves to a modal, not a panel.
195
+ // panelManager.open() fires the injected openModal callback and returns a
196
+ // no-op sentinel — so skip panelManager.show() (which would reveal an empty
197
+ // panel workspace behind the modal) when this id redirects. Keeps every
198
+ // showPanel-based front-door (openHooksPanel/openSecurityPanel/… and the
199
+ // migrated command runtimes) opening the modal cleanly.
200
+ const redirected = panelManager.getModalRedirect(panelId) !== undefined;
185
201
  panelManager.open(panelId, pane);
186
- panelManager.show();
202
+ if (!redirected) panelManager.show();
187
203
  requestRender();
188
204
  };
189
205
 
@@ -279,11 +295,15 @@ export function createBootstrapCommandActions(
279
295
  openMemoryPanel: () => {
280
296
  showPanel('memory');
281
297
  },
298
+ // W6.1: remote/subscription migrated to config-modal surfaces. open() hits
299
+ // the modal redirect and invokes the openModal callback — do NOT go through
300
+ // showPanel here, which would additionally reveal + focus an (empty) panel
301
+ // workspace behind the fullscreen modal.
282
302
  openRemotePanel: () => {
283
- showPanel('remote');
303
+ panelManager.open('remote');
284
304
  },
285
305
  openSubscriptionPanel: () => {
286
- showPanel('subscription');
306
+ panelManager.open('subscription');
287
307
  },
288
308
  openLocalAuthMaskedEntry: (kind, username) => {
289
309
  showPanel('local-auth');
@@ -301,7 +321,7 @@ export function createBootstrapCommandActions(
301
321
  export function createBootstrapCommandSessionSection(
302
322
  options: Pick<
303
323
  BootstrapCommandSectionOptions,
304
- 'conversation' | 'runtime' | 'sessionManager' | 'sessionMemoryStore' | 'sessionLineageTracker' | 'wrfcController' | 'changeTracker' | 'hydrateSessionUsage'
324
+ 'conversation' | 'runtime' | 'sessionManager' | 'sessionMemoryStore' | 'sessionLineageTracker' | 'wrfcController' | 'changeTracker' | 'hydrateSessionUsage' | 'workstreamEngine' | 'codeIndexStore' | 'getMainSessionTurnInjections'
305
325
  >,
306
326
  ): BootstrapCommandSessionSection {
307
327
  return {
@@ -313,6 +333,9 @@ export function createBootstrapCommandSessionSection(
313
333
  wrfcController: options.wrfcController,
314
334
  changeTracker: options.changeTracker,
315
335
  hydrateSessionUsage: options.hydrateSessionUsage,
336
+ workstreamEngine: options.workstreamEngine,
337
+ codeIndexStore: options.codeIndexStore,
338
+ getMainSessionTurnInjections: options.getMainSessionTurnInjections,
316
339
  };
317
340
  }
318
341
 
@@ -333,7 +356,7 @@ export function createBootstrapCommandProviderSection(
333
356
  export function createBootstrapCommandWorkspaceSection(
334
357
  options: Pick<
335
358
  BootstrapCommandSectionOptions,
336
- 'keybindingsManager' | 'fileUndoManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
359
+ 'keybindingsManager' | 'fileUndoManager' | 'workspaceCheckpointManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
337
360
  | 'projectPlanningService' | 'projectPlanningProjectId' | 'workPlanStore'
338
361
  >,
339
362
  shellServices: BootstrapCommandShellServices,
@@ -341,6 +364,7 @@ export function createBootstrapCommandWorkspaceSection(
341
364
  return {
342
365
  keybindingsManager: options.keybindingsManager,
343
366
  fileUndoManager: options.fileUndoManager,
367
+ workspaceCheckpointManager: options.workspaceCheckpointManager,
344
368
  panelManager: options.panelManager,
345
369
  profileManager: options.profileManager,
346
370
  bookmarkManager: options.bookmarkManager,
@@ -354,7 +378,7 @@ export function createBootstrapCommandWorkspaceSection(
354
378
  export function createBootstrapCommandPlatformSection(
355
379
  options: Pick<
356
380
  BootstrapCommandSectionOptions,
357
- 'configManager' | 'voiceProviderRegistry' | 'voiceService'
381
+ 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
358
382
  >,
359
383
  shellServices: BootstrapCommandShellServices,
360
384
  ): BootstrapCommandPlatformSection {
@@ -363,6 +387,9 @@ export function createBootstrapCommandPlatformSection(
363
387
  configManager: options.configManager,
364
388
  voiceProviderRegistry: options.voiceProviderRegistry,
365
389
  voiceService: options.voiceService,
390
+ webSearchService: options.webSearchService,
391
+ mediaProviders: options.mediaProviders,
392
+ artifactStore: options.artifactStore,
366
393
  ...shellServices.platform,
367
394
  };
368
395
  }
@@ -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,7 @@ 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';
37
36
 
38
37
  // ---------------------------------------------------------------------------
39
38
  // Pre-router buffer
@@ -637,10 +636,20 @@ export async function initializeBootstrapCore(
637
636
 
638
637
  providerRegistry.startWatching(runtimeBus);
639
638
 
639
+ // W2.3: attach the SAME WebhookNotifier instance that `/notify add|remove|clear`
640
+ // (notify-runtime.ts) keeps live via ctx.services.webhookNotifier, rather than
641
+ // constructing a second, boot-time-only instance here. Before this fix, a
642
+ // webhook URL added mid-session reached long-task notifications (which read
643
+ // ctx.services.webhookNotifier directly) but never reached this instance's
644
+ // AGENT_FAILED/WORKFLOW_CHAIN_FAILED/WORKFLOW_CHAIN_PASSED runtime-bus
645
+ // listeners until restart — and if the session started with zero URLs
646
+ // configured, attachToRuntimeBus was never even called, so those listeners
647
+ // never existed at all for the rest of the session. Always attaching
648
+ // (regardless of initial URL count) and seeding the shared instance fixes
649
+ // both: `send()` is already a safe no-op with zero URLs configured.
640
650
  const webhookUrls = (configManager.getCategory('notifications') as { webhookUrls?: string[] }).webhookUrls ?? [];
641
651
  if (webhookUrls.length > 0) {
642
- const webhookNotifier = WebhookNotifier.fromConfig(webhookUrls);
643
- webhookNotifier.attachToRuntimeBus(runtimeBus);
652
+ services.webhookNotifier.setUrls(webhookUrls);
644
653
  domainDispatch.syncIntegration({
645
654
  id: 'webhooks',
646
655
  displayName: 'Webhooks',
@@ -652,6 +661,7 @@ export async function initializeBootstrapCore(
652
661
  meta: { urlCount: webhookUrls.length },
653
662
  }, 'bootstrap.webhooks');
654
663
  }
664
+ services.webhookNotifier.attachToRuntimeBus(runtimeBus);
655
665
 
656
666
  const notifier = await Notifier.fromConfig(services.serviceRegistry);
657
667
  const queueStatuses = notifier.getQueueStatus();
@@ -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';
@@ -40,11 +40,6 @@ export interface BootstrapShellState {
40
40
  readonly lastGitInfoRef: { value: GitHeaderInfo | undefined };
41
41
  readonly inputHistory: InputHistory;
42
42
  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
43
  }
49
44
 
50
45
  export interface BootstrapShellOptions {
@@ -92,7 +87,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
92
87
  completeModelSelectionSideEffect,
93
88
  } = options;
94
89
 
95
- const systemMessagesPanel = new SystemMessagesPanel(configManager, services.componentHealthMonitor);
96
90
  // W0.9: after any resume seam replays historical messages into `conversation`,
97
91
  // the freshly-constructed `orchestrator` still has its zeroed default usage
98
92
  // (SDK gap — Orchestrator.usage is never persisted/reseeded). Recompute it
@@ -138,16 +132,22 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
138
132
  runtimeBus,
139
133
  });
140
134
 
141
- const openAgentDetailRef: { fn: (agentId: string) => void } = { fn: (_agentId: string) => {} };
142
-
143
135
  // WO-139: initial cost-budget alert threshold (USD; 0/unset = disabled).
144
136
  // Once the session starts, the real control surface is the CostTrackerPanel
145
137
  // itself — the in-panel 'b' key and /cost budget <usd> both call
146
- // CostTrackerPanel.setBudgetThreshold() directly on the live panel instance.
138
+ // CostTrackerPanel.setBudgetThreshold() directly on the live panel instance,
139
+ // which (W2.3) now writes through to the behavior.budgetAlertUsd config key
140
+ // so the background budget-breach notifier reads the same value. The env
141
+ // var remains a first-run convenience only: it seeds the config key when
142
+ // that key has never been set, so it doesn't silently override a value the
143
+ // user has already configured in a prior session.
147
144
  const parsedBudgetThreshold = Number(process.env.GOODVIBES_COST_BUDGET_USD);
148
145
  const initialCostBudgetThreshold = Number.isFinite(parsedBudgetThreshold) && parsedBudgetThreshold > 0
149
146
  ? parsedBudgetThreshold
150
147
  : 0;
148
+ if (initialCostBudgetThreshold > 0 && readBudgetAlertUsd((k) => configManager.get(k as Parameters<typeof configManager.get>[0])) === BUDGET_ALERT_USD_DEFAULT) {
149
+ configManager.set('behavior.budgetAlertUsd' as Parameters<typeof configManager.set>[0], initialCostBudgetThreshold as never);
150
+ }
151
151
 
152
152
  let commandContextRef: CommandContext | null = null;
153
153
  registerBuiltinPanels(services.panelManager, {
@@ -182,7 +182,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
182
182
  componentHealthMonitor: services.componentHealthMonitor,
183
183
  worktreeRegistry: services.worktreeRegistry,
184
184
  sandboxSessionRegistry: services.sandboxSessionRegistry,
185
- systemMessagesPanel,
186
185
  memoryRegistry: services.memoryRegistry,
187
186
  uiServices,
188
187
  pluginManager: services.pluginManager,
@@ -190,7 +189,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
190
189
  hookActivityTracker: services.hookActivityTracker,
191
190
  hookWorkbench: services.hookWorkbench,
192
191
  mcpRegistry: services.mcpRegistry,
193
- openAgentDetail: (agentId: string) => openAgentDetailRef.fn(agentId),
194
192
  daemonHomeDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
195
193
  opsApi,
196
194
  planRuntime,
@@ -203,7 +201,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
203
201
 
204
202
  const systemMessageRouter = createSystemMessageRouter(
205
203
  conversation,
206
- systemMessagesPanel,
207
204
  (kind) => {
208
205
  const ui = getConfigSnapshot(configManager).ui;
209
206
  if (kind === 'wrfc') return ui.wrfcMessages;
@@ -233,6 +230,9 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
233
230
  mcpRegistry: services.mcpRegistry,
234
231
  voiceProviderRegistry: services.voiceProviders,
235
232
  voiceService: services.voiceService,
233
+ webSearchService: services.webSearchService,
234
+ mediaProviders: services.mediaProviders,
235
+ artifactStore: services.artifactStore,
236
236
  forensicsRegistry,
237
237
  policyRuntimeState,
238
238
  readModels: uiServices.readModels,
@@ -240,6 +240,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
240
240
  remoteRuntime,
241
241
  planRuntime,
242
242
  fileUndoManager: services.fileUndoManager,
243
+ workspaceCheckpointManager: services.workspaceCheckpointManager,
243
244
  memoryRegistry: services.memoryRegistry,
244
245
  integrationHelpers: services.integrationHelpers,
245
246
  automationManager: services.automationManager,
@@ -268,6 +269,11 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
268
269
  sessionMemoryStore: services.sessionMemoryStore,
269
270
  sessionLineageTracker: services.sessionLineageTracker,
270
271
  wrfcController: services.wrfcController,
272
+ workstreamEngine: services.workstreamCommands,
273
+ codeIndexStore: services.codeIndexStore,
274
+ // Wave 5 (wo805): expose the MAIN session's per-turn passive-injection ring
275
+ // so `/recall injections` (no agent id) renders it — see recall-review.ts.
276
+ getMainSessionTurnInjections: () => orchestrator.getTurnInjections(),
271
277
  changeTracker: services.sessionChangeTracker,
272
278
  planManager: services.planManager,
273
279
  adaptivePlanner: services.adaptivePlanner,
@@ -302,6 +308,16 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
302
308
  lastGitInfoRef.value = info;
303
309
  requestRender();
304
310
  }).catch(() => { /* non-fatal */ });
311
+ // W1.6 FIX 2: the header's git segment otherwise only refreshes on
312
+ // TURN_COMPLETED/TOOL_SUCCEEDED/TOOL_FAILED (see turn-event-wiring.ts's
313
+ // refreshGit()) — if the user runs `git init` externally and never submits
314
+ // another turn, the header stays stuck on the startup-time fallback
315
+ // indefinitely. Poll at the same 5s cadence GitPanel already uses for its
316
+ // own self-poll (git-panel.ts) so the two mechanisms are cadence-consistent.
317
+ gitStatusProvider.startPolling(5_000, (info) => {
318
+ lastGitInfoRef.value = info;
319
+ requestRender();
320
+ });
305
321
 
306
322
  const saveHistory = configManager.get('behavior.saveHistory') as boolean;
307
323
  const inputHistory = new InputHistory({
@@ -316,8 +332,5 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
316
332
  lastGitInfoRef,
317
333
  inputHistory,
318
334
  systemMessageRouter,
319
- setOpenAgentDetail: (fn: (agentId: string) => void) => {
320
- openAgentDetailRef.fn = fn;
321
- },
322
335
  };
323
336
  }
@@ -42,6 +42,7 @@ import type { UiRuntimeServices } from './ui-services.ts';
42
42
  import { createDeferredStartupCoordinator } from '@/runtime/index.ts';
43
43
  import { initializeBootstrapCore } from './bootstrap-core.ts';
44
44
  import { createBootstrapShell } from './bootstrap-shell.ts';
45
+ import { buildSharedOrchestratorCoreServices } from './orchestrator-core-services.ts';
45
46
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
46
47
  import { DaemonServer } from '@pellux/goodvibes-sdk/platform/daemon';
47
48
  import { HttpListener } from '@pellux/goodvibes-sdk/platform/daemon';
@@ -110,19 +111,15 @@ export type BootstrapContext = RuntimeContext & {
110
111
  /** Command registry used by InputHandler. main.ts needs this to wire input. */
111
112
  commandRegistry: import('../input/command-registry.ts').CommandRegistry;
112
113
  /**
113
- * System message router instantiated at startup, wired to conversation and panel manager.
114
+ * System message router instantiated at startup, wired to conversation.
114
115
  *
115
116
  * @remarks
116
117
  * Route operational messages through this rather than calling
117
- * conversation.addSystemMessage() directly so that low-priority messages
118
- * stay out of the main conversation and go to the SystemMessagesPanel instead.
118
+ * conversation.addSystemMessage() directly so routing-target config
119
+ * (panel/conversation/both) and the forced-inline critical prefixes stay
120
+ * centralized in one place.
119
121
  */
120
122
  systemMessageRouter: SystemMessageRouter;
121
- /**
122
- * Wire the agent detail modal opener after InputHandler is constructed in main.ts.
123
- * Call with `(id) => input.agentDetailModal.open(id)` once the InputHandler is ready.
124
- */
125
- setOpenAgentDetail: (fn: (agentId: string) => void) => void;
126
123
  };
127
124
 
128
125
  // ── Bootstrap function ────────────────────────────────────────────────────
@@ -235,15 +232,11 @@ export async function bootstrapRuntime(
235
232
  logger.debug('companion handleUserInput safety catch', { error: String(err) });
236
233
  });
237
234
  };
235
+ // Shared payload (single source of truth, includes wo805's memoryRegistry —
236
+ // see orchestrator-core-services.ts) plus this site's cacheHitTracker.
238
237
  orchestrator.setCoreServices({
239
- configManager,
240
- providerRegistry,
238
+ ...buildSharedOrchestratorCoreServices({ services, configManager, providerRegistry }),
241
239
  cacheHitTracker: services.cacheHitTracker,
242
- planManager: services.planManager,
243
- adaptivePlanner: services.adaptivePlanner,
244
- sessionMemoryStore: services.sessionMemoryStore,
245
- sessionLineageTracker: services.sessionLineageTracker,
246
- idempotencyStore: services.idempotencyStore,
247
240
  });
248
241
  conversation.setSessionLineageTracker(services.sessionLineageTracker);
249
242
 
@@ -297,7 +290,9 @@ export async function bootstrapRuntime(
297
290
  const gitStatusProvider = shell.gitStatusProvider;
298
291
  const inputHistory = shell.inputHistory;
299
292
  const lastGitInfoRef = shell.lastGitInfoRef;
300
- const setOpenAgentDetail = shell.setOpenAgentDetail;
293
+ // W1.6 FIX 2: dispose the header's live-repo-state poll (git-status.ts
294
+ // startPolling) on shutdown, same pattern as acpTaskSyncInterval above.
295
+ bootstrapUnsubs.push(() => gitStatusProvider.stopPolling());
301
296
  const pluginCommandRegistry = {
302
297
  register(command: {
303
298
  readonly name: string;
@@ -628,7 +623,6 @@ export async function bootstrapRuntime(
628
623
  _getConfiguredProviderIds: () => services.providerRegistry.getConfiguredProviderIds(),
629
624
  commandRegistry,
630
625
  systemMessageRouter,
631
- setOpenAgentDetail,
632
626
  shutdown: async (sessionData) => {
633
627
  // Clear bootstrap-owned subscriptions
634
628
  bootstrapUnsubs.forEach(fn => fn());
@@ -0,0 +1,112 @@
1
+ // ---------------------------------------------------------------------------
2
+ // code-index-services.ts — Wave 5 (wo804, W5.3 Stage A TUI wiring)
3
+ //
4
+ // Constructs the TUI's repo source-tree code index: CodeIndexStore
5
+ // (@pellux/goodvibes-sdk/platform/state, landed on SDK main as wo802/W5.3
6
+ // Stage A). Extracted into its own module rather than built inline in
7
+ // services.ts: services.ts sits at the architecture check's 800-line cap
8
+ // (scripts/check-architecture.ts), so any new service gets its own
9
+ // construction module and a single wiring call there (mirrors
10
+ // createWorkstreamServices's one-function-bundle shape).
11
+ //
12
+ // Schema-initialized eagerly (mirrors memoryStore: construction + init()
13
+ // happen unconditionally so the store is queryable — /codebase status, the
14
+ // fleet node — even before any build has ever run). The actual walk/chunk/
15
+ // embed build is NEVER auto-triggered by default: the hundreds of existing
16
+ // test fixtures (and every headless invocation) construct RuntimeServices
17
+ // without asking for a full source-tree walk, and init() alone never runs
18
+ // one (mirrors the SDK's own RuntimeServices wiring in
19
+ // platform/runtime/services.ts, which gates its equivalent scheduleBuild()
20
+ // call behind an explicit autoStartCodeIndex option).
21
+ //
22
+ // REALITY-WINS DIVERGENCE from the SDK's own shape: the SDK's
23
+ // RuntimeServicesOptions exposes autoStartCodeIndex as a constructor-time
24
+ // boolean because that call site is a library entrypoint threaded by each
25
+ // embedder. This TUI's createRuntimeServices has no such per-call knob —
26
+ // auto-start is decided from a TUI-local config key instead
27
+ // (CODE_INDEX_ENABLED_CONFIG_KEY, default OFF), so every construction path
28
+ // (interactive main.ts, the daemon, and every test fixture) shares one
29
+ // honest, user-visible on/off switch rather than needing to thread a new
30
+ // boolean through every call site. With it off (the default), `/codebase
31
+ // build` is the explicit, visible trigger — exactly the shape wo804's brief
32
+ // asks for.
33
+ //
34
+ // Shares memoryEmbeddingRegistry with MemoryStore (constructed in
35
+ // services.ts) so code + memory retrieval use one embedding provider and one
36
+ // dimensionality, per the SDK design doc (code-index-store.ts's constructor
37
+ // takes the SAME MemoryEmbeddingProviderRegistry instance memory uses).
38
+ // ---------------------------------------------------------------------------
39
+
40
+ import { join } from 'node:path';
41
+ import { CodeIndexStore } from '@pellux/goodvibes-sdk/platform/state';
42
+ import type { MemoryEmbeddingProviderRegistry } from '@pellux/goodvibes-sdk/platform/state';
43
+ import type { ConfigKey, ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
44
+ import { readBooleanConfig } from '../core/alert-gating.ts';
45
+
46
+ /**
47
+ * TUI-local synthetic config key (not yet in the SDK's ConfigKey union) that
48
+ * gates the code index's auto-build on construction. Default OFF — see this
49
+ * module's header doc. Surfaced in /config via a synthetic entry
50
+ * (settings-modal-data.ts) exactly like behavior.notifyAfterSeconds.
51
+ */
52
+ export const CODE_INDEX_ENABLED_CONFIG_KEY = 'storage.codeIndexEnabled';
53
+
54
+ /**
55
+ * Honest, generous bounds passed EXPLICITLY to CodeIndexStore (values equal
56
+ * to its own internal defaults) so /codebase status and the settings
57
+ * description can state them in one place without reaching into store
58
+ * internals or duplicating magic numbers.
59
+ */
60
+ export const CODE_INDEX_MAX_FILES = 5000;
61
+ export const CODE_INDEX_MAX_FILE_BYTES = 512 * 1024;
62
+ export const CODE_INDEX_MAX_TOTAL_BYTES = 256 * 1024 * 1024;
63
+
64
+ export interface CodeIndexServicesDeps {
65
+ readonly workingDirectory: string;
66
+ readonly configManager: Pick<ConfigManager, 'get'>;
67
+ readonly memoryEmbeddingRegistry: MemoryEmbeddingProviderRegistry;
68
+ }
69
+
70
+ export interface CodeIndexServices {
71
+ readonly codeIndexStore: CodeIndexStore;
72
+ }
73
+
74
+ /** Absolute path to the TUI's code-index sqlite file, sibling to memory.sqlite under .goodvibes/tui/. */
75
+ export function codeIndexDbPath(workingDirectory: string): string {
76
+ return join(workingDirectory, '.goodvibes', 'tui', 'code-index.sqlite');
77
+ }
78
+
79
+ /**
80
+ * Whether the code index's initial build should auto-start on construction.
81
+ * Exported so /codebase status and the settings modal read the exact same
82
+ * config key + default this module decides auto-start from.
83
+ */
84
+ export function isCodeIndexAutoStartEnabled(configManager: Pick<ConfigManager, 'get'>): boolean {
85
+ return readBooleanConfig(
86
+ (key) => configManager.get(key as ConfigKey),
87
+ CODE_INDEX_ENABLED_CONFIG_KEY,
88
+ false,
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Constructs the TUI's CodeIndexStore. Schema-init runs unconditionally
94
+ * (init() never throws — it degrades to an honest `available: false` +
95
+ * recorded error on failure, mirrored by CodeIndexStats/describeDegradation);
96
+ * the initial full build only fires when isCodeIndexAutoStartEnabled() is
97
+ * true, via the SAME fire-and-forget scheduleBuild() an explicit
98
+ * `/codebase build` invocation uses.
99
+ */
100
+ export function createCodeIndexServices(deps: CodeIndexServicesDeps): CodeIndexServices {
101
+ const codeIndexStore = new CodeIndexStore(
102
+ deps.workingDirectory,
103
+ codeIndexDbPath(deps.workingDirectory),
104
+ deps.memoryEmbeddingRegistry,
105
+ { maxFiles: CODE_INDEX_MAX_FILES, maxFileBytes: CODE_INDEX_MAX_FILE_BYTES, maxTotalBytes: CODE_INDEX_MAX_TOTAL_BYTES },
106
+ );
107
+ codeIndexStore.init();
108
+ if (isCodeIndexAutoStartEnabled(deps.configManager)) {
109
+ codeIndexStore.scheduleBuild();
110
+ }
111
+ return { codeIndexStore };
112
+ }
@@ -0,0 +1,49 @@
1
+ import type { OrchestratorCoreServices } from '@pellux/goodvibes-sdk/platform/core';
2
+ import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
3
+ import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
4
+ import type { RuntimeServices } from './services.ts';
5
+
6
+ /** The slice of the runtime services bag the shared orchestrator payload draws from. */
7
+ export type OrchestratorCoreServicesSource = Pick<
8
+ RuntimeServices,
9
+ | 'planManager'
10
+ | 'adaptivePlanner'
11
+ | 'sessionMemoryStore'
12
+ | 'sessionLineageTracker'
13
+ | 'idempotencyStore'
14
+ | 'memoryRegistry'
15
+ >;
16
+
17
+ /**
18
+ * The single source of truth for the `Orchestrator.setCoreServices()` payload
19
+ * fields shared by BOTH call sites (runtime/bootstrap.ts and main.ts). Each
20
+ * site spreads this and adds its own site-specific extras (bootstrap:
21
+ * cacheHitTracker; main: favoritesStore) — setCoreServices() merges, so the
22
+ * later main.ts call only overlays, never erases.
23
+ *
24
+ * Wave-5 (wo805) BLOCKER regression guard: `memoryRegistry` here is what turns
25
+ * on per-turn passive knowledge injection for the MAIN interactive session —
26
+ * the SDK turn loop hard-gates on `coreServices.memoryRegistry` (undefined is
27
+ * a silent no-op: Orchestrator.getTurnInjections() stays empty forever and
28
+ * `/recall injections` renders a misleading empty state). Both call sites once
29
+ * omitted it independently; routing them through this one function (with
30
+ * src/test/runtime/orchestrator-core-services.test.ts pinning the field) is
31
+ * what keeps that from regressing.
32
+ */
33
+ export function buildSharedOrchestratorCoreServices(input: {
34
+ readonly services: OrchestratorCoreServicesSource;
35
+ readonly configManager: ConfigManager;
36
+ readonly providerRegistry: ProviderRegistry;
37
+ }): OrchestratorCoreServices {
38
+ const { services, configManager, providerRegistry } = input;
39
+ return {
40
+ configManager,
41
+ providerRegistry,
42
+ planManager: services.planManager,
43
+ adaptivePlanner: services.adaptivePlanner,
44
+ sessionMemoryStore: services.sessionMemoryStore,
45
+ sessionLineageTracker: services.sessionLineageTracker,
46
+ idempotencyStore: services.idempotencyStore,
47
+ memoryRegistry: services.memoryRegistry,
48
+ };
49
+ }
@@ -34,6 +34,8 @@ export interface ProcessLifecycleAnsi {
34
34
  readonly KEYBOARD_EXT_DISABLE: string;
35
35
  readonly MOUSE_DISABLE: string;
36
36
  readonly CURSOR_SHOW: string;
37
+ /** Disables terminal focus-event reporting (DECSET ?1004l) — see main.ts FOCUS_ENABLE. */
38
+ readonly FOCUS_DISABLE: string;
37
39
  }
38
40
 
39
41
  export interface ProcessLifecycleDeps {
@@ -128,7 +130,7 @@ export function installProcessLifecycle(deps: ProcessLifecycleDeps): ProcessLife
128
130
  if (terminalRestored) return;
129
131
  terminalRestored = true;
130
132
  const exitScreen = noAltScreen ? ansi.CLEAR_SCREEN : ansi.CLEAR_SCREEN + ansi.ALT_SCREEN_EXIT;
131
- allowTerminalWrite(() => stdout.write(ansi.PASTE_DISABLE + ansi.KEYBOARD_EXT_DISABLE + ansi.MOUSE_DISABLE + ansi.CURSOR_SHOW + exitScreen));
133
+ allowTerminalWrite(() => stdout.write(ansi.PASTE_DISABLE + ansi.KEYBOARD_EXT_DISABLE + ansi.MOUSE_DISABLE + ansi.FOCUS_DISABLE + ansi.CURSOR_SHOW + exitScreen));
132
134
  getTerminalOutputGuard().dispose();
133
135
  try { stdin.setRawMode(false); } catch { /* stdin may not be a TTY */ }
134
136
  };