@pellux/goodvibes-tui 1.27.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/CHANGELOG.md +125 -2
  2. package/README.md +7 -9
  3. package/bin/goodvibes +2 -2
  4. package/bin/launcher-support.js +8 -4
  5. package/docs/README.md +11 -2
  6. package/docs/foundation-artifacts/operator-contract.json +6403 -2347
  7. package/package.json +14 -25
  8. package/scripts/postinstall.js +35 -35
  9. package/src/audio/spoken-turn-model-routing.ts +1 -1
  10. package/src/cli/bundle-command.ts +5 -5
  11. package/src/cli/completions/generate.ts +1 -1
  12. package/src/cli/doctor.ts +3 -3
  13. package/src/cli/entrypoint.ts +12 -7
  14. package/src/cli/help.ts +4 -5
  15. package/src/cli/hooks-command.ts +1 -1
  16. package/src/cli/index.ts +1 -4
  17. package/src/cli/launch-auto-update.ts +59 -7
  18. package/src/cli/management-commands.ts +6 -6
  19. package/src/cli/management-utils.ts +5 -5
  20. package/src/cli/management.ts +7 -7
  21. package/src/cli/network-posture.ts +1 -1
  22. package/src/cli/package-verification.ts +7 -6
  23. package/src/cli/plugin-bundles-command.ts +1 -1
  24. package/src/cli/plugin-command.ts +2 -2
  25. package/src/cli/service-command.ts +2 -2
  26. package/src/cli/service-posture.ts +4 -4
  27. package/src/cli/status.ts +9 -8
  28. package/src/cli/surface-command.ts +4 -4
  29. package/src/cli/tui-startup.ts +12 -3
  30. package/src/cli-flags.ts +3 -3
  31. package/src/config/goodvibes-home-audit.ts +0 -2
  32. package/src/config/secret-config.ts +37 -5
  33. package/src/config/tui-extension-settings.ts +1 -1
  34. package/src/core/approval-alert.ts +2 -2
  35. package/src/core/budget-breach-notifier.ts +3 -3
  36. package/src/core/conversation-compaction-render.ts +1 -1
  37. package/src/core/conversation-line-cache.ts +1 -1
  38. package/src/core/conversation-render-context.ts +1 -1
  39. package/src/core/conversation-rendering.ts +2 -2
  40. package/src/core/conversation.ts +10 -10
  41. package/src/core/long-task-notifier.ts +2 -2
  42. package/src/core/memory-diagnostics-gateway.ts +1 -1
  43. package/src/core/scriptable-statusline.ts +1 -1
  44. package/src/core/session-auto-titler.ts +1 -1
  45. package/src/core/session-resume-core.ts +2 -2
  46. package/src/core/stream-event-wiring.ts +24 -44
  47. package/src/core/terminal-notifier.ts +3 -3
  48. package/src/core/turn-cancellation.ts +1 -1
  49. package/src/core/turn-event-wiring.ts +5 -5
  50. package/src/input/command-registry.ts +6 -6
  51. package/src/input/commands/channel-pairing.ts +1 -1
  52. package/src/input/commands/cluster-runtime.ts +1 -1
  53. package/src/input/commands/codebase-runtime.ts +1 -1
  54. package/src/input/commands/devices-runtime.ts +1 -1
  55. package/src/input/commands/hosted-runtime.ts +330 -0
  56. package/src/input/commands/local-setup-review.ts +1 -1
  57. package/src/input/commands/local-setup-transfer.ts +2 -2
  58. package/src/input/commands/local-setup.ts +3 -3
  59. package/src/input/commands/managed-runtime.ts +2 -2
  60. package/src/input/commands/operator-rpc.ts +24 -110
  61. package/src/input/commands/payment-card-intake.ts +1 -1
  62. package/src/input/commands/permissions-provenance.ts +2 -2
  63. package/src/input/commands/plugin-runtime.ts +1 -1
  64. package/src/input/commands/provider.ts +1 -1
  65. package/src/input/commands/relay-runtime.ts +18 -9
  66. package/src/input/commands/rewind-runtime.ts +1 -1
  67. package/src/input/commands/runtime-services.ts +1 -1
  68. package/src/input/commands/services-runtime.ts +1 -1
  69. package/src/input/commands/session-workflow.ts +1 -1
  70. package/src/input/commands/settings-sync-runtime.ts +2 -2
  71. package/src/input/commands/share-runtime.ts +1 -1
  72. package/src/input/commands/tasks-runtime.ts +145 -55
  73. package/src/input/commands/update-runtime.ts +31 -28
  74. package/src/input/commands/work-plan-runtime.ts +2 -2
  75. package/src/input/commands/workstream-attempts.ts +1 -1
  76. package/src/input/commands/workstream-runtime.ts +2 -2
  77. package/src/input/commands.ts +2 -0
  78. package/src/input/feature-unit-layout.ts +1 -1
  79. package/src/input/feed-context-factory.ts +3 -3
  80. package/src/input/handler-content-actions.ts +2 -2
  81. package/src/input/handler-feed-routes.ts +1 -1
  82. package/src/input/handler-feed.ts +3 -3
  83. package/src/input/handler-modal-token-routes.ts +1 -1
  84. package/src/input/handler-onboarding-daemon-adopt.ts +3 -2
  85. package/src/input/handler-onboarding.ts +1 -1
  86. package/src/input/handler-types.ts +2 -2
  87. package/src/input/handler-ui-state.ts +1 -1
  88. package/src/input/handler.ts +4 -4
  89. package/src/input/input-history.ts +1 -1
  90. package/src/input/onboarding/onboarding-feature-units.ts +2 -2
  91. package/src/input/onboarding/onboarding-runtime-status.ts +15 -1
  92. package/src/input/onboarding/onboarding-wizard-apply.ts +17 -8
  93. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +5 -3
  94. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +1 -1
  95. package/src/input/onboarding/onboarding-wizard-types.ts +1 -1
  96. package/src/input/payments-config.ts +6 -6
  97. package/src/input/search.ts +1 -1
  98. package/src/input/session-picker-modal.ts +46 -0
  99. package/src/input/settings-modal-activation.ts +1 -1
  100. package/src/input/settings-modal-behavior.ts +4 -4
  101. package/src/input/settings-modal-commit.ts +11 -0
  102. package/src/input/settings-modal-data.ts +13 -80
  103. package/src/input/settings-modal-mutations.ts +33 -0
  104. package/src/input/settings-modal-secrets.ts +34 -0
  105. package/src/input/settings-modal-subscriptions.ts +1 -1
  106. package/src/input/settings-modal-types.ts +15 -1
  107. package/src/input/settings-modal.ts +28 -3
  108. package/src/input/worktree-setup-config.ts +1 -1
  109. package/src/main.ts +11 -9
  110. package/src/panels/agent-inspector-shared.ts +2 -2
  111. package/src/panels/base-panel.ts +2 -2
  112. package/src/panels/builtin/operations.ts +6 -8
  113. package/src/panels/builtin/session.ts +17 -0
  114. package/src/panels/builtin/shared.ts +5 -5
  115. package/src/panels/builtin-modals.ts +3 -3
  116. package/src/panels/confirm-state.ts +1 -1
  117. package/src/panels/cost-tracker-panel.ts +4 -4
  118. package/src/panels/diff-panel.ts +2 -2
  119. package/src/panels/diff-review-panel.ts +2 -2
  120. package/src/panels/expandable-list-panel.ts +2 -2
  121. package/src/panels/fleet-acts.ts +1 -1
  122. package/src/panels/fleet-observed-render.ts +1 -1
  123. package/src/panels/fleet-panel-format.ts +1 -1
  124. package/src/panels/fleet-panel.ts +1 -1
  125. package/src/panels/fleet-spawn.ts +1 -1
  126. package/src/panels/fleet-steer.ts +1 -1
  127. package/src/panels/fleet-transcript.ts +1 -1
  128. package/src/panels/git-panel.ts +1 -1
  129. package/src/panels/hosted-session-feed.ts +352 -0
  130. package/src/panels/hosted-session-panel.ts +221 -0
  131. package/src/panels/local-auth-panel.ts +3 -3
  132. package/src/panels/modals/devices-modal.ts +1 -1
  133. package/src/panels/modals/local-auth-modal.ts +1 -1
  134. package/src/panels/modals/pairing-modal.ts +1 -1
  135. package/src/panels/modals/services-modal.ts +1 -1
  136. package/src/panels/modals/settings-sync-modal.ts +1 -1
  137. package/src/panels/modals/subscription-modal.ts +1 -1
  138. package/src/panels/modals/work-plan-modal.ts +1 -1
  139. package/src/panels/notifications-panel.ts +1 -1
  140. package/src/panels/panel-confirm-overlay.ts +1 -1
  141. package/src/panels/plugins-panel.ts +2 -2
  142. package/src/panels/polish-core.ts +2 -2
  143. package/src/panels/polish-tables.ts +1 -1
  144. package/src/panels/polish.ts +2 -2
  145. package/src/panels/scrollable-list-panel.ts +3 -3
  146. package/src/panels/skills-panel.ts +3 -3
  147. package/src/panels/token-budget-panel.ts +5 -5
  148. package/src/panels/types.ts +1 -2
  149. package/src/permissions/prompt.ts +1 -1
  150. package/src/renderer/autocomplete-overlay.ts +1 -1
  151. package/src/renderer/block-actions-overlay.ts +1 -1
  152. package/src/renderer/bookmark-modal.ts +1 -1
  153. package/src/renderer/buffer.ts +1 -1
  154. package/src/renderer/code-block.ts +1 -1
  155. package/src/renderer/composer-fragments.ts +1 -1
  156. package/src/renderer/compositor.ts +2 -2
  157. package/src/renderer/config-modal.ts +1 -1
  158. package/src/renderer/context-inspector.ts +1 -1
  159. package/src/renderer/conversation-layout.ts +2 -2
  160. package/src/renderer/conversation-overlays.ts +1 -1
  161. package/src/renderer/conversation-surface.ts +2 -2
  162. package/src/renderer/diff-view.ts +1 -1
  163. package/src/renderer/diff.ts +1 -1
  164. package/src/renderer/file-picker-overlay.ts +1 -1
  165. package/src/renderer/fleet-tab-strip.ts +1 -1
  166. package/src/renderer/fullscreen-primitives.ts +2 -2
  167. package/src/renderer/fullscreen-workspace.ts +1 -1
  168. package/src/renderer/header-line.ts +1 -1
  169. package/src/renderer/help-overlay.ts +1 -1
  170. package/src/renderer/history-search-overlay.ts +2 -2
  171. package/src/renderer/layout.ts +5 -8
  172. package/src/renderer/markdown-inline.ts +1 -1
  173. package/src/renderer/markdown-table.ts +1 -1
  174. package/src/renderer/markdown.ts +1 -1
  175. package/src/renderer/mcp-workspace.ts +1 -1
  176. package/src/renderer/modal-factory.ts +2 -2
  177. package/src/renderer/model-workspace.ts +2 -2
  178. package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
  179. package/src/renderer/overlay-box.ts +1 -1
  180. package/src/renderer/panel-composite.ts +1 -1
  181. package/src/renderer/panel-workspace-bar.ts +1 -1
  182. package/src/renderer/process-indicator.ts +1 -1
  183. package/src/renderer/profile-picker-modal.ts +1 -1
  184. package/src/renderer/search-overlay.ts +2 -2
  185. package/src/renderer/selection-modal-overlay.ts +1 -1
  186. package/src/renderer/session-picker-modal.ts +124 -3
  187. package/src/renderer/settings-modal-helpers.ts +2 -0
  188. package/src/renderer/settings-modal.ts +2 -2
  189. package/src/renderer/shell-surface.ts +2 -2
  190. package/src/renderer/system-message.ts +1 -1
  191. package/src/renderer/tab-strip.ts +1 -1
  192. package/src/renderer/theme-mode-config.ts +1 -1
  193. package/src/renderer/theme.ts +11 -12
  194. package/src/renderer/thinking.ts +1 -1
  195. package/src/renderer/tool-call.ts +2 -2
  196. package/src/renderer/tool-result-expanded-lines.ts +1 -1
  197. package/src/renderer/turn-injection.ts +7 -8
  198. package/src/renderer/ui-factory.ts +3 -3
  199. package/src/runtime/bootstrap-command-context.ts +4 -4
  200. package/src/runtime/bootstrap-command-parts.ts +5 -5
  201. package/src/runtime/bootstrap-core.ts +30 -30
  202. package/src/runtime/bootstrap-shell.ts +4 -4
  203. package/src/runtime/bootstrap.ts +128 -157
  204. package/src/runtime/client/approval-updates.ts +82 -0
  205. package/src/runtime/client/build-floors.ts +167 -0
  206. package/src/runtime/client/daemon-attach-handshake.ts +115 -0
  207. package/src/runtime/client/fleet-union.ts +147 -0
  208. package/src/runtime/client/host-service-status.ts +71 -0
  209. package/src/runtime/client/hosted-exit.ts +86 -0
  210. package/src/runtime/client/hosted-roster.ts +110 -0
  211. package/src/runtime/client/hosted-session-stream.ts +178 -0
  212. package/src/runtime/client/hosted-sessions.ts +187 -0
  213. package/src/runtime/client/operator-endpoint.ts +213 -0
  214. package/src/runtime/client/spine-adoption.ts +99 -0
  215. package/src/runtime/cloudflare-control-plane.ts +1 -1
  216. package/src/runtime/context-accounting-source.ts +1 -1
  217. package/src/runtime/context.ts +2 -2
  218. package/src/runtime/conversation-rewind-port.ts +42 -14
  219. package/src/runtime/daemon-attach-notices.ts +55 -19
  220. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  221. package/src/runtime/disposal-wiring.ts +4 -24
  222. package/src/runtime/index.ts +119 -105
  223. package/src/runtime/install-self-check-startup.ts +2 -2
  224. package/src/runtime/interaction-seams.ts +1 -1
  225. package/src/runtime/knowledge-services.ts +8 -2
  226. package/src/runtime/legacy-daemon-migration.ts +15 -3
  227. package/src/runtime/legacy-daemon-reconcile.ts +3 -2
  228. package/src/runtime/memory-spine-transport.ts +37 -267
  229. package/src/runtime/notification-dispatch.ts +2 -2
  230. package/src/runtime/onboarding/apply.ts +2 -2
  231. package/src/runtime/onboarding/derivation.ts +2 -2
  232. package/src/runtime/onboarding/markers.ts +2 -2
  233. package/src/runtime/onboarding/progress.ts +2 -2
  234. package/src/runtime/onboarding/snapshot.ts +1 -1
  235. package/src/runtime/onboarding/state.ts +2 -2
  236. package/src/runtime/onboarding/types.ts +2 -2
  237. package/src/runtime/orchestrator-core-services.ts +1 -1
  238. package/src/runtime/path-shadow-startup.ts +28 -221
  239. package/src/runtime/power-keepawake-remote.ts +3 -2
  240. package/src/runtime/process-lifecycle.ts +2 -2
  241. package/src/runtime/provider-fallback.ts +10 -66
  242. package/src/runtime/recovery-autosave.ts +1 -1
  243. package/src/runtime/recovery-offer-wiring.ts +39 -23
  244. package/src/runtime/recovery-prompt.ts +31 -17
  245. package/src/runtime/relay-reachability-bridge.ts +53 -42
  246. package/src/runtime/release-artifacts.ts +2 -1
  247. package/src/runtime/runtime-services-types.ts +82 -35
  248. package/src/runtime/services.ts +305 -300
  249. package/src/runtime/session-resume-liveness-confirm.ts +1 -1
  250. package/src/runtime/ui-services.ts +7 -6
  251. package/src/runtime/update-check.ts +23 -43
  252. package/src/runtime/workspace-checkpointing.ts +1 -1
  253. package/src/runtime/wrfc-persistence.ts +2 -2
  254. package/src/shell/ui-openers.ts +30 -7
  255. package/src/utils/clipboard.ts +1 -1
  256. package/src/verification/verification-ledger.ts +10 -8
  257. package/src/version.ts +1 -1
  258. package/bin/goodvibes-daemon +0 -90
  259. package/src/cli/config-overrides.ts +0 -267
  260. package/src/cli/endpoints.ts +0 -109
  261. package/src/cli/parser.ts +0 -395
  262. package/src/cli/redaction.ts +0 -170
  263. package/src/cli/types.ts +0 -84
  264. package/src/cluster/commands.ts +0 -382
  265. package/src/cluster/remote-daemon-target.ts +0 -225
  266. package/src/cluster/render.ts +0 -268
  267. package/src/config/atomic-write.ts +0 -70
  268. package/src/config/credential-availability.ts +0 -122
  269. package/src/config/goodvibes-home.ts +0 -149
  270. package/src/config/index.ts +0 -88
  271. package/src/config/provider-model.ts +0 -23
  272. package/src/config/read-versioned.ts +0 -228
  273. package/src/core/alert-gating.ts +0 -67
  274. package/src/core/consolidation-receipt.ts +0 -41
  275. package/src/core/focus-tracker.ts +0 -41
  276. package/src/core/history.ts +0 -45
  277. package/src/core/memory-status.ts +0 -118
  278. package/src/core/orchestrator.ts +0 -7
  279. package/src/core/pairing-devices.ts +0 -49
  280. package/src/core/pairing-handoff.ts +0 -101
  281. package/src/core/pairing-offers.ts +0 -83
  282. package/src/core/pairing-origin.ts +0 -78
  283. package/src/core/rewind-turn-anchors.ts +0 -311
  284. package/src/core/session-recovery.ts +0 -210
  285. package/src/core/stable-host.ts +0 -171
  286. package/src/core/transcript-journal.ts +0 -503
  287. package/src/daemon/cli.ts +0 -641
  288. package/src/daemon/handlers/context.ts +0 -29
  289. package/src/daemon/handlers/contracts.ts +0 -77
  290. package/src/daemon/handlers/credentials.ts +0 -139
  291. package/src/daemon/handlers/drafts/draft-store.ts +0 -427
  292. package/src/daemon/handlers/drafts/index.ts +0 -17
  293. package/src/daemon/handlers/drafts/register.ts +0 -331
  294. package/src/daemon/handlers/errors.ts +0 -18
  295. package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
  296. package/src/daemon/handlers/inbox/index.ts +0 -284
  297. package/src/daemon/handlers/inbox/mapping.ts +0 -192
  298. package/src/daemon/handlers/inbox/poller.ts +0 -212
  299. package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
  300. package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
  301. package/src/daemon/handlers/inbox/providers/email.ts +0 -152
  302. package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
  303. package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
  304. package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
  305. package/src/daemon/handlers/index.ts +0 -117
  306. package/src/daemon/handlers/register.ts +0 -168
  307. package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
  308. package/src/daemon/handlers/remote/backends/docker.ts +0 -79
  309. package/src/daemon/handlers/remote/backends/index.ts +0 -40
  310. package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
  311. package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
  312. package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
  313. package/src/daemon/handlers/remote/backends/types.ts +0 -97
  314. package/src/daemon/handlers/remote/dispatcher.ts +0 -181
  315. package/src/daemon/handlers/remote/index.ts +0 -119
  316. package/src/daemon/handlers/remote/peer-registry.ts +0 -357
  317. package/src/daemon/handlers/remote/service.ts +0 -191
  318. package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
  319. package/src/daemon/handlers/routing/index.ts +0 -261
  320. package/src/daemon/handlers/routing/route-store.ts +0 -319
  321. package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
  322. package/src/daemon/handlers/sqlite-store.ts +0 -278
  323. package/src/daemon/handlers/triage/index.ts +0 -57
  324. package/src/daemon/handlers/triage/integration.ts +0 -213
  325. package/src/daemon/handlers/triage/pipeline.ts +0 -274
  326. package/src/daemon/handlers/triage/scorer.ts +0 -287
  327. package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
  328. package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
  329. package/src/daemon/handlers/triage/tagger/index.ts +0 -184
  330. package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
  331. package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
  332. package/src/daemon/handlers/triage/types.ts +0 -50
  333. package/src/daemon/lifecycle.ts +0 -41
  334. package/src/daemon/provision-wake-model.ts +0 -81
  335. package/src/daemon/safe-serve.ts +0 -61
  336. package/src/daemon/send/channels.ts +0 -200
  337. package/src/daemon/send/command.ts +0 -332
  338. package/src/daemon/send/composition.ts +0 -99
  339. package/src/daemon/send/failure-text.ts +0 -93
  340. package/src/daemon/send/inert-text.ts +0 -225
  341. package/src/daemon/send/stdin.ts +0 -24
  342. package/src/daemon/service-commands.ts +0 -329
  343. package/src/export/cost-utils.ts +0 -319
  344. package/src/input/selection.ts +0 -135
  345. package/src/plugins/loader.ts +0 -15
  346. package/src/renderer/bottom-bar.ts +0 -58
  347. package/src/renderer/conversation-tree.ts +0 -228
  348. package/src/runtime/agent-graph-composition.ts +0 -78
  349. package/src/runtime/channel-composition.ts +0 -46
  350. package/src/runtime/cluster-composition.ts +0 -124
  351. package/src/runtime/cluster-group-composition.ts +0 -284
  352. package/src/runtime/code-index-services.ts +0 -167
  353. package/src/runtime/daemon-handler-composition.ts +0 -76
  354. package/src/runtime/device-posture-composition.ts +0 -110
  355. package/src/runtime/durability-housekeeping.ts +0 -183
  356. package/src/runtime/durability-services.ts +0 -155
  357. package/src/runtime/embedded-service-factories.ts +0 -58
  358. package/src/runtime/feature-settings.ts +0 -154
  359. package/src/runtime/fleet-needs-input-push.ts +0 -70
  360. package/src/runtime/fleet-services.ts +0 -41
  361. package/src/runtime/idle-power-services.ts +0 -85
  362. package/src/runtime/mail-composition.ts +0 -65
  363. package/src/runtime/memory-fold.ts +0 -55
  364. package/src/runtime/operator-token-cleanup.ts +0 -109
  365. package/src/runtime/path-shadow.ts +0 -418
  366. package/src/runtime/perf/panel-health-monitor.ts +0 -18
  367. package/src/runtime/provider-optimizer-wiring.ts +0 -55
  368. package/src/runtime/reachability-notice.ts +0 -100
  369. package/src/runtime/remote-execution-composition.ts +0 -62
  370. package/src/runtime/session-liveness-marker.ts +0 -257
  371. package/src/runtime/session-pointer-surface.ts +0 -22
  372. package/src/runtime/session-storage-services.ts +0 -41
  373. package/src/runtime/surface-feature-flags.ts +0 -96
  374. package/src/runtime/terminal-output-guard.ts +0 -235
  375. package/src/runtime/trust/workspace-registration.ts +0 -192
  376. package/src/runtime/trust/workspace-trust.ts +0 -229
  377. package/src/runtime/ui/index.ts +0 -39
  378. package/src/runtime/ui/model-picker/data-provider.ts +0 -182
  379. package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
  380. package/src/runtime/ui/model-picker/index.ts +0 -59
  381. package/src/runtime/ui/model-picker/types.ts +0 -153
  382. package/src/runtime/ui/provider-health/data-provider.ts +0 -244
  383. package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
  384. package/src/runtime/ui/provider-health/index.ts +0 -46
  385. package/src/runtime/ui/provider-health/types.ts +0 -146
  386. package/src/runtime/ui-events.ts +0 -1
  387. package/src/runtime/ui-read-model-helpers.ts +0 -1
  388. package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
  389. package/src/runtime/ui-read-models-observability-options.ts +0 -1
  390. package/src/runtime/ui-read-models-observability-remote.ts +0 -1
  391. package/src/runtime/ui-read-models-observability-security.ts +0 -1
  392. package/src/runtime/ui-read-models-observability-system.ts +0 -1
  393. package/src/runtime/ui-read-models-observability.ts +0 -1
  394. package/src/runtime/ui-service-queries.ts +0 -1
  395. package/src/runtime/voice-setup-services.ts +0 -98
  396. package/src/runtime/workstream-attempts-validation.ts +0 -77
  397. package/src/runtime/workstream-draft-edits.ts +0 -95
  398. package/src/runtime/workstream-draft-store.ts +0 -274
  399. package/src/runtime/workstream-draft-types.ts +0 -42
  400. package/src/runtime/workstream-services.ts +0 -373
  401. package/src/tools/index.ts +0 -1
  402. package/src/types/grid.ts +0 -48
  403. package/src/types/sql-js.d.ts +0 -15
  404. package/src/work-plans/work-plan-store.ts +0 -702
