@pellux/goodvibes-tui 1.27.1 → 2.0.2

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 (405) hide show
  1. package/CHANGELOG.md +127 -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 +3 -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 +9 -122
  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 +21 -33
  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 +4 -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 -693
  288. package/src/daemon/fatal-boot-report.ts +0 -111
  289. package/src/daemon/handlers/context.ts +0 -29
  290. package/src/daemon/handlers/contracts.ts +0 -77
  291. package/src/daemon/handlers/credentials.ts +0 -139
  292. package/src/daemon/handlers/drafts/draft-store.ts +0 -427
  293. package/src/daemon/handlers/drafts/index.ts +0 -17
  294. package/src/daemon/handlers/drafts/register.ts +0 -331
  295. package/src/daemon/handlers/errors.ts +0 -18
  296. package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
  297. package/src/daemon/handlers/inbox/index.ts +0 -284
  298. package/src/daemon/handlers/inbox/mapping.ts +0 -192
  299. package/src/daemon/handlers/inbox/poller.ts +0 -212
  300. package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
  301. package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
  302. package/src/daemon/handlers/inbox/providers/email.ts +0 -152
  303. package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
  304. package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
  305. package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
  306. package/src/daemon/handlers/index.ts +0 -117
  307. package/src/daemon/handlers/register.ts +0 -168
  308. package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
  309. package/src/daemon/handlers/remote/backends/docker.ts +0 -79
  310. package/src/daemon/handlers/remote/backends/index.ts +0 -40
  311. package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
  312. package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
  313. package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
  314. package/src/daemon/handlers/remote/backends/types.ts +0 -97
  315. package/src/daemon/handlers/remote/dispatcher.ts +0 -181
  316. package/src/daemon/handlers/remote/index.ts +0 -119
  317. package/src/daemon/handlers/remote/peer-registry.ts +0 -357
  318. package/src/daemon/handlers/remote/service.ts +0 -191
  319. package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
  320. package/src/daemon/handlers/routing/index.ts +0 -261
  321. package/src/daemon/handlers/routing/route-store.ts +0 -319
  322. package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
  323. package/src/daemon/handlers/sqlite-store.ts +0 -278
  324. package/src/daemon/handlers/triage/index.ts +0 -57
  325. package/src/daemon/handlers/triage/integration.ts +0 -213
  326. package/src/daemon/handlers/triage/pipeline.ts +0 -274
  327. package/src/daemon/handlers/triage/scorer.ts +0 -287
  328. package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
  329. package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
  330. package/src/daemon/handlers/triage/tagger/index.ts +0 -184
  331. package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
  332. package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
  333. package/src/daemon/handlers/triage/types.ts +0 -50
  334. package/src/daemon/lifecycle.ts +0 -41
  335. package/src/daemon/provision-wake-model.ts +0 -81
  336. package/src/daemon/safe-serve.ts +0 -61
  337. package/src/daemon/send/channels.ts +0 -200
  338. package/src/daemon/send/command.ts +0 -332
  339. package/src/daemon/send/composition.ts +0 -99
  340. package/src/daemon/send/failure-text.ts +0 -93
  341. package/src/daemon/send/inert-text.ts +0 -225
  342. package/src/daemon/send/stdin.ts +0 -24
  343. package/src/daemon/service-commands.ts +0 -329
  344. package/src/export/cost-utils.ts +0 -319
  345. package/src/input/selection.ts +0 -135
  346. package/src/plugins/loader.ts +0 -15
  347. package/src/renderer/bottom-bar.ts +0 -58
  348. package/src/renderer/conversation-tree.ts +0 -228
  349. package/src/runtime/agent-graph-composition.ts +0 -78
  350. package/src/runtime/channel-composition.ts +0 -46
  351. package/src/runtime/cluster-composition.ts +0 -124
  352. package/src/runtime/cluster-group-composition.ts +0 -284
  353. package/src/runtime/code-index-services.ts +0 -167
  354. package/src/runtime/daemon-handler-composition.ts +0 -76
  355. package/src/runtime/device-posture-composition.ts +0 -110
  356. package/src/runtime/durability-housekeeping.ts +0 -183
  357. package/src/runtime/durability-services.ts +0 -155
  358. package/src/runtime/embedded-service-factories.ts +0 -74
  359. package/src/runtime/feature-settings.ts +0 -154
  360. package/src/runtime/fleet-needs-input-push.ts +0 -70
  361. package/src/runtime/fleet-services.ts +0 -41
  362. package/src/runtime/idle-power-services.ts +0 -85
  363. package/src/runtime/mail-composition.ts +0 -65
  364. package/src/runtime/memory-fold.ts +0 -55
  365. package/src/runtime/operator-token-cleanup.ts +0 -109
  366. package/src/runtime/path-shadow.ts +0 -418
  367. package/src/runtime/perf/panel-health-monitor.ts +0 -18
  368. package/src/runtime/provider-optimizer-wiring.ts +0 -55
  369. package/src/runtime/reachability-notice.ts +0 -100
  370. package/src/runtime/remote-execution-composition.ts +0 -62
  371. package/src/runtime/session-liveness-marker.ts +0 -257
  372. package/src/runtime/session-pointer-surface.ts +0 -22
  373. package/src/runtime/session-storage-services.ts +0 -41
  374. package/src/runtime/surface-feature-flags.ts +0 -96
  375. package/src/runtime/terminal-output-guard.ts +0 -235
  376. package/src/runtime/trust/workspace-registration.ts +0 -192
  377. package/src/runtime/trust/workspace-trust.ts +0 -229
  378. package/src/runtime/ui/index.ts +0 -39
  379. package/src/runtime/ui/model-picker/data-provider.ts +0 -182
  380. package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
  381. package/src/runtime/ui/model-picker/index.ts +0 -59
  382. package/src/runtime/ui/model-picker/types.ts +0 -153
  383. package/src/runtime/ui/provider-health/data-provider.ts +0 -244
  384. package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
  385. package/src/runtime/ui/provider-health/index.ts +0 -46
  386. package/src/runtime/ui/provider-health/types.ts +0 -146
  387. package/src/runtime/ui-events.ts +0 -1
  388. package/src/runtime/ui-read-model-helpers.ts +0 -1
  389. package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
  390. package/src/runtime/ui-read-models-observability-options.ts +0 -1
  391. package/src/runtime/ui-read-models-observability-remote.ts +0 -1
  392. package/src/runtime/ui-read-models-observability-security.ts +0 -1
  393. package/src/runtime/ui-read-models-observability-system.ts +0 -1
  394. package/src/runtime/ui-read-models-observability.ts +0 -1
  395. package/src/runtime/ui-service-queries.ts +0 -1
  396. package/src/runtime/voice-setup-services.ts +0 -98
  397. package/src/runtime/workstream-attempts-validation.ts +0 -77
  398. package/src/runtime/workstream-draft-edits.ts +0 -95
  399. package/src/runtime/workstream-draft-store.ts +0 -274
  400. package/src/runtime/workstream-draft-types.ts +0 -42
  401. package/src/runtime/workstream-services.ts +0 -373
  402. package/src/tools/index.ts +0 -1
  403. package/src/types/grid.ts +0 -48
  404. package/src/types/sql-js.d.ts +0 -15
  405. package/src/work-plans/work-plan-store.ts +0 -702
