@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
@@ -1,11 +1,9 @@
1
1
  import { join } from 'node:path';
2
- import { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
2
+ import { FocusTracker } from '../core/focus-tracker.ts';
3
+ import { ConfigManager, ServiceRegistry, SubscriptionManager, ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
3
4
  import { SecretsManager } from '../config/secrets.ts';
4
- import { ServiceRegistry } from '@pellux/goodvibes-sdk/platform/config';
5
- import { SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config';
6
5
  import { AutomationDeliveryManager, AutomationManager, AutomationRouteStore } from '@pellux/goodvibes-sdk/platform/automation';
7
- import { ChannelPluginRegistry, ChannelPolicyManager, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
8
- import { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
6
+ import { ChannelDeliveryRouter, ChannelPluginRegistry, ChannelPolicyManager, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
9
7
  import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
10
8
  import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
11
9
  import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
@@ -23,16 +21,10 @@ import {
23
21
  } from '@pellux/goodvibes-sdk/platform/knowledge';
24
22
  import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
25
23
  import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
26
- import { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
27
- import { AgentMessageBus } from '@pellux/goodvibes-sdk/platform/agents';
28
- import { WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
29
- import { AgentOrchestrator } from '@pellux/goodvibes-sdk/platform/agents';
30
- import { ArchetypeLoader } from '@pellux/goodvibes-sdk/platform/agents';
31
- import { ProcessManager } from '@pellux/goodvibes-sdk/platform/tools';
32
- import { ModeManager } from '@pellux/goodvibes-sdk/platform/state';
33
- import { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
34
- import { MemoryRegistry } from '@pellux/goodvibes-sdk/platform/state';
35
- import { MemoryStore } from '@pellux/goodvibes-sdk/platform/state';
24
+ import { AgentMessageBus, AgentOrchestrator, ArchetypeLoader, WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
25
+ import { AgentManager, OverflowHandler, ProcessManager, createWorkflowServices, type WorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
26
+ import { FileStateCache, FileUndoManager, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, type CodeIndexStore } from '@pellux/goodvibes-sdk/platform/state';
27
+ import { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
36
28
  import type { RuntimeEventBus } from '@/runtime/index.ts';
37
29
  import { createDomainDispatch } from './store/index.ts';
38
30
  import type { DomainDispatch, RuntimeStore } from './store/index.ts';
@@ -41,40 +33,20 @@ import { RemoteRunnerRegistry, RemoteSupervisor } from '@/runtime/index.ts';
41
33
  import { IntegrationHelperService } from '@/runtime/index.ts';
42
34
  import { VoiceProviderRegistry, VoiceService, ensureBuiltinVoiceProviders } from '@pellux/goodvibes-sdk/platform/voice';
43
35
  import { WebSearchProviderRegistry, WebSearchService } from '@pellux/goodvibes-sdk/platform/web-search';
44
- import { MemoryEmbeddingProviderRegistry } from '@pellux/goodvibes-sdk/platform/state';
45
36
  import { PanelManager } from '../panels/panel-manager.ts';
46
37
  import { HookActivityTracker } from '@pellux/goodvibes-sdk/platform/hooks';
47
38
  import { HookDispatcher, createHookWorkbench, type HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks';
48
39
  import { PluginManager } from '@pellux/goodvibes-sdk/platform/plugins';
49
40
  import { BookmarkManager } from '@pellux/goodvibes-sdk/platform/bookmarks';
50
41
  import { ProfileManager } from '@pellux/goodvibes-sdk/platform/profiles';
51
- import { SessionManager } from '@pellux/goodvibes-sdk/platform/sessions';
52
- import { CrossSessionTaskRegistry } from '@pellux/goodvibes-sdk/platform/sessions';
53
- import { ApiTokenAuditor } from '@pellux/goodvibes-sdk/platform/security';
54
- import { UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
42
+ import { SessionManager, CrossSessionTaskRegistry, SessionChangeTracker } from '@pellux/goodvibes-sdk/platform/sessions';
43
+ import { ApiTokenAuditor, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
55
44
  import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
56
45
  import { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
57
- import { DeterministicReplayEngine } from '@pellux/goodvibes-sdk/platform/core';
58
- import { ProviderOptimizer } from '@pellux/goodvibes-sdk/platform/providers';
59
- import { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
60
- import type { ModelDefinition } from '@pellux/goodvibes-sdk/platform/providers';
61
- import { ProviderCapabilityRegistry } from '@pellux/goodvibes-sdk/platform/providers';
62
- import { CacheHitTracker } from '@pellux/goodvibes-sdk/platform/providers';
63
- import { FavoritesStore } from '@pellux/goodvibes-sdk/platform/providers';
64
- import { BenchmarkStore } from '@pellux/goodvibes-sdk/platform/providers';
65
- import { ModelLimitsService } from '@pellux/goodvibes-sdk/platform/providers';
66
- import { inferFallbackContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
46
+ import { BenchmarkStore, CacheHitTracker, FavoritesStore, inferFallbackContextWindow, type ModelDefinition, ModelLimitsService, ProviderCapabilityRegistry, ProviderOptimizer, ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
67
47
  import { KeybindingsManager } from '../input/keybindings.ts';
68
- import { SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
69
- import { SessionLineageTracker } from '@pellux/goodvibes-sdk/platform/core';
70
- import { SessionChangeTracker } from '@pellux/goodvibes-sdk/platform/sessions';
71
- import { ExecutionPlanManager } from '@pellux/goodvibes-sdk/platform/core';
72
- import { AdaptivePlanner } from '@pellux/goodvibes-sdk/platform/core';
73
- import { FileStateCache } from '@pellux/goodvibes-sdk/platform/state';
74
- import { ProjectIndex } from '@pellux/goodvibes-sdk/platform/state';
48
+ import { AdaptivePlanner, DeterministicReplayEngine, ExecutionPlanManager, SessionLineageTracker, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
75
49
  import { IdempotencyStore } from '@/runtime/index.ts';
76
- import { OverflowHandler } from '@pellux/goodvibes-sdk/platform/tools';
77
- import { ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
78
50
  import { ComponentHealthMonitor } from '@/runtime/index.ts';
79
51
  import { WorktreeRegistry } from '@/runtime/index.ts';
80
52
  import { SandboxSessionRegistry } from '@/runtime/index.ts';
@@ -83,10 +55,10 @@ import { isFeatureFlagEnabled } from './surface-feature-flags.ts';
83
55
  import type { FeatureFlagManager } from '@/runtime/index.ts';
84
56
  import { createFeatureFlagManager } from '@/runtime/index.ts';
85
57
  import { PolicyRuntimeState } from '@/runtime/index.ts';
86
- import {
87
- createWorkflowServices,
88
- type WorkflowServices,
89
- } from '@pellux/goodvibes-sdk/platform/tools';
58
+ import { createProcessRegistry, type ProcessRegistry } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
59
+ import { calcSessionCost, isModelPriced } from '../export/cost-utils.ts';
60
+ import { createWorkstreamServices, type OrchestrationEngine, type WorkstreamCommandService } from './workstream-services.ts';
61
+ import { codeIndexDbPath, createCodeIndexServices } from './code-index-services.ts';
90
62
  import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
91
63
  import {
92
64
  registerDaemonHandlers,
@@ -221,6 +193,8 @@ export interface RuntimeServices {
221
193
  readonly worktreeRegistry: WorktreeRegistry;
222
194
  readonly sandboxSessionRegistry: SandboxSessionRegistry;
223
195
  readonly webhookNotifier: WebhookNotifier;
196
+ /** Terminal focus tracker (W2.3) — fed by input/handler-feed.ts, read by the alert notifiers in core/. */
197
+ readonly focusTracker: FocusTracker;
224
198
  readonly replayEngine: DeterministicReplayEngine;
225
199
  readonly providerOptimizer: ProviderOptimizer;
226
200
  readonly providerCapabilityRegistry: ProviderCapabilityRegistry;
@@ -248,8 +222,16 @@ export interface RuntimeServices {
248
222
  readonly agentOrchestrator: AgentOrchestrator;
249
223
  readonly wrfcController: WrfcController;
250
224
  readonly processManager: ProcessManager;
225
+ /** Wave 4 (wo703): the phase/work-item orchestration engine — see runtime/workstream-services.ts. */
226
+ readonly orchestrationEngine: OrchestrationEngine;
227
+ readonly workstreamCommands: WorkstreamCommandService;
228
+ /** Wave 5 (wo804): the repo source-tree code index — see runtime/code-index-services.ts. */
229
+ readonly codeIndexStore: CodeIndexStore;
230
+ /** W2.1/W2.2: unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the Fleet panel. */
231
+ readonly processRegistry: ProcessRegistry;
251
232
  readonly modeManager: ModeManager;
252
233
  readonly fileUndoManager: FileUndoManager;
234
+ readonly workspaceCheckpointManager: WorkspaceCheckpointManager;
253
235
  readonly integrationHelpers: IntegrationHelperService;
254
236
  /**
255
237
  * Re-root path-bound stores (MemoryStore, ProjectIndex) to a new working directory.
@@ -272,6 +254,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
272
254
  const runtimeDispatch = createDomainDispatch(options.runtimeStore);
273
255
  const gatewayMethods = new GatewayMethodCatalog();
274
256
  const panelManager = new PanelManager();
257
+ // W6.1 (the purge): MIGRATE-TO-MODAL surface + redirect registration moved to
258
+ // registerBuiltinPanels (builtin-panels.ts), where the panels' resolved deps
259
+ // are available for the surfaces to close over.
275
260
  const keybindingsManager = new KeybindingsManager({
276
261
  configPath: shellPaths.resolveUserPath('tui', 'keybindings.json'),
277
262
  });
@@ -352,6 +337,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
352
337
  executor: agentOrchestrator,
353
338
  configManager,
354
339
  });
340
+ agentOrchestrator.setConversationSink({ // Wave-3 Part C6 bridge (mirrors the SDK's own createRuntimeServices)
341
+ register: (agentId, source) => agentManager.registerConversationSource(agentId, source),
342
+ release: (agentId) => agentManager.releaseConversationSource(agentId),
343
+ });
355
344
  agentManager.setRuntimeBus(options.runtimeBus);
356
345
  const wrfcController = new WrfcController(options.runtimeBus, agentMessageBus, {
357
346
  agentManager,
@@ -580,6 +569,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
580
569
  const componentHealthMonitor = new ComponentHealthMonitor();
581
570
  const worktreeRegistry = new WorktreeRegistry(workingDirectory);
582
571
  const webhookNotifier = new WebhookNotifier();
572
+ const focusTracker = new FocusTracker();
583
573
  const replayEngine = new DeterministicReplayEngine(workingDirectory);
584
574
  const providerOptimizer = new ProviderOptimizer(
585
575
  providerRegistry,
@@ -603,8 +593,57 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
603
593
  artifactStore,
604
594
  });
605
595
  const processManager = new ProcessManager();
596
+ // Wave 4 (wo703): the phase/work-item orchestration engine, constructed
597
+ // before the process registry so its fleet nodes (workstream/phase/
598
+ // work-item) can be folded in below via the registry's optional
599
+ // orchestrationEngine dep.
600
+ const { orchestrationEngine, workstreamCommands } = createWorkstreamServices({
601
+ agentManager, configManager, adaptivePlanner, runtimeBus: options.runtimeBus, projectRoot: workingDirectory,
602
+ });
603
+ // Wave 5 (wo804): repo source-tree code index, sharing memoryEmbeddingRegistry
604
+ // with MemoryStore above. Auto-build is config-gated (default off) — see
605
+ // code-index-services.ts's header doc.
606
+ const { codeIndexStore } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry });
607
+ // W2.1/W2.2: one shared process registry aggregating the managers above —
608
+ // the Fleet panel (panels/fleet-read-model.ts) is its first consumer.
609
+ // Constructed once here (not per-consumer) so the coalesced tick and the
610
+ // agent-activity side-table are shared, not duplicated.
611
+ const processRegistry = createProcessRegistry({
612
+ agentManager,
613
+ wrfcController,
614
+ orchestrationEngine, // Wave 4 (wo703): folds workstream/phase/work-item nodes into the fleet
615
+ codeIndexService: codeIndexStore, // Wave 5 (wo804): folds a single 'code-index' node into the fleet
616
+ processManager,
617
+ watcherRegistry,
618
+ workflow,
619
+ approvalBroker,
620
+ sessionBroker,
621
+ messageBus: agentMessageBus, // Wave-3: backs steer()/`steerable` (wo612 builds the composer UI on top)
622
+ automationManager, // Wave 6 (wo-F item d4): folds /schedule AutomationJobs into the fleet as 'schedule' nodes
623
+ runtimeBus: options.runtimeBus,
624
+ // Honest pricing: never fabricate a cost for an unrecognized model.
625
+ priceUsage: (model, usage) => {
626
+ const modelId = model ?? 'unknown';
627
+ if (!isModelPriced(modelId)) return null;
628
+ return calcSessionCost(usage.inputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens, modelId);
629
+ },
630
+ });
606
631
  const modeManager = new ModeManager();
607
632
  const fileUndoManager = new FileUndoManager();
633
+ const workspaceCheckpointManager = new WorkspaceCheckpointManager({
634
+ workspaceRoot: workingDirectory,
635
+ runtimeBus: options.runtimeBus,
636
+ });
637
+ // Fire-and-forget: subscriptions go live immediately if init() succeeds.
638
+ // If it rejects, WorkspaceCheckpointManager caches that rejection on
639
+ // `initPromise` and never clears it, so every later call (create/list/
640
+ // diff/restore — each awaits init() first) re-throws the same error
641
+ // forever: checkpointing becomes entirely unavailable for the rest of the
642
+ // session, not "degraded to manual-only". The `.catch(() => {})` here only
643
+ // exists to prevent an unhandled rejection at startup; the checkpoint
644
+ // commands (checkpoint-runtime.ts) are what actually catch and report the
645
+ // failure to the user, on first use.
646
+ void workspaceCheckpointManager.init().catch(() => {});
608
647
  const integrationHelpers = new IntegrationHelperService({
609
648
  workingDirectory,
610
649
  homeDirectory,
@@ -709,6 +748,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
709
748
  worktreeRegistry,
710
749
  sandboxSessionRegistry,
711
750
  webhookNotifier,
751
+ focusTracker,
712
752
  replayEngine,
713
753
  providerOptimizer,
714
754
  providerCapabilityRegistry,
@@ -736,12 +776,20 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
736
776
  agentOrchestrator,
737
777
  wrfcController,
738
778
  processManager,
779
+ orchestrationEngine,
780
+ workstreamCommands,
781
+ codeIndexStore,
782
+ processRegistry,
739
783
  modeManager,
740
784
  fileUndoManager,
785
+ workspaceCheckpointManager,
741
786
  integrationHelpers,
742
787
  async rerootStores(newWorkingDir: string): Promise<void> {
743
788
  const newMemoryDbPath = join(newWorkingDir, '.goodvibes', 'tui', 'memory.sqlite');
744
789
  await memoryStore.reroot(newMemoryDbPath);
790
+ // Wave 5 (wo804) risk #7: the code index must follow memory to the new
791
+ // tree, or it keeps pointing at the old working directory.
792
+ await codeIndexStore.reroot(newWorkingDir, codeIndexDbPath(newWorkingDir));
745
793
  await projectIndex.reroot(newWorkingDir);
746
794
  },
747
795
  };
@@ -55,6 +55,7 @@ export interface UiPlatformServices {
55
55
  readonly tokenAuditor: RuntimeServices['tokenAuditor'];
56
56
  readonly replayEngine: RuntimeServices['replayEngine'];
57
57
  readonly webhookNotifier: RuntimeServices['webhookNotifier'];
58
+ readonly focusTracker: RuntimeServices['focusTracker'];
58
59
  readonly policyRuntimeState: RuntimeServices['policyRuntimeState'];
59
60
  readonly externalServices?: {
60
61
  inspect(): {
@@ -101,6 +102,10 @@ export interface UiRuntimeSharedServices {
101
102
  readonly distributedRuntime: RuntimeServices['distributedRuntime'];
102
103
  readonly remoteRunnerRegistry: RuntimeServices['remoteRunnerRegistry'] & RemoteRunnerRegistry;
103
104
  readonly remoteSupervisor: RuntimeServices['remoteSupervisor'] & RemoteSupervisor;
105
+ /** W2.2: the shared live process registry backing the Fleet panel. */
106
+ readonly processRegistry: RuntimeServices['processRegistry'];
107
+ /** Wave-3 (W3.2): the shared runtime event bus — the Fleet panel subscribes to its 'communication' domain for the honest steer-consumed signal. */
108
+ readonly runtimeBus: RuntimeServices['runtimeBus'];
104
109
  };
105
110
  }
106
111
 
@@ -167,6 +172,7 @@ export function createUiRuntimeServices(
167
172
  tokenAuditor: runtimeServices.tokenAuditor,
168
173
  replayEngine: runtimeServices.replayEngine,
169
174
  webhookNotifier: runtimeServices.webhookNotifier,
175
+ focusTracker: runtimeServices.focusTracker,
170
176
  policyRuntimeState: runtimeServices.policyRuntimeState,
171
177
  },
172
178
  planning: {
@@ -183,6 +189,8 @@ export function createUiRuntimeServices(
183
189
  distributedRuntime: runtimeServices.distributedRuntime,
184
190
  remoteRunnerRegistry: runtimeServices.remoteRunnerRegistry,
185
191
  remoteSupervisor: runtimeServices.remoteSupervisor,
192
+ processRegistry: runtimeServices.processRegistry,
193
+ runtimeBus: runtimeServices.runtimeBus,
186
194
  },
187
195
  events: createUiRuntimeEvents(runtimeServices.runtimeBus),
188
196
  readModels: createUiReadModels(runtimeServices, options),
@@ -0,0 +1,195 @@
1
+ // ---------------------------------------------------------------------------
2
+ // workstream-services.ts — Wave 4 (wo703)
3
+ //
4
+ // Constructs the TUI's OrchestrationEngine instance (@pellux/goodvibes-sdk/
5
+ // platform/orchestration, landed on SDK main as wo701/W4.1) and a thin
6
+ // command-facing facade around it. Extracted into its own module rather than
7
+ // built inline in services.ts: services.ts sits at the architecture check's
8
+ // 800-line cap (scripts/check-architecture.ts), so any new service gets its
9
+ // own construction module and a single wiring call there (mirrors
10
+ // createWorkflowServices's one-function-bundle shape).
11
+ //
12
+ // Why a facade, not the bare engine: createOrchestrationEngine() is a pure
13
+ // construction call with no auto-start and NO concept of a not-yet-launched
14
+ // "proposal" a human can review/edit before anything is spent — its only
15
+ // creation entry point, createWorkstream(), immediately materializes a real,
16
+ // ticking-eligible Workstream. The /workstream command module
17
+ // (input/commands/workstream-runtime.ts) needs a create -> propose -> approve
18
+ // -> launch flow (Pillar-3 doctrine: render the plan in the transcript before
19
+ // spending anything, mirroring /plan's approve step). REALITY-WINS DIVERGENCE
20
+ // from the wo703 design brief: the brief recommended an "engine-owned/
21
+ // journal-backed" draft so `/workstream status` could re-render a pending
22
+ // proposal after a restart; the real engine (verified against the linked SDK
23
+ // build) exposes no pre-creation draft concept at all, so WorkstreamDraft
24
+ // below is process-lifetime-only state, owned by this module's facade
25
+ // instance (constructed once, threaded onto CommandContext) — never a
26
+ // module-level ambient global. A draft that existed only in memory is lost on
27
+ // restart, same as an unsent chat draft; that is a real, stated limitation,
28
+ // not a bug.
29
+ // ---------------------------------------------------------------------------
30
+
31
+ import {
32
+ createOrchestrationEngine,
33
+ fromChainSpec,
34
+ type CreateWorkstreamInput,
35
+ type OrchestrationEngine,
36
+ } from '@pellux/goodvibes-sdk/platform/orchestration';
37
+ export type { OrchestrationEngine } from '@pellux/goodvibes-sdk/platform/orchestration';
38
+ import { AdaptivePlanner, type DecompositionGate, type PlannerInputs } from '@pellux/goodvibes-sdk/platform/core';
39
+ import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
40
+ import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
41
+ import type { RuntimeEventBus } from '@/runtime/index.ts';
42
+ import { calcSessionCost, isModelPriced } from '../export/cost-utils.ts';
43
+
44
+ export interface WorkstreamServicesDeps {
45
+ readonly agentManager: Pick<AgentManager, 'spawn' | 'getStatus' | 'cancel' | 'registerCancellationSignal' | 'releaseCancellationSignal'>;
46
+ readonly configManager: Pick<ConfigManager, 'get' | 'getCategory'>;
47
+ readonly adaptivePlanner: AdaptivePlanner;
48
+ readonly runtimeBus: RuntimeEventBus;
49
+ readonly projectRoot: string;
50
+ }
51
+
52
+ /** A not-yet-launched /workstream proposal. See this file's header doc for why it lives here rather than on the engine. */
53
+ export interface WorkstreamDraft {
54
+ readonly id: string;
55
+ task: string;
56
+ spec: CreateWorkstreamInput;
57
+ readonly gate: DecompositionGate;
58
+ approved: boolean;
59
+ readonly createdAt: number;
60
+ }
61
+
62
+ /** `ctx.session.workstreamEngine`'s real shape: the live engine plus the draft-proposal bookkeeping the engine itself has no concept of. */
63
+ export interface WorkstreamCommandService {
64
+ readonly engine: OrchestrationEngine;
65
+ proposeDraft(task: string): WorkstreamDraft;
66
+ getDraft(id: string): WorkstreamDraft | undefined;
67
+ listDrafts(): WorkstreamDraft[];
68
+ /** Re-derive a held draft's spec from a new task string. Clears any prior approval — an edit must be re-approved. */
69
+ editDraft(id: string, task: string): WorkstreamDraft | undefined;
70
+ approveDraft(id: string): WorkstreamDraft | undefined;
71
+ removeDraft(id: string): boolean;
72
+ /** Materialize an approved draft into a real, running Workstream (engine.createWorkstream + start), then drop the draft. Null when the draft is missing or not approved. */
73
+ launchDraft(id: string): { workstreamId: string } | null;
74
+ }
75
+
76
+ export interface WorkstreamServices {
77
+ readonly orchestrationEngine: OrchestrationEngine;
78
+ readonly workstreamCommands: WorkstreamCommandService;
79
+ }
80
+
81
+ /**
82
+ * Placeholder planner inputs until a richer risk/latency signal is wired in.
83
+ * `/workstream create` is inherently a multi-step authoring surface, so
84
+ * isMultiStep is always true; the rest are neutral defaults that let
85
+ * AdaptivePlanner's real scoring run rather than short-circuiting it.
86
+ */
87
+ function buildPlannerInputs(task: string): PlannerInputs {
88
+ return {
89
+ riskScore: 0.3,
90
+ latencyBudgetMs: Number.POSITIVE_INFINITY,
91
+ isMultiStep: true,
92
+ remoteAvailable: false,
93
+ backgroundEligible: false,
94
+ taskDescription: task,
95
+ };
96
+ }
97
+
98
+ function createWorkstreamCommandService(
99
+ engine: OrchestrationEngine,
100
+ adaptivePlanner: AdaptivePlanner,
101
+ configManager: Pick<ConfigManager, 'get' | 'getCategory'>,
102
+ ): WorkstreamCommandService {
103
+ const drafts = new Map<string, WorkstreamDraft>();
104
+
105
+ /**
106
+ * fromChainSpec is the SDK's own bridge from "a task string" to a real,
107
+ * launchable engineer -> review CreateWorkstreamInput — the same two-phase
108
+ * shape WrfcController.createChain would otherwise start (see
109
+ * controller-compat.ts). AdaptivePlanner.proposeWorkstream's own
110
+ * PlanProposal is deliberately NOT used for the rendered shape: it always
111
+ * degrades to a fictional single-phase fallback in this wave (nothing yet
112
+ * supplies it a `raw` LLM decomposition — no planning-agent-spawn pipeline
113
+ * exists in the shipped SDK surface this item compiles against), which
114
+ * would silently disagree with what launchDraft actually creates. Showing
115
+ * the real fromChainSpec shape keeps the proposal and the launch
116
+ * byte-for-byte the same plan. proposeWorkstream is still called (below)
117
+ * for its `gate` — the real strategy/reason-code rationale — which stays
118
+ * meaningful even without a raw decomposition.
119
+ */
120
+ function buildSpec(task: string): CreateWorkstreamInput {
121
+ return fromChainSpec({ id: `item-${crypto.randomUUID().slice(0, 8)}`, task }, configManager);
122
+ }
123
+
124
+ return {
125
+ engine,
126
+ proposeDraft(task: string): WorkstreamDraft {
127
+ const { gate } = adaptivePlanner.proposeWorkstream(buildPlannerInputs(task));
128
+ const draft: WorkstreamDraft = {
129
+ id: `wsd_${crypto.randomUUID().slice(0, 8)}`,
130
+ task,
131
+ spec: buildSpec(task),
132
+ gate,
133
+ approved: false,
134
+ createdAt: Date.now(),
135
+ };
136
+ drafts.set(draft.id, draft);
137
+ return draft;
138
+ },
139
+ getDraft: (id) => drafts.get(id),
140
+ listDrafts: () => Array.from(drafts.values()).sort((a, b) => a.createdAt - b.createdAt),
141
+ editDraft(id, task) {
142
+ const draft = drafts.get(id);
143
+ if (!draft) return undefined;
144
+ draft.task = task;
145
+ draft.spec = buildSpec(task);
146
+ draft.approved = false;
147
+ return draft;
148
+ },
149
+ approveDraft(id) {
150
+ const draft = drafts.get(id);
151
+ if (!draft) return undefined;
152
+ draft.approved = true;
153
+ return draft;
154
+ },
155
+ removeDraft: (id) => drafts.delete(id),
156
+ launchDraft(id) {
157
+ const draft = drafts.get(id);
158
+ if (!draft || !draft.approved) return null;
159
+ const workstream = engine.createWorkstream(draft.spec);
160
+ engine.start(workstream.id);
161
+ drafts.delete(id);
162
+ return { workstreamId: workstream.id };
163
+ },
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Constructs the TUI's OrchestrationEngine instance and its command-facing
169
+ * facade. `persist` and `createWorktree` are left at the engine's own
170
+ * defaults: journal-backed snapshots under .goodvibes/orchestration/ (so
171
+ * resumeAllFromDisk below has something to resume) and a plain
172
+ * AgentWorktree(projectRoot) — the same "shared working directory, no real
173
+ * per-item isolation" behavior WrfcController itself uses today (see
174
+ * phase-runner.ts's own REALITY-WINS divergence doc in the SDK).
175
+ */
176
+ export function createWorkstreamServices(deps: WorkstreamServicesDeps): WorkstreamServices {
177
+ const orchestrationEngine = createOrchestrationEngine({
178
+ agentManager: deps.agentManager,
179
+ configManager: deps.configManager,
180
+ runtimeBus: deps.runtimeBus,
181
+ projectRoot: deps.projectRoot,
182
+ priceUsage: (model, usage) => {
183
+ const modelId = model ?? 'unknown';
184
+ if (!isModelPriced(modelId)) return null;
185
+ return calcSessionCost(usage.inputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens, modelId);
186
+ },
187
+ });
188
+ // Honest resume: a prior process's still-in-flight workstreams pick back up
189
+ // (and reappear in the fleet tree) instead of silently vanishing on
190
+ // restart. Never throws — persistence.ts guards every read/parse and
191
+ // quarantines an unrecognized snapshot rather than propagating.
192
+ orchestrationEngine.resumeAllFromDisk();
193
+ const workstreamCommands = createWorkstreamCommandService(orchestrationEngine, deps.adaptivePlanner, deps.configManager);
194
+ return { orchestrationEngine, workstreamCommands };
195
+ }
@@ -4,9 +4,12 @@ import type { SessionSnapshot } from '@/runtime/index.ts';
4
4
  import type { SystemMessageRouter } from '../core/system-message-router.ts';
5
5
  import type { ConversationMessageSnapshot } from '@pellux/goodvibes-sdk/platform/core';
6
6
  import { replayJournalForSession } from '../core/session-recovery.ts';
7
+ import { applyHunkKey, buildModifiedEditArgs, type HunkSelectionState } from '../permissions/hunk-selection.ts';
7
8
 
8
9
  export type PendingPermissionState = PermissionRequest & {
9
- resolve: (approved: boolean, remember?: boolean) => void;
10
+ resolve: (approved: boolean, remember?: boolean, modifiedArgs?: Record<string, unknown>) => void;
11
+ /** Present only when isHunkSelectable(request) was true when the prompt was opened. */
12
+ hunkState?: HunkSelectionState;
10
13
  };
11
14
 
12
15
  export type BlockingInputHandlerOptions = {
@@ -73,6 +76,24 @@ export function handleBlockingShellInput(
73
76
 
74
77
  if (pendingPermission) {
75
78
  const req = pendingPermission;
79
+
80
+ if (req.hunkState) {
81
+ const { state, commit } = applyHunkKey(req.hunkState, data);
82
+ if (commit === 'apply') {
83
+ req.resolve(true, false, buildModifiedEditArgs(req, state));
84
+ render();
85
+ return { handled: true, pendingPermission: null, recoveryPending };
86
+ }
87
+ if (commit === 'cancel') {
88
+ req.resolve(false, false);
89
+ abortTurn();
90
+ render();
91
+ return { handled: true, pendingPermission: null, recoveryPending };
92
+ }
93
+ render();
94
+ return { handled: true, pendingPermission: { ...req, hunkState: state }, recoveryPending };
95
+ }
96
+
76
97
  const key = data.toLowerCase().trim();
77
98
 
78
99
  if (key === 'y') {