@@ -1,80 +1,117 @@
1
- import { join } from 'node:path';
2
- import { FocusTracker } from '../core/focus-tracker.ts';
3
- import { ServiceRegistry, SubscriptionManager, ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
1
+ /**
2
+ * services.ts — the terminal app's composition root, as a CLIENT.
3
+ *
4
+ * Every gateway-serving piece — the `GatewayMethodCatalog`, the
5
+ * inbox/triage/drafts/routing handlers, the cluster group and its election,
6
+ * the device-posture runtime and its housekeeping, the mail service deps —
7
+ * lives in the daemon product. This composition serves no verbs, elects
8
+ * nothing, polls no mailbox, and supervises no remote runner. It builds what
9
+ * a TURN needs in this process and reaches the daemon for the rest.
10
+ *
11
+ * ── The floor comes from the SDK ───────────────────────────────────────────
12
+ *
13
+ * The loop essentials — the agent graph, the model stack, config/secrets/
14
+ * services, hooks, plugins, MCP, the file-tool caches, permissions as a client,
15
+ * the spine clients — are composed by `createClientRuntimeServices`, the SDK's
16
+ * one implementation of that shape. Not a fork of it and not a copy of it: the
17
+ * agent product composes the same function, so a wiring step added there
18
+ * cannot silently miss this product.
19
+ *
20
+ * The SDK's own note on that shape applies here literally: it is a FLOOR, not a
21
+ * ceiling. Everything below the `createClientRuntimeServices` call is what THIS
22
+ * surface adds on top — panels, keybindings, the WRFC controller wired over the
23
+ * client's own `agentManager`, the workstream engine, the fleet read model, the
24
+ * voice stack with its local playback sink, the knowledge stack the recall
25
+ * surfaces read. None of those need daemon furniture; they are simply not
26
+ * required for a turn to run, which is why they are here and not in the SDK's
27
+ * client floor.
28
+ *
29
+ * ── The two things that look like daemon furniture and are not ─────────────
30
+ *
31
+ * `sessionBroker` and `approvalBroker` are still constructed. They are this
32
+ * surface's own record of the sessions it is running and the asks it raised —
33
+ * what the transcript, the session panel and the approval card read. They are
34
+ * NOT authoritative: session identity is mirrored to the daemon's spine
35
+ * (register/heartbeat/inputs) and an ask is raised on the daemon
36
+ * (`approvals.raise`) so every other surface can see and answer it. Where the
37
+ * two disagree the daemon's record is the truth, and the client seams in
38
+ * runtime/client/ are what keep them in step.
39
+ */
40
+ import { FocusTracker } from '@pellux/goodvibes-sdk/platform/runtime/operations';
4
41
  import { AutomationDeliveryManager, AutomationManager } from '@pellux/goodvibes-sdk/platform/automation';
5
- import { ChannelDeliveryRouter, ChannelPolicyManager } from '@pellux/goodvibes-sdk/platform/channels';
42
+ import { ChannelPolicyManager } from '@pellux/goodvibes-sdk/platform/channels';
6
43
  import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
7
- import { wireIdlePowerAndLiveTurn } from './idle-power-services.ts';
8
- import { resolvePairingWebOrigin } from '../core/pairing-origin.ts';
9
- import { attachWsOnlyGatewayVerbHandlers } from '@pellux/goodvibes-terminal-shell';
10
- import { composeMailDeps } from './mail-composition.ts';
11
- import { composeCredentialServices } from './credential-composition.ts';
44
+ import { createClientRuntimeServices } from '@pellux/goodvibes-sdk/platform/runtime/client-services';
45
+ import { wireIdlePowerAndLiveTurn } from '@pellux/goodvibes-sdk/platform/runtime/operations';
12
46
  import { createDisposalScope, registerSurfaceRuntimePollers } from './disposal-wiring.ts';
47
+ import { composeCredentialServices } from './credential-composition.ts';
13
48
  import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
14
- import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
15
49
  import { createWebKnowledgeGapRepairer } from '@pellux/goodvibes-sdk/platform/knowledge';
16
50
  import { createKnowledgeServices } from './knowledge-services.ts';
51
+ import { cancelAllAgentRuns } from '@pellux/goodvibes-sdk/platform/tools';
17
52
  import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
18
53
  import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
19
- import { OverflowHandler, ProcessManager, cancelAllAgentRuns, createWorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
20
- import { FileStateCache, FileUndoManager, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath } from '@pellux/goodvibes-sdk/platform/state';
54
+ import { MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, resolveCanonicalMemoryDbPath } from '@pellux/goodvibes-sdk/platform/state';
21
55
  import { buildExecPromptAnswerHandler } from '@pellux/goodvibes-sdk/platform/runtime/permissions/exec-prompt-wiring';
22
56
  import { buildLocalhostFetchApproval } from '@pellux/goodvibes-sdk/platform/runtime/permissions/localhost-fetch-approval';
23
57
  import { createNotificationDispatcher, wireRuntimeNotificationBridge, wireMemoryPressureNotice } from './notification-dispatch.ts';
24
- import { createDurabilityServices } from './durability-services.ts';
58
+ import { createDurabilityServices } from '@pellux/goodvibes-sdk/platform/runtime/operations';
25
59
  import { MemorySpineClient, createLocalMemoryAccess } from '@pellux/goodvibes-sdk/platform/runtime/memory-spine';
26
60
  import { createWorkspaceCheckpointing } from './workspace-checkpointing.ts';
27
- import { createSessionConversationRewindPort } from './conversation-rewind-port.ts';
28
61
  import { createDomainDispatch } from './store/index.ts';
29
- import { DistributedRuntimeManager, IntegrationHelperService, IdempotencyStore, ComponentHealthMonitor, WorktreeRegistry, createShellPathService, createFeatureFlagManager, PolicyRuntimeState } from '@/runtime/index.ts';
30
- import { createSessionStorageServices } from './session-storage-services.ts';
62
+ import { DistributedRuntimeManager, IntegrationHelperService, IdempotencyStore, ComponentHealthMonitor, WorktreeRegistry, createFeatureFlagManager, createShellPathService } from '@/runtime/index.ts';
63
+ import { createSessionStorageServices } from '@pellux/goodvibes-sdk/platform/runtime/operations';
31
64
  import { VoiceProviderRegistry, VoiceService, ensureBuiltinVoiceProviders } from '@pellux/goodvibes-sdk/platform/voice';
32
65
  import { CacheRegistry, PauseController } from '@pellux/goodvibes-sdk/platform/runtime/memory';
33
66
  import { wireMemoryGovernance } from './memory-governance-services.ts';
34
- import { wireVoiceSetup } from './voice-setup-services.ts';
35
- import { WebSearchProviderRegistry, WebSearchService } from '@pellux/goodvibes-sdk/platform/web-search';
67
+ import { wireVoiceSetup } from '@pellux/goodvibes-sdk/platform/runtime/operations';
36
68
  import { PanelManager } from '../panels/panel-manager.ts';
37
- import { HookActivityTracker } from '@pellux/goodvibes-sdk/platform/hooks';
38
- import { HookDispatcher, createHookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks';
39
- import { PluginManager } from '@pellux/goodvibes-sdk/platform/plugins';
40
69
  import { BookmarkManager } from '@pellux/goodvibes-sdk/platform/bookmarks';
41
70
  import { ProfileManager } from '@pellux/goodvibes-sdk/platform/profiles';
42
- import { CrossSessionTaskRegistry, SessionChangeTracker } from '@pellux/goodvibes-sdk/platform/sessions';
71
+ import { SessionChangeTracker } from '@pellux/goodvibes-sdk/platform/sessions';
43
72
  import { ApiTokenAuditor, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
44
73
  import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
45
- import { createRemoteExecutionServices } from './remote-execution-composition.ts';
46
- import { createAgentGraph } from './agent-graph-composition.ts';
47
- import { BenchmarkStore, CacheHitTracker, FavoritesStore, ModelLimitsService, ProviderCapabilityRegistry, ProviderOptimizer, ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
74
+ import { createRemoteExecutionServices } from '@pellux/goodvibes-sdk/platform/runtime/operations';
75
+ import { WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
48
76
  import { KeybindingsManager } from '../input/keybindings.ts';
49
77
  import { AdaptivePlanner, DeterministicReplayEngine, ExecutionPlanManager, SessionLineageTracker, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
50
78
  import { deriveFeatureStates, bindFeatureSettingsBridge } from '@pellux/goodvibes-sdk/platform/runtime/state';
51
- import { createChannelComposition } from './channel-composition.ts';
52
- import { applyProviderOptimizerConfigMode, bindProviderOptimizerFeatureFlag } from './provider-optimizer-wiring.ts';
53
- import { createFleetServices } from './fleet-services.ts';
54
- import { createWorkstreamServices } from './workstream-services.ts';
55
- import { wireFleetNeedsInputPush } from './fleet-needs-input-push.ts';
56
- import { codeIndexDbPath, createCodeIndexServices, createStoreRerooter, isCodeInjectionSettingEnabled } from './code-index-services.ts';
57
- import { createDaemonHandlerComposition } from './daemon-handler-composition.ts';
58
- import { createDevicePostureServices } from './device-posture-composition.ts';
59
- // Re-exported so the shell's bootstrap reaches the install through the same
60
- // module it already imports the runtime graph from.
61
- export { installDevicePosture } from './device-posture-composition.ts';
62
- import { createClusterServices, startClusterServices } from './cluster-group-composition.ts';
63
- import { WorkspaceTrustManager } from './trust/workspace-trust.ts';
64
- import { ensureConfiguredModelIsRoutable } from './provider-fallback.ts';
79
+ import { createChannelComposition } from '@pellux/goodvibes-sdk/platform/runtime/operations';
80
+ import { applyProviderOptimizerConfigMode, bindProviderOptimizerFeatureFlag } from '@pellux/goodvibes-sdk/platform/runtime/operations';
81
+ import { createFleetServices } from '@pellux/goodvibes-terminal-shell';
82
+ import { createWorkstreamServices } from '@pellux/goodvibes-sdk/platform/orchestration';
83
+ import { codeIndexDbPath, createCodeIndexServices, createStoreRerooter, isCodeInjectionSettingEnabled } from '@pellux/goodvibes-sdk/platform/runtime/operations';
84
+ import { WorkspaceTrustManager } from '@pellux/goodvibes-sdk/platform/runtime/operations';
85
+ import { ensureConfiguredModelIsRoutable } from '@pellux/goodvibes-sdk/platform/providers';
86
+ import { GOODVIBES_TUI_SURFACE_ROOT } from '../config/surface.ts';
87
+ import { createDaemonVerbCaller } from './client/operator-endpoint.ts';
88
+ import { createTerminalApprovalUpdateSubscriber } from './client/approval-updates.ts';
89
+ import { createHostedSessionsClient } from './client/hosted-sessions.ts';
90
+ import { getSharedHostedSessionRoster } from './client/hosted-roster.ts';
91
+ import {
92
+ createClientApprovalRaiser,
93
+ createConversationRewindHost,
94
+ createDaemonConfigClient,
95
+ createDaemonCredentialsClient,
96
+ createDevicesClient,
97
+ createWireSessionDispatch,
98
+ readSurfaceAgentOutcome,
99
+ } from '@pellux/goodvibes-sdk/platform/runtime/client';
100
+ import { ClientBuildGuard } from './client/build-floors.ts';
101
+ import { createFleetUnionReadModel } from './client/fleet-union.ts';
102
+ import { logger } from '@pellux/goodvibes-sdk/platform/utils';
103
+ import { VERSION } from '../version.ts';
104
+ import { createSessionConversationRewindPort, hasSessionConversation } from './conversation-rewind-port.ts';
105
+ import { createFleetReadModel } from '../panels/fleet-read-model.ts';
106
+ import type { PermissionPromptDecision, PermissionPromptRequest } from '@pellux/goodvibes-sdk/platform/permissions';
65
107
  import type { RuntimeServicesOptions, RuntimeServices } from './runtime-services-types.ts';
66
108
  export type { RuntimeServicesOptions, RuntimeServices } from './runtime-services-types.ts';
67
109
 
68
110
  export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeServices {
69
111
  const disposalScope = createDisposalScope('RuntimeServices'); const workingDirectory = options.workingDir; // disposal seam: see ./disposal-wiring.ts
70
112
  const homeDirectory = options.homeDirectory;
71
- const shellPaths = createShellPathService({
72
- workingDirectory,
73
- homeDirectory,
74
- });
75
113
  // Built before anything that touches session state — see session-storage-services.ts.
76
- const { surface, sessionManager } = createSessionStorageServices({ workingDirectory, homeDirectory });
77
- const workspaceTrustManager = new WorkspaceTrustManager({ shellPaths });
114
+ const { surface, sessionManager } = createSessionStorageServices({ workingDirectory, homeDirectory, surfaceRoot: GOODVIBES_TUI_SURFACE_ROOT });
78
115
  const configManager = options.configManager;
79
116
  const featureFlags = options.featureFlags ?? createFeatureFlagManager();
80
117
  if (options.featureFlags === undefined) {
@@ -83,13 +120,97 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
83
120
  featureFlags.loadFromConfig({ flags: deriveFeatureStates(configManager) });
84
121
  bindFeatureSettingsBridge(configManager, featureFlags);
85
122
  }
123
+
124
+ // ── The client seams: one resolution of "which daemon", shared by all of them.
125
+ const verbs = createDaemonVerbCaller({ configManager, homeDirectory });
126
+ const daemonConfig = createDaemonConfigClient(verbs);
127
+ const devices = createDevicesClient(verbs);
128
+ // Daemon-hosted sessions: the session picker (built in the input layer, which
129
+ // has no config manager to resolve a daemon from) reads the roster; this is
130
+ // the one place that can give it a client. See client/hosted-roster.ts.
131
+ getSharedHostedSessionRoster().bindClient(createHostedSessionsClient(verbs));
132
+
133
+ // Built here rather than read off the client composition below because the
134
+ // approval seam it feeds is an INPUT to that composition: the path service is
135
+ // pure (it derives paths, it opens nothing), so building it twice costs
136
+ // nothing and keeps the ordering honest.
137
+ const shellPaths = createShellPathService({ workingDirectory, homeDirectory });
138
+ // The surface's own record of the asks it raised — what the approval card and
139
+ // the panel read. The AUTHORITATIVE record is the daemon's; the raiser below
140
+ // keeps the two in step (see the SDK's client/approval-raiser.ts).
141
+ const approvalBroker = new ApprovalBroker({
142
+ storePath: shellPaths.resolveProjectPath('tui', 'control-plane', 'approvals.json'),
143
+ });
144
+ // The late-bound terminal prompt: the UI layer patches the real implementation
145
+ // in after boot, exactly as it always did.
146
+ const localPromptRef: { requestPermission: (request: PermissionPromptRequest) => Promise<PermissionPromptDecision> } = {
147
+ requestPermission: async () => ({ approved: false, remember: false }),
148
+ };
149
+ const liveSessionIdRef: { value: string | null } = { value: null };
150
+ const requestApproval = createClientApprovalRaiser({
151
+ verbs,
152
+ // The SDK's raiser cannot honestly default this: it names how THIS surface
153
+ // reports its own decision back to the daemon (`actorSurface`), so every
154
+ // other surface can see where the answer came from. Reproduces the
155
+ // previous hard-coded `actor: 'tui', actorSurface: 'tui'` write-back exactly.
156
+ actor: 'tui',
157
+ sessionId: () => liveSessionIdRef.value,
158
+ // The "local prompt" is this surface's own broker plus the terminal ask:
159
+ // that is what puts the ask on the approval card and in the panel while the
160
+ // daemon holds the record every other surface reads.
161
+ localPrompt: () => (request) => approvalBroker.requestApproval({
162
+ request,
163
+ ...(liveSessionIdRef.value ? { sessionId: liveSessionIdRef.value } : {}),
164
+ localPrompt: (prompt) => localPromptRef.requestPermission(prompt),
165
+ }),
166
+ // The push channel for a decision made on another surface. Without it the
167
+ // raiser learns by re-reading the record on an interval; with it a phone's
168
+ // answer reaches this terminal in the time one SSE frame takes. The interval
169
+ // stays as the fallback — see client/approval-updates.ts.
170
+ subscribeApprovalUpdates: createTerminalApprovalUpdateSubscriber({ configManager, homeDirectory }),
171
+ });
172
+
173
+ // ── The SDK's client floor: everything a turn needs in this process.
174
+ const client = createClientRuntimeServices({
175
+ runtimeBus: options.runtimeBus,
176
+ runtimeStore: options.runtimeStore,
177
+ configManager,
178
+ surfaceRoot: GOODVIBES_TUI_SURFACE_ROOT,
179
+ workingDir: workingDirectory,
180
+ homeDirectory,
181
+ featureFlags,
182
+ requestApproval,
183
+ ...(options.daemonHomeDirectory === undefined ? {} : { daemonHome: options.daemonHomeDirectory }),
184
+ });
86
185
  const runtimeDispatch = createDomainDispatch(options.runtimeStore);
87
- // Memory governance seams built EARLY (mirrors the SDK's own createRuntimeServices)
88
- // so the scheduler gates and the knowledge background jobs can consult the pause
89
- // controller before the MemoryGovernor (constructed at the composition tail)
90
- // drives it. The admission gate is late-bound: expensive entry points capture
91
- // this closure now and the governor binds into it at the tail — until then
92
- // everything is admitted (the daemon is still booting).
186
+ const workspaceTrustManager = new WorkspaceTrustManager({ shellPaths, surfaceRoot: GOODVIBES_TUI_SURFACE_ROOT });
187
+ const {
188
+ agentManager, agentMessageBus, agentOrchestrator, archetypeLoader,
189
+ contextAccountingHolder, providerRegistry, providerCapabilityRegistry, cacheHitTracker,
190
+ favoritesStore, benchmarkStore, modelLimitsService, toolLLM,
191
+ secretsManager, serviceRegistry, subscriptionManager, hookDispatcher, hookActivityTracker,
192
+ hookWorkbench, pluginManager, workflow, artifactStore, webSearchProviders, webSearchService,
193
+ mcpRegistry: clientMcpRegistry, sandboxSessionRegistry: clientSandboxRegistry,
194
+ processManager, modeManager, fileUndoManager, overflowHandler, policyRuntimeState,
195
+ fileCache, projectIndex, sessionOrchestration,
196
+ } = client;
197
+ void clientMcpRegistry; void clientSandboxRegistry;
198
+ disposalScope.registry.add('client runtime services', () => client.dispose());
199
+
200
+ ensureConfiguredModelIsRoutable(providerRegistry, configManager);
201
+ providerRegistry.initCustomProviders();
202
+ // Background, TTL-respecting live model discovery so provider model lists
203
+ // refresh from their own listing APIs.
204
+ providerRegistry.initProviderModelDiscovery();
205
+
206
+ // A daemon-scoped credential goes to the daemon over `credentials.set`, which
207
+ // writes the value AND points the config key at it in one verified sequence.
208
+ // Everything else stays in this surface's own store.
209
+ const daemonCredentials = createDaemonCredentialsClient(verbs);
210
+
211
+ // Memory governance seams built EARLY so the scheduler gates and the knowledge
212
+ // background jobs can consult the pause controller before the MemoryGovernor
213
+ // (constructed at the composition tail) drives it.
93
214
  const cacheRegistry = new CacheRegistry();
94
215
  const pauseController = new PauseController();
95
216
  const MEMORY_BACKGROUND_JOB_IDS = ['knowledge-self-improvement', 'memory-consolidation', 'code-index-reindex'];
@@ -97,11 +218,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
97
218
  const admitExpensiveWork = (label: string): { allowed: boolean; reason?: string | undefined } =>
98
219
  admitExpensiveWorkRef.current?.(label) ?? { allowed: true };
99
220
  const isKnowledgeBackgroundPaused = (): boolean => pauseController.isPaused('knowledge-self-improvement');
100
- const gatewayMethods = new GatewayMethodCatalog();
101
221
  const panelManager = new PanelManager();
102
- // (the purge): MIGRATE-TO-MODAL surface + redirect registration moved to
103
- // registerBuiltinPanels (builtin-panels.ts), where the panels' resolved deps
104
- // are available for the surfaces to close over.
105
222
  const keybindingsManager = new KeybindingsManager({
106
223
  configPath: shellPaths.resolveUserPath('tui', 'keybindings.json'),
107
224
  });
@@ -112,72 +229,27 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
112
229
  runtimeBus: options.runtimeBus,
113
230
  featureFlags,
114
231
  });
115
- // The credential/identity seam (credential-composition.ts).
116
- const { secretsManager, stepUpService, pairingTokens } = composeCredentialServices({
232
+ // An EMPTY catalog. This product answers no verbs; the field exists only
233
+ // because the SDK's startExternalServices takes a daemon-grade graph even in
234
+ // the adopt-only mode this surface runs in, and because plugin loading is
235
+ // handed one. With adoptOnly no DaemonServer is constructed, so nothing is
236
+ // ever served off it.
237
+ const gatewayMethods = new GatewayMethodCatalog();
238
+ // The credential/identity seam (credential-composition.ts) — this
239
+ // installation's own pairing tokens and step-up service.
240
+ const { stepUpService, pairingTokens } = composeCredentialServices({
117
241
  workingDirectory, homeDirectory, configManager,
118
- daemonHomeDirectory: options.daemonHomeDirectory,
242
+ ...(options.daemonHomeDirectory === undefined ? {} : { daemonHomeDirectory: options.daemonHomeDirectory }),
119
243
  pairingTokenPath: shellPaths.resolveUserPath('control-plane', 'pairing-tokens.json'),
120
244
  });
121
- const subscriptionManager = new SubscriptionManager(shellPaths.resolveUserPath('tui', 'subscriptions.json'));
122
- const serviceRegistry = new ServiceRegistry(shellPaths.resolveProjectPath('tui', 'services.json'), {
123
- secretsManager,
124
- subscriptionManager,
125
- });
126
- const providerCapabilityRegistry = new ProviderCapabilityRegistry();
127
- const cacheHitTracker = new CacheHitTracker();
128
- const favoritesStore = new FavoritesStore({ dir: shellPaths.resolveUserPath('tui') });
129
- const benchmarkStore = new BenchmarkStore({ dir: shellPaths.resolveUserPath('tui') });
130
- const modelLimitsService = new ModelLimitsService({
131
- cachePath: shellPaths.resolveUserPath('tui', 'model-limits.json'),
132
- });
133
- const providerRegistry = new ProviderRegistry({
134
- configManager,
135
- subscriptionManager,
136
- secretsManager,
137
- serviceRegistry,
138
- capabilityRegistry: providerCapabilityRegistry,
139
- cacheHitTracker,
140
- favoritesStore,
141
- benchmarkStore,
142
- modelLimitsService,
143
- featureFlags,
144
- runtimeBus: options.runtimeBus,
145
- });
146
- ensureConfiguredModelIsRoutable(providerRegistry, configManager);
147
- providerRegistry.initCustomProviders();
148
- // Kick off the background, TTL-respecting live model discovery sweep so
149
- // provider model lists refresh from their own listing APIs — matching the
150
- // SDK and agent compositions (this call was the one omitted here).
151
- providerRegistry.initProviderModelDiscovery();
152
- const toolLLM = new ToolLLM({
153
- configManager,
154
- providerRegistry,
155
- });
156
245
  const localUserAuthManager = options.localUserAuthManager ?? new UserAuthManager({
157
246
  bootstrapFilePath: shellPaths.resolveUserPath('tui', 'auth-users.json'),
158
247
  bootstrapCredentialPath: shellPaths.resolveUserPath('tui', 'auth-bootstrap.txt'),
159
248
  });
160
249
  const profileManager = new ProfileManager(shellPaths.resolveUserPath('tui', 'profiles'));
161
250
  const bookmarkManager = new BookmarkManager(shellPaths.resolveUserPath('tui', 'bookmarks'));
162
- const sessionOrchestration = new CrossSessionTaskRegistry(
163
- join(surface.sessionsDir, 'task-graph.json'),
164
- );
165
- const hookActivityTracker = new HookActivityTracker();
166
- // featureFlags is REQUIRED here in practice, even though the SDK types it
167
- // optional. isFeatureGateEnabled(null, ...) is permissive by design — a
168
- // narrow embed with no manager wired gets the capability rather than a
169
- // silent off — so omitting it did not disable the watcher framework when
170
- // watchers.enabled is turned off; it made the setting configure nothing.
171
- // Threading it preserves current effective behaviour rather than changing
172
- // it: watchers.enabled defaults true, the watcher-framework flag's own
173
- // defaultState is 'enabled', and the flag declares no notOperable record —
174
- // so with nothing configured the gate reads exactly as before, and the
175
- // difference is only that turning it OFF now turns it off. This composes
176
- // with bootstrap-core.ts's own `if (configManager.get('watchers.enabled'))`
177
- // check around the built-in polling watcher registration: that check reads
178
- // the same key, so the two never disagree, and this fix only reaches the
179
- // watcher registry's OTHER entry points (registerWatcher/startWatcher/etc.)
180
- // that bootstrap-core.ts's narrower check does not cover.
251
+ // The watcher framework is the daemon's to RUN; this registry is the surface's
252
+ // read/edit handle on the same store, so `/watch` still lists and edits.
181
253
  const watcherRegistry = new WatcherRegistry({
182
254
  storePath: shellPaths.resolveProjectPath('tui', 'watchers.json'),
183
255
  featureFlags,
@@ -186,31 +258,60 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
186
258
  runtimeStore: options.runtimeStore,
187
259
  runtimeBus: options.runtimeBus,
188
260
  });
189
- // The agent-execution graph, wired in both directions; see
190
- // agent-graph-composition.ts for why the six are built as one.
191
- const {
192
- agentMessageBus, archetypeLoader, agentOrchestrator,
193
- agentManager, contextAccountingHolder, wrfcController,
194
- } = createAgentGraph({
195
- runtimeBus: options.runtimeBus, workingDirectory, configManager, providerRegistry,
196
- });
197
- const hookDispatcher = new HookDispatcher({ agentManager, toolLLM, projectRoot: workingDirectory }, hookActivityTracker);
198
- configManager.attachHookDispatcher(hookDispatcher);
199
- const hookWorkbench = createHookWorkbench({
200
- hookDispatcher,
261
+ // WRFC over the client's own agent graph — the "floor, not ceiling" case,
262
+ // verbatim: the review/fix workstream controller needs the agent manager and
263
+ // the message bus, and nothing daemon-side at all.
264
+ const wrfcController = new WrfcController(options.runtimeBus, agentMessageBus, {
265
+ agentManager,
201
266
  configManager,
267
+ projectRoot: workingDirectory,
202
268
  });
203
- const approvalBroker = new ApprovalBroker({
204
- storePath: shellPaths.resolveProjectPath('tui', 'control-plane', 'approvals.json'),
205
- });
269
+ agentManager.setWrfcController(wrfcController);
206
270
  const sessionBroker = new SharedSessionBroker({
207
271
  storePath: shellPaths.resolveProjectPath('tui', 'control-plane', 'sessions.json'),
208
272
  routeBindings,
209
273
  agentStatusProvider: agentManager,
210
274
  messageSender: agentMessageBus,
211
- conversationGateConfig: configManager, // without this the gate runs on DEFAULTS: an inbound message landing in a live session takes the handover and starts work whatever conversationGate.mode/gatedSurfaces say
212
- });
213
- sessionBroker.setContinuationRunner(async ({ task, input }) => {
275
+ conversationGateConfig: configManager, // without this the gate runs on DEFAULTS
276
+ });
277
+ // Work that arrives for a session THIS surface hosts reaches the loop through
278
+ // the same runner whether it came from the local broker or from the daemon's
279
+ // queue. The wire half is inert until bootstrap.ts adopts a daemon (see
280
+ // the SDK's client/session-dispatch.ts); binding one runner to both is what stops a
281
+ // continuation delivered over the wire from taking a different path — and a
282
+ // different set of routing options — than one raised locally.
283
+ const wireSessionDispatch = createWireSessionDispatch({
284
+ hostedSessionIds: () => (liveSessionIdRef.value ? [liveSessionIdRef.value] : []),
285
+ // The reply half. A continuation dispatched here runs in THIS process, so
286
+ // the daemon's own completion poll can never see it finish; this is how the
287
+ // answer gets reported back, and how a message that arrived over a channel
288
+ // is answered into that channel instead of into nothing.
289
+ readAgentOutcome: (agentId) => readSurfaceAgentOutcome(agentManager.getStatus(agentId)),
290
+ });
291
+ disposalScope.registry.add('wire session dispatch', () => wireSessionDispatch.stop());
292
+ // A daemon update swaps the daemon binary and leaves this terminal running
293
+ // the build it started with. The daemon announces the minimum client build it
294
+ // accepts on the /status read the attach handshake already makes; when this
295
+ // build is below it the guard latches, the owner is told on the same surface
296
+ // daemon notices already render, and the runner below stops taking
297
+ // shared-session work rather than executing it under superseded rules. See
298
+ // client/build-floors.ts; bootstrap.ts feeds the reads and attaches the
299
+ // notice sink.
300
+ const clientBuildGuard = new ClientBuildGuard({ clientVersion: VERSION });
301
+ // The parameter type comes from the broker's own runner rather than being
302
+ // re-declared: a hand-written copy would drift from the routing options the
303
+ // spawn actually forwards, and the drift would be silent.
304
+ type ContinuationRequest = Parameters<NonNullable<Parameters<typeof sessionBroker.setContinuationRunner>[0]>>[0];
305
+ const continuationRunner = async ({ task, input }: ContinuationRequest): Promise<{ agentId: string } | null> => {
306
+ // Too old for the live daemon: refuse the work instead of doing it the old
307
+ // way. The owner has already been told to restart this terminal.
308
+ if (!clientBuildGuard.maySharedSessionWork()) {
309
+ logger.warn('declined a shared-session continuation: this build is below the daemon floor', {
310
+ sessionId: input.sessionId,
311
+ floor: clientBuildGuard.current().floor,
312
+ });
313
+ return null;
314
+ }
214
315
  const record = agentManager.spawn({
215
316
  mode: 'spawn',
216
317
  task,
@@ -230,10 +331,11 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
230
331
  context: `shared-session:${input.sessionId}`,
231
332
  });
232
333
  return { agentId: record.id };
233
- });
234
- const artifactStore = new ArtifactStore({ configManager });
334
+ };
335
+ sessionBroker.setContinuationRunner(continuationRunner);
336
+ wireSessionDispatch.setContinuationRunner(continuationRunner);
235
337
  const memoryEmbeddingRegistry = new MemoryEmbeddingProviderRegistry({ configManager });
236
- // Open the ONE home-scoped canonical store; legacy per-project TUI memory folds in at boot (foldTuiLegacyMemory).
338
+ // Open the ONE home-scoped canonical store; legacy per-project TUI memory folds in at boot (foldLegacyProjectMemory).
237
339
  const memoryDbPath = resolveCanonicalMemoryDbPath(homeDirectory);
238
340
  const memoryStore = new MemoryStore(memoryDbPath, {
239
341
  embeddingRegistry: memoryEmbeddingRegistry,
@@ -243,22 +345,8 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
243
345
  // modal): bootstrap.ts activates the wire transport when a compatible
244
346
  // external daemon is adopted, same signal as the session spine.
245
347
  const memorySpine = new MemorySpineClient({ local: createLocalMemoryAccess(memoryRegistry) });
246
- // featureFlags is REQUIRED here in practice, even though the SDK types it
247
- // optional. isFeatureGateEnabled(null, ...) is permissive by design, so
248
- // omitting it did not disable delivery tracking when
249
- // integrations.deliveryTracking is turned off — it made the setting
250
- // configure nothing: deliverText/deliverJobRun kept running either way.
251
- // Threading it preserves current effective behaviour rather than changing
252
- // it: the config default is true, the delivery-engine flag's own
253
- // defaultState is 'enabled', and the flag declares no notOperable record —
254
- // so with nothing configured the gate reads exactly as before.
255
348
  const deliveryManager = new AutomationDeliveryManager({
256
349
  configManager,
257
- // This manager builds the delivery router the daemon actually replies
258
- // through (bootstrap.ts hands it to the daemon facade). Without the
259
- // secrets manager it cannot resolve a goodvibes://secrets/... credential,
260
- // so Telegram accepted every inbound message and dropped every reply with
261
- // "Missing Telegram bot token" while ntfy — which needs no secret — worked.
262
350
  secretsManager,
263
351
  serviceRegistry,
264
352
  runtimeBus: options.runtimeBus,
@@ -267,18 +355,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
267
355
  artifactStore,
268
356
  featureFlags,
269
357
  });
270
- // Same shape as deliveryManager above: automation.enabled defaults true,
271
- // the automation-domain flag's own defaultState is 'enabled', so threading
272
- // featureFlags here does not change what a default install does — it only
273
- // makes turning automation.enabled off actually turn AutomationManager's own
274
- // create/update/run/list surface off. This composes with bootstrap.ts's own
275
- // `if (configManager.get('automation.enabled'))` gate around scheduling
276
- // automationManager.start(): that check reads the same key, and
277
- // AutomationManager.start() re-checks the same gate internally (it no-ops
278
- // and stops rather than starting when disabled), so the two can never
279
- // disagree — this fix only reaches the manager's OTHER entry points
280
- // (createJob/updateJob/runNow/etc.) that the bootstrap.ts gate does not
281
- // cover, the same way watchers.enabled and the watcher registry above do.
282
358
  const automationManager = new AutomationManager({
283
359
  configManager,
284
360
  defaultSurfaceKind: 'tui',
@@ -287,8 +363,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
287
363
  runtimeStore: options.runtimeStore,
288
364
  runtimeBus: options.runtimeBus,
289
365
  deliveryManager,
290
- // Same live registry: a bare model id on an automation job resolves through
291
- // the shared resolver instead of a format-only rejection.
292
366
  providerRegistry,
293
367
  featureFlags,
294
368
  spawnTask: (input) => {
@@ -315,32 +389,18 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
315
389
  knowledgeService, agentKnowledgeService, homeGraphService,
316
390
  projectPlanningService, projectPlanningProjectId, workPlanStore,
317
391
  } = createKnowledgeServices({ configManager, providerRegistry, artifactStore, memoryRegistry, runtimeBus: options.runtimeBus, workingDirectory, homeDirectory, isBackgroundPaused: isKnowledgeBackgroundPaused, admitExpensiveWork });
392
+ // Voice: the PROVIDERS are local (a spoken turn plays out of this terminal's
393
+ // own speaker) — synthesis reaches `voice.tts.stream` when a daemon serves it
394
+ // and falls back to a local provider otherwise; see audio/spoken-turn-wiring.ts.
318
395
  const voiceProviders = new VoiceProviderRegistry();
319
396
  ensureBuiltinVoiceProviders(voiceProviders, { readConfig: (key) => configManager.get(key as Parameters<typeof configManager.get>[0]) });
320
397
  const voiceService = new VoiceService(voiceProviders);
321
- const webSearchProviders = new WebSearchProviderRegistry({
322
- env: process.env,
323
- serviceRegistry,
324
- });
325
- const webSearchService = new WebSearchService(webSearchProviders, {
326
- serviceRegistry,
327
- featureFlags,
328
- });
329
398
  for (const [semantic, ingest] of [[knowledgeSemanticService, knowledgeService], [agentKnowledgeSemanticService, agentKnowledgeService], [homeGraphSemanticService, homeGraphService]] as const) {
330
399
  semantic.setGapRepairer(createWebKnowledgeGapRepairer({ searchService: webSearchService, ingestService: ingest }));
331
400
  }
332
401
  const mediaProviders = new MediaProviderRegistry();
333
402
  ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
334
403
  const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, knowledgeService);
335
- const pluginManager = new PluginManager({
336
- pathOptions: {
337
- cwd: shellPaths.workingDirectory,
338
- homeDir: shellPaths.homeDirectory,
339
- },
340
- stateFilePath: shellPaths.resolveUserPath('tui', 'plugins.json'),
341
- });
342
- const workflow = createWorkflowServices();
343
- hookDispatcher.setTriggerManager(workflow.triggerManager);
344
404
  const channelPolicy = new ChannelPolicyManager({
345
405
  storePath: shellPaths.resolveProjectPath('tui', 'channels', 'policies.json'),
346
406
  });
@@ -352,34 +412,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
352
412
  approvalBridge: approvalBroker,
353
413
  automationBridge: automationManager,
354
414
  });
355
- // The paired-phone feature for this host, on the SAME runtime phones pair onto
356
- // and the SAME approval broker every other confirmation rides. Every `device.*`
357
- // setting is read live through this; see device-posture-composition.ts.
358
- const { devicePosture } = createDevicePostureServices({
359
- configManager,
360
- distributedRuntime,
361
- approvals: approvalBroker,
362
- stateDirectory: shellPaths.resolveProjectPath('tui', 'devices'),
363
- gatewayMethods,
364
- });
365
-
366
- // Which machines on this network are "us", and which of them reads the
367
- // shared inbox. Both inert until startCluster() — no socket, no key material
368
- // read; see cluster-group-composition.ts for why they are built together.
369
- const { clusterGroup, clusterCoordinator } = createClusterServices({
370
- configManager, shellPaths, secretsManager,
371
- });
372
- // Daemon handler surfaces (see daemon-handler-composition.ts); the inbox
373
- // poller registers itself with the coordinator rather than starting eagerly.
374
- const daemonHandlers = createDaemonHandlerComposition({
375
- gatewayMethods,
376
- secretsManager,
377
- configManager,
378
- workingDirectory,
379
- homeDirectory,
380
- distributedRuntime,
381
- clusterCoordinator,
382
- });
383
415
 
384
416
  // Remote runners and the sandboxes tool calls are confined to; see
385
417
  // remote-execution-composition.ts for why the four are built as one.
@@ -387,24 +419,13 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
387
419
  = createRemoteExecutionServices({
388
420
  agentManager, workingDirectory, hookDispatcher, configManager, runtimeBus: options.runtimeBus,
389
421
  });
390
- // featureFlags is REQUIRED here in practice, even though the SDK types it
391
- // optional. isFeatureGateEnabled(null, ...) is permissive by design, so
392
- // omitting it did not disable managed blocking when
393
- // security.tokenAudit.enabled is turned off. Threading it preserves current
394
- // effective behaviour rather than changing it: managed is hardcoded false
395
- // here (advisory reporting only; excess-scope/overdue tokens are reported,
396
- // never blocked, regardless of this flag — see isBlocked()'s
397
- // `this._config.managed && this._managedBlockingEnabled()` guard), the
398
- // config default for security.tokenAudit.enabled is true, and the
399
- // token-scope-rotation-audit flag's own defaultState is 'enabled' — so with
400
- // nothing configured the gate reads exactly as before either way.
401
422
  const tokenAuditor = new ApiTokenAuditor({ managed: false, featureFlags });
402
423
  const componentHealthMonitor = new ComponentHealthMonitor();
403
424
  const worktreeRegistry = new WorktreeRegistry(workingDirectory);
404
425
  const webhookNotifier = new WebhookNotifier();
405
426
  const focusTracker = new FocusTracker();
406
427
  const replayEngine = new DeterministicReplayEngine(workingDirectory);
407
- const providerOptimizer = new ProviderOptimizer(providerRegistry, providerCapabilityRegistry, false); // dark until its gate flips it (see provider-optimizer-wiring.ts)
428
+ const providerOptimizer = client.providerOptimizer;
408
429
  bindProviderOptimizerFeatureFlag(featureFlags, providerOptimizer);
409
430
  applyProviderOptimizerConfigMode(configManager, providerOptimizer);
410
431
  const sessionMemoryStore = new SessionMemoryStore();
@@ -412,63 +433,60 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
412
433
  const planManager = new ExecutionPlanManager(workingDirectory);
413
434
  const adaptivePlanner = new AdaptivePlanner();
414
435
  const idempotencyStore = new IdempotencyStore();
415
- const overflowHandler = new OverflowHandler({ baseDir: workingDirectory });
416
- const policyRuntimeState = new PolicyRuntimeState();
417
- const fileCache = new FileStateCache();
418
- const projectIndex = new ProjectIndex(workingDirectory);
419
- const channelDeliveryRouter = new ChannelDeliveryRouter({
420
- configManager,
421
- secretsManager,
422
- serviceRegistry,
423
- artifactStore,
424
- });
425
- const processManager = new ProcessManager();
426
- // The phase/work-item orchestration engine, constructed
427
- // before the process registry so its fleet nodes (workstream/phase/
428
- // work-item) can be folded in below via the registry's optional
429
- // orchestrationEngine dep.
436
+ // ONE router, not two. This surface used to build a second ChannelDeliveryRouter
437
+ // from the same four arguments AutomationDeliveryManager builds its own from,
438
+ // and expose that second one — so the router on the service surface and the
439
+ // router replies actually leave through were different objects, and a delivery
440
+ // strategy registered on the exposed one reached nothing. The SDK's
441
+ // RuntimeServices contract requires the field; it now names the real router.
442
+ const channelDeliveryRouter = deliveryManager.getDeliveryRouter();
443
+ // The phase/work-item orchestration engine, constructed before the process
444
+ // registry so its fleet nodes can be folded in below.
430
445
  const { orchestrationEngine, workstreamCommands } = createWorkstreamServices({
431
446
  agentManager, configManager, adaptivePlanner, runtimeBus: options.runtimeBus, projectRoot: workingDirectory,
432
447
  });
433
- // Repo source-tree code index, sharing memoryEmbeddingRegistry
434
- // with MemoryStore above. Auto-build is config-gated (default off) — see
435
- // code-index-services.ts's header doc.
436
- const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry, isReindexPaused: () => pauseController.isPaused('code-index-reindex'), admitExpensiveWork });
437
- // Store snapshots, the periodic append-only sweep, durable remembered-approval rules + the live credential chain — see durability-services.ts.
448
+ // Repo source-tree code index, sharing memoryEmbeddingRegistry with MemoryStore.
449
+ const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, surfaceRoot: GOODVIBES_TUI_SURFACE_ROOT, configManager, memoryEmbeddingRegistry, isReindexPaused: () => pauseController.isPaused('code-index-reindex'), admitExpensiveWork });
450
+ const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler };
451
+ // Store snapshots, the periodic append-only sweep, durable remembered-approval rules + the live credential chain.
438
452
  const { storeSnapshotScheduler, appendOnlyRetentionScheduler, userPermissionRuleStore, stopDurabilityHousekeeping, stopConfigWatch } = createDurabilityServices({
439
- configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory), surface, shellPaths, // + retention-sweep roots & live config watch (mirrors the SDK)
440
- ...(options.currentSessionId ? { currentSessionId: options.currentSessionId } : {}), // exempts the running session from crash-residue reaping
453
+ configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory, GOODVIBES_TUI_SURFACE_ROOT), surface, shellPaths,
454
+ ...(options.currentSessionId ? { currentSessionId: options.currentSessionId } : {}),
441
455
  });
442
- const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler }; // Code-injection seam (agent here; main via orchestrator-core-services.ts)
443
- const { processRegistry } = createFleetServices({ // Shared archive-aware fleet registry (+ daemon observed rows) — see fleet-services.ts
456
+ const { processRegistry } = createFleetServices({ // Shared archive-aware fleet registry — see fleet-services.ts
444
457
  agentManager, wrfcController,
445
- orchestrationEngine, // Folds workstream/phase/work-item nodes into the fleet
446
- codeIndexService: codeIndexStore, // Folds a single 'code-index' node into the fleet
458
+ orchestrationEngine,
459
+ codeIndexService: codeIndexStore,
447
460
  processManager, watcherRegistry, workflow, approvalBroker, sessionBroker,
448
- messageBus: agentMessageBus, // Backs steer()/`steerable` (the Fleet steer composer builds on top)
449
- automationManager, // Folds /schedule AutomationJobs into the fleet as 'schedule' nodes
461
+ messageBus: agentMessageBus,
462
+ automationManager,
450
463
  runtimeBus: options.runtimeBus,
451
- observeExternalAgents: options.observeExternalAgents, providerRegistry, // observeExternalAgents is daemon-side only
464
+ providerRegistry,
452
465
  });
453
- // featureFlags is REQUIRED here in practice, even though the SDK types it
454
- // optional. isFeatureGateEnabled(null, ...) is permissive by design, so
455
- // omitting it did not disable the HITL UX mode system when
456
- // behavior.hitlMode is set to 'off' — setHITLMode/setDomainVerbosity kept
457
- // accepting writes either way. Threading it preserves current effective
458
- // behaviour rather than changing it: behavior.hitlMode defaults to
459
- // 'balanced' (not 'off'), and the hitl-ux-modes flag's own defaultState is
460
- // 'enabled' — so with nothing configured the gate reads exactly as before.
461
- const modeManager = new ModeManager({ featureFlags }); const fileUndoManager = new FileUndoManager();
466
+ // What the Fleet panel reads: this surface's own live registry UNION the
467
+ // adopted daemon's rows. The daemon runs work no registry here knows about
468
+ // (scheduled jobs, channel-driven runs, sessions other surfaces started, the
469
+ // external agents it observes), and a panel showing only half the fleet is
470
+ // worse than one showing none — the half it shows looks complete.
471
+ const fleetReadModel = createFleetUnionReadModel({
472
+ local: createFleetReadModel(processRegistry, options.runtimeBus),
473
+ verbs,
474
+ });
475
+ disposalScope.registry.add('fleet union refresh', () => fleetReadModel.stop());
476
+ // Conversation-scope rewind, from ANY surface. The daemon holds the
477
+ // checkpoint store and answers the files half; the messages live in this
478
+ // process, so this offers them and answers the daemon's questions about them.
479
+ // Started on adoption (bootstrap.ts), released on disposal.
480
+ const conversationRewindHost = createConversationRewindHost({
481
+ verbs,
482
+ port: createSessionConversationRewindPort(),
483
+ hosts: hasSessionConversation,
484
+ label: 'the terminal app',
485
+ });
486
+ disposalScope.registry.add('conversation rewind host', () => { void conversationRewindHost.stop(); });
462
487
  const workspaceCheckpointManager = createWorkspaceCheckpointing({ workspaceRoot: workingDirectory, surface, runtimeBus: options.runtimeBus, configManager });
463
- // memory-consolidation honors governor backpressure: it ticks only when idle
464
- // AND the 'memory-consolidation' job is not paused AND expensive work is
465
- // admitted (mirrors the SDK's own createRuntimeServices idle gate).
466
488
  const { memoryConsolidationScheduler, powerManager, sessionLiveTurnControls } = wireIdlePowerAndLiveTurn({ configManager, memoryRegistry, runtimeBus: options.runtimeBus, isIdle: () => sessionBroker.countBusySessions() === 0 && !pauseController.isPaused('memory-consolidation') && admitExpensiveWork('memory consolidation').allowed, snapshotTick: () => storeSnapshotScheduler.tick(), heartbeat: async () => { await automationManager.triggerHeartbeat({ source: 'wake-catchup' }); }, powerSeam: options.powerSeam });
467
489
 
468
- // Construct + start the MemoryGovernor (default ON — a safety feature) with
469
- // the standard KNOWN cache adapters (knowledge stores + shared session
470
- // broker), then late-bind the admission gate the expensive entry points
471
- // captured earlier. Mirrors the SDK's own createRuntimeServices composition tail.
472
490
  const { memoryGovernor } = wireMemoryGovernance({
473
491
  configManager,
474
492
  runtimeBus: options.runtimeBus,
@@ -478,8 +496,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
478
496
  receiptPath: shellPaths.resolveProjectPath('tui', 'memory', 'tripwire-receipt.json'),
479
497
  knowledgeStores: [knowledgeStore, agentKnowledgeStore, homeGraphKnowledgeStore],
480
498
  sessionBroker,
481
- // Graceful tripwire shutdown flushes in-flight state via ASYNC store
482
- // snapshots so the governor's 10s shutdown ceiling stays enforceable.
483
499
  onTripwireShutdown: async () => { await storeSnapshotScheduler.snapshotAllAsync('tripwire'); },
484
500
  });
485
501
  admitExpensiveWorkRef.current = (label) => memoryGovernor.admitExpensiveWork(label);
@@ -487,17 +503,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
487
503
  // Managed local-voice provisioning (voice.local.status/install) — single-flight
488
504
  // one-act install + no-network status; see voice-setup-services.ts.
489
505
  const { voiceSetup, stopWakeHousekeeping } = wireVoiceSetup({ configManager, shellPaths, voiceProviders, admitExpensiveWork,
490
- // Boot provisioning of the wake-word model + its recovery sweep, opted into
491
- // by the real entrypoints only (same treatment as powerSeam) so a one-shot
492
- // CLI command and a test composing this graph fetch nothing and start no timer.
493
506
  provisionWakeModelsAtBoot: options.provisionWakeModelsAtBoot === true });
507
+ void voiceSetup;
494
508
 
495
- // Terminal-shell wrapper over the SDK registerGatewayVerbGroups (gateway-verbs.ts); checkin.*/fleet-needs-input/pairing.* register only when their deps are present. memoryGovernor lights up ops.memory.get; voiceSetup lights up voice.local.status/install.
496
- // calendar.*/email.* are platform-served; these two let it register (mail-composition.ts).
497
- const { emailServiceDeps, describeEmailConfigProblem } = composeMailDeps({ configManager, secretsManager });
498
- attachWsOnlyGatewayVerbHandlers(gatewayMethods, { homeDirectory, emailServiceDeps, describeEmailConfigProblem, processRegistry, workspaceCheckpointManager, conversationRewindPort: createSessionConversationRewindPort(), sessionBroker, secretsManager, stepUpService, approvalBroker, requestApproval: (input) => approvalBroker.requestApproval(input), watcherRegistry, userPermissionRuleStore, shellPaths, configManager, runtimeStore: options.runtimeStore, channelDeliveryRouter, providerRegistry, automationManager, sessionLister: sessionBroker, sessionIntake: sessionBroker, workingDirectory, memoryRegistry, pairingTokens, sessionLiveTurnControls, powerManager, memoryGovernor, voiceSetup, relayAvailable: () => configManager.get('relay.enabled') === true, pairingWebOrigin: () => resolvePairingWebOrigin(configManager).origin, disposal: disposalScope.registry, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
499
- // surface-scoped: continuity's recovery-file check must read the SAME paths
500
- // the app writes with, not the unscoped legacy pair.
501
509
  const integrationHelpers = new IntegrationHelperService({
502
510
  surface, configManager, automationManager, approvalBroker, sessionBroker, distributedRuntime,
503
511
  remoteRunnerRegistry, remoteSupervisor, panelManager, localUserAuthManager, providerRegistry,
@@ -505,12 +513,13 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
505
513
  runtimeStore: options.runtimeStore, runtimeBus: options.runtimeBus,
506
514
  getConversationTitle: options.getConversationTitle,
507
515
  });
508
- // A loopback fetch that isn't allow-listed asks once through the approval
509
- // broker; "allow for this project" persists and later fetches never ask. Built
510
- // once and shared with the tool registry (bootstrap-core) so both ask alike.
511
- const localhostFetchApproval = buildLocalhostFetchApproval({ requestApproval: (input) => approvalBroker.requestApproval(input), configManager });
512
- // Exec stuck on a terminal prompt rides the approval broker; the typed answer feeds the continuing run. Built once and shared (like localhostFetchApproval) so the tool registry AND every setDependencies site — incl. the post-clobber rewire in bootstrap-core — install the SAME handler; otherwise a wholesale replace drops it and interactive prompts hang.
513
- const execPromptAnswerHandler = buildExecPromptAnswerHandler({ requestApproval: (input) => approvalBroker.requestApproval(input) });
516
+ // A loopback fetch that isn't allow-listed asks once through the CLIENT raiser;
517
+ // "allow for this project" persists and later fetches never ask.
518
+ const localhostFetchApproval = buildLocalhostFetchApproval({ requestApproval: (input) => requestApproval(input), configManager });
519
+ // Exec stuck on a terminal prompt rides the same raiser; the typed answer feeds
520
+ // the continuing run. Built once and shared with every setDependencies site —
521
+ // a wholesale replace that forgets it hangs interactive prompts.
522
+ const execPromptAnswerHandler = buildExecPromptAnswerHandler({ requestApproval: (input) => requestApproval(input) });
514
523
  agentOrchestrator.setDependencies({
515
524
  surfaceRoot: surface.surfaceRoot,
516
525
  execPromptAnswerHandler,
@@ -542,13 +551,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
542
551
  contextAccountingHolder,
543
552
  });
544
553
 
545
- // Give the panel_only notification target a live producer: curated
546
- // runtime-domain events route through the notification router into the shared
547
- // panel feed (panel_only and burst-collapsed decisions land there).
554
+ // Give the panel_only notification target a live producer.
548
555
  const notificationDispatcher = createNotificationDispatcher(configManager);
549
556
  wireRuntimeNotificationBridge(options.runtimeBus, notificationDispatcher);
550
- // OPS_MEMORY_PRESSURE is lifted into the notice feed on its own targeted
551
- // bridge (the high-churn 'ops' domain stays out of the wholesale allowlist).
552
557
  wireMemoryPressureNotice(options.runtimeBus, notificationDispatcher);
553
558
 
554
559
  const services: RuntimeServices = {
@@ -570,6 +575,19 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
570
575
  channelDeliveryRouter,
571
576
  watcherRegistry,
572
577
  approvalBroker,
578
+ requestApproval,
579
+ daemonVerbs: verbs,
580
+ wireSessionDispatch,
581
+ clientBuildGuard,
582
+ conversationRewindHost,
583
+ gatewayMethods,
584
+ stepUpService,
585
+ pairingTokens,
586
+ devices,
587
+ daemonConfig,
588
+ daemonCredentials,
589
+ localPromptRef,
590
+ liveSessionIdRef,
573
591
  localhostFetchApproval,
574
592
  execPromptAnswerHandler,
575
593
  notificationDispatcher,
@@ -577,7 +595,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
577
595
  sessionBroker,
578
596
  deliveryManager,
579
597
  automationManager,
580
- gatewayMethods,
581
598
  artifactStore,
582
599
  knowledgeService,
583
600
  agentKnowledgeService,
@@ -590,8 +607,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
590
607
  memorySpine,
591
608
  serviceRegistry,
592
609
  secretsManager,
593
- stepUpService,
594
- pairingTokens,
595
610
  subscriptionManager,
596
611
  localUserAuthManager,
597
612
  profileManager,
@@ -628,11 +643,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
628
643
  providerRegistry,
629
644
  toolLLM,
630
645
  distributedRuntime,
631
- devicePosture,
632
- daemonHandlers,
633
- clusterCoordinator,
634
- clusterGroup,
635
- startCluster: () => startClusterServices({ clusterGroup, clusterCoordinator }),
636
646
  remoteRunnerRegistry,
637
647
  remoteSupervisor,
638
648
  sessionMemoryStore,
@@ -662,17 +672,12 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
662
672
  pauseController,
663
673
  sessionLiveTurnControls,
664
674
  processRegistry,
675
+ fleetReadModel,
665
676
  modeManager,
666
677
  fileUndoManager,
667
678
  workspaceCheckpointManager,
668
679
  integrationHelpers,
669
- rerootStores: createStoreRerooter({ codeIndexStore, projectIndex }),
670
- // Cancels the agent runs this graph was hosting. By dispose() time the
671
- // fleet registry, orchestration engine, process registry and bus these runs
672
- // report through are already down, so a run still described as "running" is
673
- // orphaned rather than preserved — and this is the only shutdown-reachable
674
- // way to abort its in-flight provider call instead of letting it sleep out
675
- // a retry backoff nobody is waiting on.
680
+ rerootStores: createStoreRerooter({ codeIndexStore, projectIndex, surfaceRoot: GOODVIBES_TUI_SURFACE_ROOT }),
676
681
  cancelHostedAgentRuns: () => cancelAllAgentRuns(agentManager),
677
682
  dispose: (): void => disposalScope.dispose(),
678
683
  };