@@ -1,284 +0,0 @@
1
- /**
2
- * cluster-group-composition.ts — this machine's membership of a LAN group.
3
- *
4
- * Leader election answers "which of us reads the inbox". This answers the
5
- * question underneath it: "which machines are US". Without a group, any daemon
6
- * that happened to be on the same network — a neighbour's, a colleague's, a
7
- * container someone left running — would join the same coordination and one of
8
- * you would silently stop receiving messages.
9
- *
10
- * The group layer owns the socket and the election rides on it: every
11
- * coordination datagram is wrapped in the group envelope and signed with the
12
- * current group key, so a datagram from outside the group never reaches the
13
- * election at all. That is why `createClusterComposition` is handed a transport
14
- * from here instead of opening one of its own.
15
- *
16
- * Key material lives ONLY in the encrypted secrets store. Never in config,
17
- * never in a log line, never in `/status`.
18
- */
19
- import {
20
- ClusterGroupRuntime,
21
- createClusterGroupVerbs,
22
- createSystemClusterClock,
23
- readClusterSettings,
24
- rejoinGroup,
25
- resolveClusterGroupSettings,
26
- resolveNodeIdentity,
27
- stillOnRoster,
28
- UdpClusterTransport,
29
- type ClusterGroupVerbSurface,
30
- type ClusterSurfaceHolding,
31
- type GroupOperationsContext,
32
- } from '@pellux/goodvibes-sdk/platform/cluster';
33
- import type { ConfigManager, SecretsManager } from '@pellux/goodvibes-sdk/platform/config';
34
- import type { ClusterTransport } from '@pellux/goodvibes-sdk/platform/cluster';
35
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
36
- import type { ShellPathService } from '@/runtime/index.ts';
37
- import { createClusterComposition } from './cluster-composition.ts';
38
- import type { ClusterCoordinator } from '@pellux/goodvibes-sdk/platform/cluster';
39
- import { GOODVIBES_TUI_SURFACE_ROOT } from '../config/surface.ts';
40
- import { VERSION } from '../version.ts';
41
-
42
- export interface ClusterGroupComposition {
43
- readonly runtime: ClusterGroupRuntime;
44
- readonly verbs: ClusterGroupVerbSurface;
45
- /** The transport the leader election must use, so its traffic is group-signed. */
46
- readonly electionTransport: ClusterTransport;
47
- /** Start the group layer. Safe to call more than once. */
48
- start(): Promise<void>;
49
- stop(): Promise<void>;
50
- }
51
-
52
- /**
53
- * A label for THIS machine in the member list.
54
- *
55
- * Deliberately NOT the hostname. The roster replicates to every member and the
56
- * group name reaches the network in a beacon, so defaulting to a hostname would
57
- * quietly publish "mikes-laptop" to anything listening. A short slice of the
58
- * node id is meaningless and safe, and `cluster nodes` shows it plainly so an
59
- * operator who wants a real name can see there is one to set.
60
- */
61
- function defaultNodeDisplayName(nodeId: string): string {
62
- return `machine ${nodeId.slice(0, 8)}`;
63
- }
64
-
65
- /**
66
- * Build the group layer.
67
- *
68
- * Constructing it is inert: no socket is opened and no key material is read
69
- * until `start()`, so composing a runtime in a test never touches the network
70
- * or the secrets store.
71
- */
72
- export function createClusterGroupComposition(options: {
73
- readonly configManager: ConfigManager;
74
- readonly shellPaths: ShellPathService;
75
- readonly secretsManager: SecretsManager;
76
- /**
77
- * The leader election's own answer to "am I the master".
78
- *
79
- * Config replication needs exactly one machine issuing revisions, and it must
80
- * be the SAME machine leadership already picked — two notions of master in
81
- * one process would disagree the moment one of them changed.
82
- *
83
- * Late-bound because the coordinator is built from this composition's
84
- * transport: it does not exist yet when this function runs.
85
- */
86
- readonly isMaster?: (() => boolean) | undefined;
87
- /**
88
- * Which surfaces this machine currently holds, and why.
89
- *
90
- * The per-surface election establishes this; the group layer only reports it,
91
- * in `cluster status` and in /status. Late-bound for the same reason
92
- * `isMaster` is. Absent means the group layer reports that the information is
93
- * unavailable rather than reporting an empty list as though this machine held
94
- * nothing — a distinction an operator diagnosing a silent inbox depends on.
95
- */
96
- readonly surfaceHoldings?: (() => readonly ClusterSurfaceHolding[]) | undefined;
97
- }): ClusterGroupComposition {
98
- const settings = readClusterSettings(options.configManager);
99
- const groupSettings = resolveClusterGroupSettings(
100
- (options.configManager as { getCategory?: (name: string) => unknown }).getCategory?.('cluster'),
101
- );
102
- // Surface-scoped, alongside the election's node identity and this surface's
103
- // other durable state.
104
- const stateDirectory = options.shellPaths.resolveProjectPath(GOODVIBES_TUI_SURFACE_ROOT, 'cluster');
105
- const nodeId = resolveNodeIdentity({ stateDirectory, logger }).nodeId;
106
-
107
- const runtime = new ClusterGroupRuntime({
108
- settings: groupSettings,
109
- transport: new UdpClusterTransport({
110
- port: settings.port,
111
- multicastGroup: settings.multicastGroup,
112
- peers: settings.peers,
113
- logger,
114
- }),
115
- // Narrower than the SecretsManager itself: the group layer gets get/set/
116
- // delete on one key and nothing else.
117
- secrets: {
118
- get: (key) => options.secretsManager.get(key),
119
- set: (key, value) => options.secretsManager.set(key, value),
120
- delete: (key) => options.secretsManager.delete(key),
121
- },
122
- stateDirectory,
123
- nodeId,
124
- nodeDisplayName: defaultNodeDisplayName(nodeId),
125
- version: VERSION,
126
- clock: createSystemClusterClock(),
127
- logger,
128
- ...(options.isMaster ? { isMaster: options.isMaster } : {}),
129
- ...(options.surfaceHoldings ? { surfaceHoldings: options.surfaceHoldings } : {}),
130
- // Only daemon-owned, group-scoped keys ever reach this; the SDK's
131
- // replication policy decides which, and refuses anything machine-specific.
132
- config: {
133
- get: (path) => (options.configManager as unknown as {
134
- get(key: string): unknown;
135
- }).get(path),
136
- set: (path, value) => (options.configManager as unknown as {
137
- set(key: string, value: unknown): void;
138
- }).set(path, value),
139
- },
140
- });
141
-
142
- const context: GroupOperationsContext = {
143
- runtime,
144
- secrets: {
145
- get: (key) => options.secretsManager.get(key),
146
- set: (key, value) => options.secretsManager.set(key, value),
147
- delete: (key) => options.secretsManager.delete(key),
148
- },
149
- settings: groupSettings,
150
- nodeId,
151
- nodeDisplayName: defaultNodeDisplayName(nodeId),
152
- version: VERSION,
153
- now: () => Date.now(),
154
- };
155
-
156
- let started = false;
157
- return {
158
- runtime,
159
- verbs: createClusterGroupVerbs(context),
160
- electionTransport: runtime.electionTransport(),
161
- start: async () => {
162
- if (started) return;
163
- started = true;
164
- await runtime.start();
165
- await announceReturn(runtime, context, nodeId);
166
- },
167
- stop: async () => {
168
- started = false;
169
- await runtime.stop();
170
- },
171
- };
172
- }
173
-
174
- /**
175
- * Build both halves of the LAN cluster, wired to each other.
176
- *
177
- * They are mutually dependent and the dependency runs both ways, which is why
178
- * this exists rather than two calls at the composition root: the election
179
- * coordinates over the GROUP's transport, and the group's config replication
180
- * needs the ELECTION's answer to "am I the master". The master signal is read
181
- * through a closure because the coordinator does not exist yet when the group
182
- * layer is constructed.
183
- *
184
- * Constructing either is inert — no socket, no key material read — until
185
- * `startCluster` runs.
186
- */
187
- export function createClusterServices(options: {
188
- readonly configManager: ConfigManager;
189
- readonly shellPaths: ShellPathService;
190
- readonly secretsManager: SecretsManager;
191
- }): { readonly clusterGroup: ClusterGroupComposition; readonly clusterCoordinator: ClusterCoordinator } {
192
- let coordinator: ClusterCoordinator | null = null;
193
- const clusterGroup = createClusterGroupComposition({
194
- ...options,
195
- isMaster: () => coordinator?.isMaster ?? false,
196
- // The elections actually running are the only honest source for this, so
197
- // the group layer reads them rather than keeping a second tally that could
198
- // disagree. Before the coordinator exists there is nothing to report, and
199
- // an empty list is the truthful answer at that point: no election has been
200
- // held, so this machine holds nothing.
201
- surfaceHoldings: () => coordinator?.surfaceHoldings() ?? [],
202
- });
203
- coordinator = createClusterComposition({
204
- configManager: options.configManager,
205
- shellPaths: options.shellPaths,
206
- transport: clusterGroup.electionTransport,
207
- });
208
- return { clusterGroup, clusterCoordinator: coordinator };
209
- }
210
-
211
- /**
212
- * Start the LAN cluster, in the order it has to be started in.
213
- *
214
- * The group layer FIRST: it owns the socket the leader election coordinates
215
- * over, and starting the election against a transport whose group is not yet
216
- * loaded would sign its first datagrams with nothing. Both calls are
217
- * idempotent, so a composition root that reaches this twice is fine.
218
- */
219
- export async function startClusterServices(services: {
220
- readonly clusterGroup: Pick<ClusterGroupComposition, 'start'>;
221
- readonly clusterCoordinator: { start(): Promise<void> };
222
- }): Promise<void> {
223
- await services.clusterGroup.start();
224
- await services.clusterCoordinator.start();
225
- }
226
-
227
- /**
228
- * Ask the group to take this machine back, on start.
229
- *
230
- * This is the zero-touch return. A machine that has been switched off for
231
- * months — through many group-key rotations and possibly a join-key change —
232
- * comes up holding stale keys, says "it is still me" with a key that never
233
- * rotates, and is re-keyed to the current generation by whichever member
234
- * answers. The operator does nothing.
235
- *
236
- * It runs only when this machine still believes it is on the roster. A machine
237
- * that was REMOVED asks for nothing: it would be refused, and asking anyway
238
- * would put a pointless refusal in everyone's logs every time it started.
239
- */
240
- async function announceReturn(
241
- runtime: ClusterGroupRuntime,
242
- context: GroupOperationsContext,
243
- nodeId: string,
244
- ): Promise<void> {
245
- if (runtime.membership !== 'member') return;
246
- if (!stillOnRoster(runtime.groupState, nodeId)) return;
247
- const result = await rejoinGroup(context);
248
- if (result.ok) {
249
- logger.info('cluster: rejoined the group and took the current group key', {
250
- group: result.data.groupName,
251
- members: result.data.memberCount,
252
- });
253
- return;
254
- }
255
- if (result.terminal) {
256
- // A member refused this machine and proved it was a member when it did.
257
- // Retrying will never succeed, so this is not a quiet debug line: without
258
- // it the operator sees a healthy daemon that is simply never given any
259
- // work, with nothing anywhere saying why. Stated at ERROR with the command
260
- // that fixes it, the same standard a surface this node cannot serve is
261
- // held to.
262
- logger.error('cluster: this machine is no longer in its group and will not be given work', {
263
- reason: result.error,
264
- action: result.fix,
265
- });
266
- return;
267
- }
268
- if (result.failure === 'unverifiable-replies') {
269
- // Something answered and none of it could be authenticated. This machine
270
- // cannot tell a removal it slept through from a stranger making noise, so
271
- // it says exactly that and does not assert either. WARN rather than ERROR
272
- // for the same reason: anything on the network can produce this, and a
273
- // machine that shouted "you were removed" on cue would be worse than one
274
- // that stayed quiet.
275
- logger.warn('cluster: replies to this machine\'s return could not be authenticated', {
276
- reason: result.error,
277
- action: result.fix,
278
- });
279
- return;
280
- }
281
- // Not an error. A machine that starts first, or is alone on the network, has
282
- // nobody to answer it and carries on with the keys it already holds.
283
- logger.debug('cluster: no other machine answered the return announcement', { reason: result.error });
284
- }
@@ -1,167 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // code-index-services.ts — repo source-tree code index (TUI wiring)
3
- //
4
- // Constructs the TUI's repo source-tree code index: CodeIndexStore
5
- // (@pellux/goodvibes-sdk/platform/state). Extracted into its own module rather than built inline in
6
- // services.ts: services.ts sits at the architecture check's 800-line cap
7
- // (scripts/check-architecture.ts), so any new service gets its own
8
- // construction module and a single wiring call there (mirrors
9
- // createWorkstreamServices's one-function-bundle shape).
10
- //
11
- // Schema-initialized eagerly (mirrors memoryStore: construction + init()
12
- // happen unconditionally so the store is queryable — /codebase status, the
13
- // fleet node — even before any build has ever run). The actual walk/chunk/
14
- // embed build is NEVER auto-triggered by default: the hundreds of existing
15
- // test fixtures (and every headless invocation) construct RuntimeServices
16
- // without asking for a full source-tree walk, and init() alone never runs
17
- // one (mirrors the SDK's own RuntimeServices wiring in
18
- // platform/runtime/services.ts, which gates its equivalent scheduleBuild()
19
- // call behind an explicit autoStartCodeIndex option).
20
- //
21
- // REALITY-WINS DIVERGENCE from the SDK's own shape: the SDK's
22
- // RuntimeServicesOptions exposes autoStartCodeIndex as a constructor-time
23
- // boolean because that call site is a library entrypoint threaded by each
24
- // embedder. This TUI's createRuntimeServices has no such per-call knob —
25
- // auto-start is decided from a TUI-local config key instead
26
- // (CODE_INDEX_ENABLED_CONFIG_KEY, default OFF), so every construction path
27
- // (interactive main.ts, the daemon, and every test fixture) shares one
28
- // honest, user-visible on/off switch rather than needing to thread a new
29
- // boolean through every call site. With it off (the default), `/codebase
30
- // build` is the explicit, visible trigger — exactly the shape this design
31
- // asks for.
32
- //
33
- // Shares memoryEmbeddingRegistry with MemoryStore (constructed in
34
- // services.ts) so code + memory retrieval use one embedding provider and one
35
- // dimensionality, per the SDK design doc (code-index-store.ts's constructor
36
- // takes the SAME MemoryEmbeddingProviderRegistry instance memory uses).
37
- // ---------------------------------------------------------------------------
38
-
39
- import { join } from 'node:path';
40
- import { CodeIndexStore, CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
41
- import type { MemoryEmbeddingProviderRegistry } from '@pellux/goodvibes-sdk/platform/state';
42
- import type { ConfigKey, ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
43
- import { readBooleanConfig } from '../core/alert-gating.ts';
44
-
45
- /**
46
- * TUI-local synthetic config key (not yet in the SDK's ConfigKey union) that
47
- * gates the code index's auto-build on construction. Default OFF — see this
48
- * module's header doc. Surfaced in /config via a synthetic entry
49
- * (settings-modal-data.ts) exactly like behavior.notifyAfterSeconds.
50
- */
51
- export const CODE_INDEX_ENABLED_CONFIG_KEY = 'storage.codeIndexEnabled';
52
-
53
- /**
54
- * Honest, generous bounds passed EXPLICITLY to CodeIndexStore (values equal
55
- * to its own internal defaults) so /codebase status and the settings
56
- * description can state them in one place without reaching into store
57
- * internals or duplicating magic numbers.
58
- */
59
- export const CODE_INDEX_MAX_FILES = 5000;
60
- export const CODE_INDEX_MAX_FILE_BYTES = 512 * 1024;
61
- export const CODE_INDEX_MAX_TOTAL_BYTES = 256 * 1024 * 1024;
62
-
63
- export interface CodeIndexServicesDeps {
64
- readonly workingDirectory: string;
65
- readonly configManager: Pick<ConfigManager, 'get'>;
66
- readonly memoryEmbeddingRegistry: MemoryEmbeddingProviderRegistry;
67
- /**
68
- * Memory-governor backpressure (optional): when the governor pauses the
69
- * 'code-index-reindex' job, the tool-site reindex scheduler stops scheduling
70
- * new work; the critical tier refuses new reindex work outright via
71
- * admitExpensiveWork. Absent (most test fixtures) → never paused, always
72
- * admitted, exactly as before.
73
- */
74
- readonly isReindexPaused?: (() => boolean) | undefined;
75
- readonly admitExpensiveWork?: ((label: string) => { allowed: boolean; reason?: string | undefined }) | undefined;
76
- }
77
-
78
- /**
79
- * Whether code auto-injection / tool-site reindex may run: the SAME
80
- * storage.codeIndexEnabled switch that gates auto-build. Read live so a runtime
81
- * /config toggle takes effect without restart. (The separate, default-off
82
- * `agent-passive-code-injection` feature flag gates injection additionally; this
83
- * is only the storage-side setting the SDK asks embedders to respect.)
84
- */
85
- export function isCodeInjectionSettingEnabled(configManager: Pick<ConfigManager, 'get'>): boolean {
86
- return isCodeIndexAutoStartEnabled(configManager);
87
- }
88
-
89
- export interface CodeIndexServices {
90
- readonly codeIndexStore: CodeIndexStore;
91
- /**
92
- * Tool-site incremental reindex scheduler, bound to codeIndexStore and
93
- * gated live on storage.codeIndexEnabled. Threaded into both SDK orchestrators (main +
94
- * agent) so a successful write/edit debounces an incremental reindex, and into the command
95
- * context so /codebase status can report the last reindex activity honestly.
96
- */
97
- readonly codeIndexReindexScheduler: CodeIndexReindexScheduler;
98
- }
99
-
100
- /** Absolute path to the TUI's code-index sqlite file, sibling to memory.sqlite under .goodvibes/tui/. */
101
- export function codeIndexDbPath(workingDirectory: string): string {
102
- return join(workingDirectory, '.goodvibes', 'tui', 'code-index.sqlite');
103
- }
104
-
105
- /**
106
- * Build the runtime's `rerootStores` implementation — called by
107
- * WorkspaceSwapManager after it has verified a new working directory.
108
- *
109
- * Only working-tree-bound stores move. The memory store is deliberately NOT
110
- * rerooted: it is the home-scoped canonical cross-surface store, and moving
111
- * it per project would re-silo memory back into the per-project stores that
112
- * were consolidated away.
113
- */
114
- export function createStoreRerooter(deps: {
115
- readonly codeIndexStore: Pick<CodeIndexStore, 'reroot'>;
116
- readonly projectIndex: { reroot(dir: string): Promise<unknown> };
117
- }): (newWorkingDir: string) => Promise<void> {
118
- return async (newWorkingDir: string): Promise<void> => {
119
- await deps.codeIndexStore.reroot(newWorkingDir, codeIndexDbPath(newWorkingDir));
120
- await deps.projectIndex.reroot(newWorkingDir);
121
- };
122
- }
123
-
124
- /**
125
- * Whether the code index's initial build should auto-start on construction.
126
- * Exported so /codebase status and the settings modal read the exact same
127
- * config key + default this module decides auto-start from.
128
- */
129
- export function isCodeIndexAutoStartEnabled(configManager: Pick<ConfigManager, 'get'>): boolean {
130
- return readBooleanConfig(
131
- (key) => configManager.get(key as ConfigKey),
132
- CODE_INDEX_ENABLED_CONFIG_KEY,
133
- false,
134
- );
135
- }
136
-
137
- /**
138
- * Constructs the TUI's CodeIndexStore. Schema-init runs unconditionally
139
- * (init() never throws — it degrades to an honest `available: false` +
140
- * recorded error on failure, mirrored by CodeIndexStats/describeDegradation);
141
- * the initial full build only fires when isCodeIndexAutoStartEnabled() is
142
- * true, via the SAME fire-and-forget scheduleBuild() an explicit
143
- * `/codebase build` invocation uses.
144
- */
145
- export function createCodeIndexServices(deps: CodeIndexServicesDeps): CodeIndexServices {
146
- const codeIndexStore = new CodeIndexStore(
147
- deps.workingDirectory,
148
- codeIndexDbPath(deps.workingDirectory),
149
- deps.memoryEmbeddingRegistry,
150
- { maxFiles: CODE_INDEX_MAX_FILES, maxFileBytes: CODE_INDEX_MAX_FILE_BYTES, maxTotalBytes: CODE_INDEX_MAX_TOTAL_BYTES },
151
- );
152
- codeIndexStore.init();
153
- if (isCodeIndexAutoStartEnabled(deps.configManager)) {
154
- codeIndexStore.scheduleBuild();
155
- }
156
- const codeIndexReindexScheduler = new CodeIndexReindexScheduler({
157
- target: codeIndexStore,
158
- workingDirectory: deps.workingDirectory,
159
- // Honor governor backpressure: a paused code-index reindex job stops
160
- // scheduling new work until the governor resumes it, and the critical
161
- // memory tier refuses new reindex work outright (mirrors the SDK).
162
- isEnabled: () => isCodeInjectionSettingEnabled(deps.configManager)
163
- && !(deps.isReindexPaused?.() ?? false)
164
- && (deps.admitExpensiveWork?.('code-index reindex').allowed ?? true),
165
- });
166
- return { codeIndexStore, codeIndexReindexScheduler };
167
- }
@@ -1,76 +0,0 @@
1
- /**
2
- * daemon-handler-composition.ts — the daemon's HOST-side handler surfaces.
3
- *
4
- * Attaches this repository's handlers to the SDK-auto-registered builtin
5
- * gateway descriptors (channels.* / email.* / calendar.*) via
6
- * catalog.register(descriptor, handler, { replace: true }) — the SDK owns
7
- * every id, descriptor and schema; only the behaviour is ours. The remote
8
- * surface reuses the SAME DistributedRuntimeManager the SDK facade injects.
9
- *
10
- * Split out of services.ts for the 800-line file cap, the same reason
11
- * channel-composition.ts exists.
12
- *
13
- * The one behavioural decision that lives here: the inbox poller is handed to
14
- * the cluster coordinator instead of being started eagerly. It is this
15
- * product's own inbound consumer — the SDK facade does not know it exists —
16
- * so if it is not gated here it is not gated anywhere, and two goodvibes nodes
17
- * on one network each read the shared inbox and answer the same message twice.
18
- */
19
- import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
20
- import type { ClusterCoordinator } from '@pellux/goodvibes-sdk/platform/cluster';
21
- import type { GatewayMethodCatalog } from '@pellux/goodvibes-sdk/platform/control-plane';
22
- import type { SecretsManager } from '@pellux/goodvibes-sdk/platform/config';
23
- import { registerDaemonHandlers, type DaemonHandlerSurfaces } from '../daemon/handlers/index.ts';
24
- import type { HandlerContext, HandlerLogger } from '../daemon/handlers/context.ts';
25
- import { createDaemonCredentialStore } from '../daemon/handlers/credentials.ts';
26
- import { registerRouting } from '../daemon/handlers/routing/index.ts';
27
- import { registerInboxMethods } from '../daemon/handlers/inbox/index.ts';
28
- import { registerTriagedInbox } from '../daemon/handlers/triage/index.ts';
29
- import { registerDraftMethods } from '../daemon/handlers/drafts/index.ts';
30
- import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
31
- import { inboxPollerGate } from './cluster-composition.ts';
32
-
33
- export interface DaemonHandlerCompositionOptions {
34
- readonly gatewayMethods: GatewayMethodCatalog;
35
- readonly secretsManager: SecretsManager;
36
- readonly configManager: ConfigManager;
37
- readonly workingDirectory: string;
38
- readonly homeDirectory: string;
39
- readonly distributedRuntime: NonNullable<Parameters<typeof registerRemoteSurface>[1]>['manager'];
40
- /**
41
- * Decides whether THIS node polls the shared inbox. Always supplied by the
42
- * composition root; the poller is never started outside it.
43
- */
44
- readonly clusterCoordinator: ClusterCoordinator;
45
- }
46
-
47
- export function createDaemonHandlerComposition(
48
- options: DaemonHandlerCompositionOptions,
49
- ): DaemonHandlerSurfaces {
50
- const handlerLogger: HandlerLogger = {
51
- info: (message, meta) => console.info(message, meta ?? ''),
52
- warn: (message, meta) => console.warn(message, meta ?? ''),
53
- error: (message, meta) => console.error(message, meta ?? ''),
54
- };
55
- const handlerContext: HandlerContext = {
56
- catalog: options.gatewayMethods,
57
- credentials: createDaemonCredentialStore(options.secretsManager),
58
- configManager: options.configManager,
59
- workingDirectory: options.workingDirectory,
60
- homeDirectory: options.homeDirectory,
61
- logger: handlerLogger,
62
- };
63
- return registerDaemonHandlers(handlerContext, {
64
- registerRouting,
65
- registerInbox: (ctx, routing) =>
66
- registerTriagedInbox(ctx, (inboxCtx) => registerInboxMethods(inboxCtx, routing, {
67
- // Hands polling to leadership. The `channels.inbox.list` read stays
68
- // available on every node — a standby still SERVES the persisted feed,
69
- // it just does not FETCH into it.
70
- gatePolling: (providerId, control) =>
71
- options.clusterCoordinator.register(inboxPollerGate(providerId, control)),
72
- })).unregister,
73
- registerDrafts: (ctx) => registerDraftMethods(ctx),
74
- registerRemote: (ctx) => registerRemoteSurface(ctx, { manager: options.distributedRuntime }),
75
- });
76
- }
@@ -1,110 +0,0 @@
1
- /**
2
- * device-posture-composition.ts — the paired-phone feature inside THIS daemon.
3
- *
4
- * A phone pairs with whichever daemon the person runs, and for this owner that
5
- * daemon is hosted by the terminal app. Until this module existed the app had no
6
- * device posture at all: `device.nodes.maxPaired` was enforced at the pairing
7
- * path (SDK-side) and `device.capabilities.mode` was an onboarding toggle, while
8
- * the other eleven `device.*` keys were recorded, read back, and governed
9
- * nothing — the capability service they describe was never built here, so there
10
- * was nothing for them to govern.
11
- *
12
- * The feature itself is platform-owned (`platform/devices`): the settings→policy
13
- * mapping, the grants ledger, the capture store, the housekeeping sweeps, the
14
- * confirmation flow, and the `phone` tool. This module supplies the three seams
15
- * that are actually ours and nothing else:
16
- *
17
- * - the peer transport — the same DistributedRuntimeManager the remote surface
18
- * pairs devices onto, so a phone paired here is a node here,
19
- * - the approval path — the shared approval broker, so the confirmation
20
- * appears wherever the person is looking (terminal, web app, companion),
21
- * - the storage root and the live config manager.
22
- *
23
- * Constructing this starts nothing. `startHousekeeping()` is called from the
24
- * bootstrap tail: grants and captures both outlive a restart, so a grant whose
25
- * phone is gone, or a capture torn by a crash, is reaped BEFORE the first
26
- * request of this run is served — and the periodic sweep after it is what keeps
27
- * a long-running daemon from going days without one. A failed sweep is logged
28
- * and the app still runs: housekeeping failing is a reason to say so, not a
29
- * reason to refuse to start.
30
- */
31
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
32
- import { createDevicePostureRuntime, registerDevicePhoneTool } from '@pellux/goodvibes-sdk/platform/devices';
33
- import type {
34
- DeviceApprovalBridge,
35
- DevicePeerTransport,
36
- DevicePhoneToolRegistry,
37
- DevicePostureRuntime,
38
- } from '@pellux/goodvibes-sdk/platform/devices';
39
- import { registerDevicesGatewayMethods } from '@pellux/goodvibes-sdk/platform/control-plane';
40
- import type { GatewayMethodCatalog } from '@pellux/goodvibes-sdk/platform/control-plane';
41
- import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
42
-
43
- /** Who this surface records in the device audit trail. */
44
- export const TUI_DEVICE_ACTOR = 'tui:phone-tool';
45
-
46
- export interface DevicePostureCompositionOptions {
47
- readonly configManager: ConfigManager;
48
- /** The runtime devices pair onto; its listPeers/invokePeer are the transport. */
49
- readonly distributedRuntime: DevicePeerTransport;
50
- readonly approvals: DeviceApprovalBridge;
51
- /** Surface-scoped directory the grants ledger, captures and disclosure live in. */
52
- readonly stateDirectory: string;
53
- /**
54
- * Binding the catalog turns devices.nodes.list / devices.grants.* /
55
- * devices.housekeeping.run from cataloged-but-unhandled into real handlers,
56
- * which is what makes the grants surface work in the web app and the companion
57
- * rather than only through this app's own tool.
58
- */
59
- readonly gatewayMethods?: GatewayMethodCatalog | undefined;
60
- readonly getSessionId?: (() => string | undefined) | undefined;
61
- }
62
-
63
- export interface DevicePostureServices {
64
- readonly devicePosture: DevicePostureRuntime;
65
- }
66
-
67
- /** Build the device posture runtime and bind the device verbs to it. */
68
- export function createDevicePostureServices(options: DevicePostureCompositionOptions): DevicePostureServices {
69
- const devicePosture = createDevicePostureRuntime({
70
- transport: options.distributedRuntime,
71
- approvals: options.approvals,
72
- config: options.configManager,
73
- stateDirectory: options.stateDirectory,
74
- actor: TUI_DEVICE_ACTOR,
75
- ...(options.getSessionId ? { getSessionId: options.getSessionId } : {}),
76
- });
77
- if (options.gatewayMethods) registerDevicesGatewayMethods(options.gatewayMethods, devicePosture);
78
- return { devicePosture };
79
- }
80
-
81
- /**
82
- * Everything a host with a tool registry has to do once it is up: register the
83
- * `phone` tool — the only path that reaches the capability service, so without it
84
- * the posture keys govern nothing a session can observe — and start housekeeping.
85
- *
86
- * One call, because these two belong to the same feature and a host that did the
87
- * first and forgot the second would serve requests while never reaping a grant
88
- * whose phone is gone.
89
- */
90
- export function installDevicePosture(
91
- toolRegistry: DevicePhoneToolRegistry,
92
- devicePosture: DevicePostureRuntime,
93
- ): void {
94
- registerDevicePhoneTool(toolRegistry, devicePosture);
95
- startDeviceHousekeeping(devicePosture);
96
- }
97
-
98
- /**
99
- * The recovery sweep plus the periodic timer. Separate from construction so
100
- * composing a runtime in a test starts no timer and touches no disk, and
101
- * separate from the call above so the standalone daemon — which registers no
102
- * tools — still sweeps.
103
- */
104
- export function startDeviceHousekeeping(devicePosture: DevicePostureRuntime): void {
105
- void devicePosture.startHousekeeping().catch((error: unknown) => {
106
- logger.warn('Device housekeeping sweep failed at startup', {
107
- error: error instanceof Error ? error.message : String(error),
108
- });
109
- });
110
- }