@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,357 +0,0 @@
1
- import { HandlerSqliteStore } from '../sqlite-store.ts';
2
- import {
3
- isSecretReferenceValue,
4
- isMalformedGoodVibesSecretReferenceValue,
5
- } from '../../../config/secret-config.ts';
6
-
7
- // ---------------------------------------------------------------------------
8
- // Backend vocabulary + per-backend config shapes
9
- // ---------------------------------------------------------------------------
10
-
11
- export type BackendKind = 'docker' | 'ssh' | 'cloud-terminal' | 'local-process';
12
-
13
- export type CloudProvider = 'gcp' | 'aws' | 'azure';
14
-
15
- export interface DockerBackendConfig {
16
- containerName: string;
17
- /**
18
- * Optional Docker host. When it points at a remote daemon over TLS this MUST
19
- * be a goodvibes://secrets/ reference (never a raw URL with embedded creds).
20
- * A bare local socket path (unix://...) or tcp host without credentials is
21
- * also accepted.
22
- */
23
- dockerHost?: string;
24
- }
25
-
26
- export interface SshBackendConfig {
27
- sshHost: string;
28
- sshPort?: number;
29
- sshUser: string;
30
- /** goodvibes://secrets/ reference to the private key — never the raw key. */
31
- identityRef: string;
32
- }
33
-
34
- export interface CloudTerminalBackendConfig {
35
- provider: CloudProvider;
36
- projectId?: string;
37
- /** goodvibes://secrets/ reference to the provider credential. */
38
- credentialRef: string;
39
- /** Optional zone/region/location passed to the provider CLI. */
40
- location?: string;
41
- /** For gcp: the Cloud Shell / VM instance to target. */
42
- instance?: string;
43
- }
44
-
45
- export interface LocalProcessBackendConfig {
46
- /** Optional working directory for spawned processes. */
47
- cwd?: string;
48
- /** Optional allowlist of executables; when set, only these may be invoked. */
49
- allowedCommands?: string[];
50
- }
51
-
52
- export type BackendConfig =
53
- | ({ kind: 'docker' } & DockerBackendConfig)
54
- | ({ kind: 'ssh' } & SshBackendConfig)
55
- | ({ kind: 'cloud-terminal' } & CloudTerminalBackendConfig)
56
- | ({ kind: 'local-process' } & LocalProcessBackendConfig);
57
-
58
- export interface PeerRecord {
59
- peerId: string;
60
- displayName: string;
61
- backendKind: BackendKind;
62
- backendConfig: BackendConfig;
63
- }
64
-
65
- export interface PeerRegistrationInput {
66
- peerId: string;
67
- displayName: string;
68
- backendKind: BackendKind;
69
- // Raw, untrusted config from the operator method body. Normalized + validated.
70
- backendConfig: Record<string, unknown>;
71
- }
72
-
73
- // ---------------------------------------------------------------------------
74
- // Validation helpers — backendConfig must hold ONLY secret refs for any
75
- // credential-bearing field. Raw secrets are rejected outright.
76
- // ---------------------------------------------------------------------------
77
-
78
- class PeerRegistryValidationError extends Error {
79
- constructor(message: string) {
80
- super(message);
81
- this.name = 'PeerRegistryValidationError';
82
- }
83
- }
84
-
85
- function requireString(value: unknown, field: string): string {
86
- if (typeof value !== 'string' || value.trim().length === 0) {
87
- throw new PeerRegistryValidationError(`Field '${field}' is required and must be a non-empty string.`);
88
- }
89
- return value.trim();
90
- }
91
-
92
- function optionalString(value: unknown, field: string): string | undefined {
93
- if (value === undefined || value === null) return undefined;
94
- if (typeof value !== 'string') {
95
- throw new PeerRegistryValidationError(`Field '${field}' must be a string when provided.`);
96
- }
97
- const trimmed = value.trim();
98
- return trimmed.length === 0 ? undefined : trimmed;
99
- }
100
-
101
- function requireSecretRef(value: unknown, field: string): string {
102
- const ref = requireString(value, field);
103
- if (!isSecretReferenceValue(ref)) {
104
- throw new PeerRegistryValidationError(
105
- `Field '${field}' must be a goodvibes://secrets/ reference, not a raw credential.`,
106
- );
107
- }
108
- return ref;
109
- }
110
-
111
- function assertDockerHostSafe(value: string | undefined, field: string): void {
112
- // A dockerHost is accepted in exactly two shapes, mirroring how docker.ts
113
- // resolves it (docker.ts: `startsWith('goodvibes://') ? resolveRef(...) : raw`):
114
- // 1. A goodvibes://secrets/ reference — resolved from the credential store.
115
- // 2. A credential-free local/plain address (unix:// socket, or a bare
116
- // tcp/host with no embedded userinfo) — used verbatim.
117
- // Enforcement here must match that resolution so no credential-bearing or
118
- // unresolvable value slips through to docker.ts.
119
- if (value === undefined) return;
120
-
121
- // A valid secret ref is always allowed: docker.ts resolves it from the store.
122
- if (isSecretReferenceValue(value)) return;
123
-
124
- // A `goodvibes://` value that is NOT a well-formed secret ref would be handed
125
- // to credentials.resolveRef() and fail opaquely (REMOTE_BACKEND_CREDENTIAL_MISSING)
126
- // — or, worse, a near-miss could be treated as a literal host. Reject it at
127
- // registration so the misconfiguration surfaces immediately.
128
- if (isMalformedGoodVibesSecretReferenceValue(value)) {
129
- throw new PeerRegistryValidationError(
130
- `Field '${field}' looks like a goodvibes:// reference but is malformed; use a valid goodvibes://secrets/ reference.`,
131
- );
132
- }
133
-
134
- // Embedded userinfo credentials (e.g. tcp://user:pass@host) must never be
135
- // stored raw — docker.ts would pass them verbatim as DOCKER_HOST.
136
- if (value.includes('@')) {
137
- throw new PeerRegistryValidationError(
138
- `Field '${field}' appears to embed credentials; pass a goodvibes://secrets/ reference instead.`,
139
- );
140
- }
141
-
142
- // A remote daemon reached over TLS carries its credentials out-of-band and
143
- // MUST be referenced through the credential store, never pinned as a raw
144
- // host string the daemon would use unauthenticated. docker.ts only treats a
145
- // goodvibes:// value as a secret, so a raw `https://`/`tcp+tls://` endpoint
146
- // here would bypass credential resolution entirely.
147
- const lowered = value.toLowerCase();
148
- if (lowered.startsWith('https://') || lowered.startsWith('tcp+tls://')) {
149
- throw new PeerRegistryValidationError(
150
- `Field '${field}' points at a TLS Docker daemon; pass a goodvibes://secrets/ reference instead of a raw URL.`,
151
- );
152
- }
153
- }
154
-
155
- /** Normalize + validate raw backendConfig into a typed, ref-only BackendConfig. */
156
- export function normalizeBackendConfig(
157
- backendKind: BackendKind,
158
- raw: Record<string, unknown>,
159
- ): BackendConfig {
160
- switch (backendKind) {
161
- case 'docker': {
162
- const dockerHost = optionalString(raw.dockerHost, 'dockerHost');
163
- assertDockerHostSafe(dockerHost, 'dockerHost');
164
- return {
165
- kind: 'docker',
166
- containerName: requireString(raw.containerName, 'containerName'),
167
- ...(dockerHost !== undefined ? { dockerHost } : {}),
168
- };
169
- }
170
- case 'ssh': {
171
- const portValue = raw.sshPort;
172
- let sshPort: number | undefined;
173
- if (portValue !== undefined && portValue !== null) {
174
- const parsed = typeof portValue === 'number' ? portValue : Number(portValue);
175
- if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) {
176
- throw new PeerRegistryValidationError("Field 'sshPort' must be an integer between 1 and 65535.");
177
- }
178
- sshPort = parsed;
179
- }
180
- return {
181
- kind: 'ssh',
182
- sshHost: requireString(raw.sshHost, 'sshHost'),
183
- sshUser: requireString(raw.sshUser, 'sshUser'),
184
- identityRef: requireSecretRef(raw.identityRef, 'identityRef'),
185
- ...(sshPort !== undefined ? { sshPort } : {}),
186
- };
187
- }
188
- case 'cloud-terminal': {
189
- const provider = requireString(raw.provider, 'provider');
190
- if (provider !== 'gcp' && provider !== 'aws' && provider !== 'azure') {
191
- throw new PeerRegistryValidationError("Field 'provider' must be one of 'gcp' | 'aws' | 'azure'.");
192
- }
193
- const projectId = optionalString(raw.projectId, 'projectId');
194
- const location = optionalString(raw.location, 'location');
195
- const instance = optionalString(raw.instance, 'instance');
196
- return {
197
- kind: 'cloud-terminal',
198
- provider,
199
- credentialRef: requireSecretRef(raw.credentialRef, 'credentialRef'),
200
- ...(projectId !== undefined ? { projectId } : {}),
201
- ...(location !== undefined ? { location } : {}),
202
- ...(instance !== undefined ? { instance } : {}),
203
- };
204
- }
205
- case 'local-process': {
206
- const cwd = optionalString(raw.cwd, 'cwd');
207
- let allowedCommands: string[] | undefined;
208
- if (raw.allowedCommands !== undefined && raw.allowedCommands !== null) {
209
- if (!Array.isArray(raw.allowedCommands)) {
210
- throw new PeerRegistryValidationError("Field 'allowedCommands' must be an array of strings.");
211
- }
212
- const list = raw.allowedCommands
213
- .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
214
- .filter((entry) => entry.length > 0);
215
- allowedCommands = list;
216
- }
217
- return {
218
- kind: 'local-process',
219
- ...(cwd !== undefined ? { cwd } : {}),
220
- ...(allowedCommands !== undefined ? { allowedCommands } : {}),
221
- };
222
- }
223
- default:
224
- throw new PeerRegistryValidationError(`Unknown backendKind: ${String(backendKind)}`);
225
- }
226
- }
227
-
228
- // ---------------------------------------------------------------------------
229
- // Peer registry — persisted via HandlerSqliteStore (peer-registry.sqlite)
230
- // ---------------------------------------------------------------------------
231
-
232
- const PEER_REGISTRY_FILE = 'peer-registry.sqlite';
233
-
234
- const SCHEMA = [
235
- `CREATE TABLE IF NOT EXISTS peers (
236
- peerId TEXT PRIMARY KEY,
237
- displayName TEXT NOT NULL,
238
- backendKind TEXT NOT NULL,
239
- backendConfig TEXT NOT NULL
240
- )`,
241
- ];
242
-
243
- interface PeerRow {
244
- peerId: string;
245
- displayName: string;
246
- backendKind: string;
247
- backendConfig: string;
248
- }
249
-
250
- const VALID_BACKEND_KINDS: ReadonlySet<BackendKind> = new Set([
251
- 'docker',
252
- 'ssh',
253
- 'cloud-terminal',
254
- 'local-process',
255
- ]);
256
-
257
- function rowToRecord(row: PeerRow): PeerRecord {
258
- const backendKind = row.backendKind as BackendKind;
259
- const parsed = JSON.parse(row.backendConfig) as BackendConfig;
260
- return {
261
- peerId: row.peerId,
262
- displayName: row.displayName,
263
- backendKind,
264
- backendConfig: parsed,
265
- };
266
- }
267
-
268
- export class PeerRegistry {
269
- private readonly store: HandlerSqliteStore;
270
- private initialized = false;
271
-
272
- constructor(workingDirectory: string) {
273
- this.store = new HandlerSqliteStore({
274
- workingDirectory,
275
- fileName: PEER_REGISTRY_FILE,
276
- schema: SCHEMA,
277
- });
278
- }
279
-
280
- get dbPath(): string {
281
- return this.store.dbPath;
282
- }
283
-
284
- async init(): Promise<void> {
285
- if (this.initialized) return;
286
- await this.store.init();
287
- this.initialized = true;
288
- }
289
-
290
- private requireInit(): void {
291
- if (!this.initialized) {
292
- throw new Error('PeerRegistry not initialized: call init() first.');
293
- }
294
- }
295
-
296
- /** Register (upsert) a peer. Validates + normalizes backendConfig to refs-only. */
297
- async register(input: PeerRegistrationInput): Promise<PeerRecord> {
298
- this.requireInit();
299
- const peerId = requireString(input.peerId, 'peerId');
300
- const displayName = requireString(input.displayName, 'displayName');
301
- if (!VALID_BACKEND_KINDS.has(input.backendKind)) {
302
- throw new PeerRegistryValidationError(`Unknown backendKind: ${String(input.backendKind)}`);
303
- }
304
- const backendConfig = normalizeBackendConfig(input.backendKind, input.backendConfig ?? {});
305
- const serialized = JSON.stringify(backendConfig);
306
- this.store.run(
307
- `INSERT INTO peers (peerId, displayName, backendKind, backendConfig)
308
- VALUES (?, ?, ?, ?)
309
- ON CONFLICT(peerId) DO UPDATE SET
310
- displayName = excluded.displayName,
311
- backendKind = excluded.backendKind,
312
- backendConfig = excluded.backendConfig`,
313
- [peerId, displayName, input.backendKind, serialized],
314
- );
315
- await this.store.save();
316
- return { peerId, displayName, backendKind: input.backendKind, backendConfig };
317
- }
318
-
319
- /** Look up a peer by id. Returns null when not registered. */
320
- get(peerId: string): PeerRecord | null {
321
- this.requireInit();
322
- const row = this.store.get<PeerRow>(
323
- 'SELECT peerId, displayName, backendKind, backendConfig FROM peers WHERE peerId = ?',
324
- [peerId],
325
- );
326
- return row ? rowToRecord(row) : null;
327
- }
328
-
329
- /** List all registered peers (config included; contains only secret refs). */
330
- list(): PeerRecord[] {
331
- this.requireInit();
332
- const rows = this.store.all<PeerRow>(
333
- 'SELECT peerId, displayName, backendKind, backendConfig FROM peers ORDER BY peerId ASC',
334
- );
335
- return rows.map(rowToRecord);
336
- }
337
-
338
- /** Remove a peer. Returns true when a row was deleted. */
339
- async remove(peerId: string): Promise<boolean> {
340
- this.requireInit();
341
- const existed = this.get(peerId) !== null;
342
- if (existed) {
343
- this.store.run('DELETE FROM peers WHERE peerId = ?', [peerId]);
344
- await this.store.save();
345
- }
346
- return existed;
347
- }
348
-
349
- close(): void {
350
- if (this.initialized) {
351
- this.store.close();
352
- this.initialized = false;
353
- }
354
- }
355
- }
356
-
357
- export { PeerRegistryValidationError };
@@ -1,191 +0,0 @@
1
- /**
2
- * Host implementation of the daemon-sdk `DistributedRuntimeRouteService` (17
3
- * methods). The SDK ships NO docker/ssh/cloud backend, so the host owns it:
4
- *
5
- * - `invokePeer` executes against the host's own remote backends through the
6
- * `RemoteDispatcher` (docker / ssh / cloud-terminal / local-process). This is
7
- * the only method that performs real command execution.
8
- * - The 16 peer / pairing / work-queue methods are backed by the SDK's
9
- * `DistributedRuntimeManager` (constructed by the surface), which owns peer
10
- * records, pairing challenges, token rotation, and the work queue.
11
- *
12
- * The SDK injects this instance into `DaemonRemoteRouteContext.distributedRuntime`
13
- * so the published `remote.peers.*` HTTP routes dispatch to it. No catalog
14
- * descriptor or schema is authored here.
15
- */
16
- import { operations } from '@pellux/goodvibes-sdk/platform/runtime';
17
- import type {
18
- DistributedRuntimeRouteService,
19
- RemotePeerAuth,
20
- } from '../contracts.ts';
21
- import { RemoteDispatcher } from './dispatcher.ts';
22
- import type { DispatchPayload } from './backends/index.ts';
23
-
24
- type DistributedRuntimeManager = operations.DistributedRuntimeManager;
25
- type DistributedPeerAuth = operations.DistributedPeerAuth;
26
-
27
- /** Coerce an injected `RemotePeerAuth` (typed `unknown` by the SDK) to the manager's auth shape. */
28
- function asPeerAuth(auth: RemotePeerAuth): DistributedPeerAuth {
29
- return auth as DistributedPeerAuth;
30
- }
31
-
32
- /** Narrow an arbitrary route-supplied input bag to a typed manager input. */
33
- function asInput<T>(input: Record<string, unknown>): T {
34
- return input as unknown as T;
35
- }
36
-
37
- function readString(input: Record<string, unknown>, key: string): string {
38
- const value = input[key];
39
- return typeof value === 'string' ? value : '';
40
- }
41
-
42
- function readPrincipal(input: Record<string, unknown>): string {
43
- const actor = input.actor ?? input.principalId ?? input.queuedBy;
44
- return typeof actor === 'string' && actor.length > 0 ? actor : 'remote';
45
- }
46
-
47
- function readPayload(input: Record<string, unknown>): DispatchPayload | undefined {
48
- const payload = input.payload;
49
- if (payload && typeof payload === 'object') {
50
- return payload as DispatchPayload;
51
- }
52
- return undefined;
53
- }
54
-
55
- export class HostDistributedRuntime implements DistributedRuntimeRouteService {
56
- private readonly manager: DistributedRuntimeManager;
57
- private readonly dispatcher: RemoteDispatcher;
58
-
59
- constructor(manager: DistributedRuntimeManager, dispatcher: RemoteDispatcher) {
60
- this.manager = manager;
61
- this.dispatcher = dispatcher;
62
- }
63
-
64
- // --- Pairing -------------------------------------------------------------
65
-
66
- listPairRequests(): unknown {
67
- return this.manager.listPairRequests();
68
- }
69
-
70
- requestPairing(input: Record<string, unknown>): Promise<unknown> {
71
- return this.manager.requestPairing(
72
- asInput<Parameters<DistributedRuntimeManager['requestPairing']>[0]>(input),
73
- );
74
- }
75
-
76
- approvePairRequest(requestId: string, input: Record<string, unknown>): Promise<unknown | null> {
77
- return this.manager.approvePairRequest(
78
- requestId,
79
- asInput<Parameters<DistributedRuntimeManager['approvePairRequest']>[1]>(input),
80
- );
81
- }
82
-
83
- rejectPairRequest(requestId: string, input: Record<string, unknown>): Promise<unknown | null> {
84
- return this.manager.rejectPairRequest(
85
- requestId,
86
- asInput<Parameters<DistributedRuntimeManager['rejectPairRequest']>[1]>(input),
87
- );
88
- }
89
-
90
- verifyPairRequest(
91
- requestId: string,
92
- challenge: string,
93
- input: Record<string, unknown>,
94
- ): Promise<unknown | null> {
95
- return this.manager.verifyPairRequest(
96
- requestId,
97
- challenge,
98
- asInput<Parameters<DistributedRuntimeManager['verifyPairRequest']>[2]>(input),
99
- );
100
- }
101
-
102
- // --- Peer management -----------------------------------------------------
103
-
104
- listPeers(): unknown {
105
- return this.manager.listPeers();
106
- }
107
-
108
- rotatePeerToken(peerId: string, input: Record<string, unknown>): Promise<unknown | null> {
109
- return this.manager.rotatePeerToken(
110
- peerId,
111
- asInput<Parameters<DistributedRuntimeManager['rotatePeerToken']>[1]>(input),
112
- );
113
- }
114
-
115
- revokePeerToken(peerId: string, input: Record<string, unknown>): Promise<unknown | null> {
116
- return this.manager.revokePeerToken(
117
- peerId,
118
- asInput<Parameters<DistributedRuntimeManager['revokePeerToken']>[1]>(input),
119
- );
120
- }
121
-
122
- disconnectPeer(peerId: string, input: Record<string, unknown>): Promise<unknown | null> {
123
- return this.manager.disconnectPeer(
124
- peerId,
125
- asInput<Parameters<DistributedRuntimeManager['disconnectPeer']>[1]>(input),
126
- );
127
- }
128
-
129
- getNodeHostContract(): unknown {
130
- return this.manager.getNodeHostContract();
131
- }
132
-
133
- // --- Peer-authenticated heartbeat + work claim ---------------------------
134
-
135
- heartbeatPeer(auth: RemotePeerAuth, input: Record<string, unknown>): Promise<unknown> {
136
- return this.manager.heartbeatPeer(
137
- asPeerAuth(auth),
138
- asInput<Parameters<DistributedRuntimeManager['heartbeatPeer']>[1]>(input),
139
- );
140
- }
141
-
142
- claimWork(auth: RemotePeerAuth, input: Record<string, unknown>): Promise<unknown> {
143
- return this.manager.claimWork(
144
- asPeerAuth(auth),
145
- asInput<Parameters<DistributedRuntimeManager['claimWork']>[1]>(input),
146
- );
147
- }
148
-
149
- completeWork(
150
- auth: RemotePeerAuth,
151
- workId: string,
152
- input: Record<string, unknown>,
153
- ): Promise<unknown | null> {
154
- return this.manager.completeWork(
155
- asPeerAuth(auth),
156
- workId,
157
- asInput<Parameters<DistributedRuntimeManager['completeWork']>[2]>(input),
158
- );
159
- }
160
-
161
- // --- Work queue ----------------------------------------------------------
162
-
163
- listWork(): unknown {
164
- return this.manager.listWork();
165
- }
166
-
167
- cancelWork(workId: string, input: Record<string, unknown>): Promise<unknown | null> {
168
- return this.manager.cancelWork(
169
- workId,
170
- asInput<Parameters<DistributedRuntimeManager['cancelWork']>[1]>(input),
171
- );
172
- }
173
-
174
- // --- Command execution (host-owned backends) -----------------------------
175
-
176
- /**
177
- * Execute a command on a registered peer through the host backends. Unlike the
178
- * manager's enqueue-only `invokePeer`, this performs real docker/ssh/cloud/
179
- * local-process execution and returns a receipt with a full-stdout digest.
180
- */
181
- async invokePeer(input: Record<string, unknown>): Promise<unknown> {
182
- const payload = readPayload(input);
183
- return this.dispatcher.dispatch({
184
- peerId: readString(input, 'peerId'),
185
- command: readString(input, 'command'),
186
- principalId: readPrincipal(input),
187
- async: input.async === true,
188
- ...(payload !== undefined ? { payload } : {}),
189
- });
190
- }
191
- }
@@ -1,71 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Inbox <-> Routing resolver bridge.
3
- //
4
- // The inbox provider adapters expose a best-effort route-resolution seam: given
5
- // an inbound item's `{ provider, fromDigest, kind, routeId? }` they ask "which
6
- // daemon route binding handles this item?" and stamp the answer onto
7
- // `item.routeId` when one resolves. The routing control plane owns the
8
- // channel<->profile bindings and exposes a `RoutingResolver` whose
9
- // `getProfileForChannel(surfaceKind, routeId?)` applies the canonical
10
- // resolution order:
11
- //
12
- // 1. exact — surfaceKind AND routeId both match
13
- // 2. surface — surfaceKind matches, route has no routeId
14
- // 3. wildcard — a route with surfaceKind === 'any' (no routeId)
15
- //
16
- // This module bridges the two shapes. The bridge maps an inbound item's
17
- // `provider` to the routing `surfaceKind` and forwards an optional `routeId`
18
- // refinement; `fromDigest`/`kind` are NOT used as routing keys (the routing
19
- // store is keyed by surfaceKind + optional routeId only, never by sender digest
20
- // or message kind — see RoutingChannelRoute). When no binding matches the
21
- // resolver returns null and the bridge yields `undefined`, so the adapter falls
22
- // back to leaving the item unrouted (offline/default behaviour intact). The
23
- // bridge NEVER throws: the underlying resolver is a pure in-memory lookup.
24
- //
25
- // The inbox surface is a separate follow-up module, so this bridge declares the
26
- // minimal `RouteResolver` seam locally rather than importing a sibling that the
27
- // routing slice does not own — keeping the routing handler layer free of any
28
- // cross-surface import edge.
29
- // ---------------------------------------------------------------------------
30
-
31
- import type { RoutingResolver } from './routing-resolver.ts';
32
-
33
- /**
34
- * Fields the bridge consults on an inbound item. `provider` maps to the routing
35
- * `surfaceKind`; an optional `routeId` (e.g. a Slack channel id or email
36
- * mailbox tag) enables exact (surfaceKind+routeId) matches. Additional inbound
37
- * fields are ignored for routing purposes.
38
- */
39
- export interface RouteResolverInput {
40
- readonly provider?: unknown;
41
- readonly routeId?: unknown;
42
- readonly [key: string]: unknown;
43
- }
44
-
45
- /**
46
- * Best-effort seam the inbox provider adapters invoke per inbound item. Returns
47
- * the resolved profile-route binding id, or `undefined` when nothing matches.
48
- */
49
- export type RouteResolver = (input: RouteResolverInput) => string | undefined;
50
-
51
- /**
52
- * Build a {@link RouteResolver} backed by the routing surface's
53
- * {@link RoutingResolver}. Maps `provider -> surfaceKind` and forwards an
54
- * optional `routeId` refinement, then applies the canonical
55
- * exact > surface-only > wildcard resolution order via `getProfileForChannel`.
56
- * Returns the resolved profileId (the daemon route binding) or `undefined` when
57
- * nothing matches.
58
- */
59
- export function createInboxRouteResolver(resolver: RoutingResolver): RouteResolver {
60
- return (input: RouteResolverInput): string | undefined => {
61
- const surfaceKind = typeof input.provider === 'string' ? input.provider : '';
62
- if (surfaceKind.length === 0) return undefined;
63
- const routeId = typeof input.routeId === 'string' && input.routeId.length > 0
64
- ? input.routeId
65
- : undefined;
66
- // getProfileForChannel applies exact (surfaceKind+routeId) > surface-only >
67
- // wildcard ('any') and returns null when no assignment matches.
68
- const profileId = resolver.getProfileForChannel(surfaceKind, routeId);
69
- return profileId ?? undefined;
70
- };
71
- }