@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
@@ -0,0 +1,352 @@
1
+ /**
2
+ * hosted-session-feed.ts — what this terminal knows about the daemon-hosted
3
+ * session it is attached to.
4
+ *
5
+ * One place holds it because two surfaces read it: the `/hosted` command family
6
+ * (which prints status and drives the verbs) and the Hosted Session panel
7
+ * (which renders the conversation). The same shared-feed shape
8
+ * notifications-feed.ts already uses in this repo — a module-level instance a
9
+ * command writes and a panel subscribes to — rather than threading a service
10
+ * through the command context and the panel deps for one feature.
11
+ *
12
+ * ── What is a fact here, and what is a rendering ──────────────────────────
13
+ *
14
+ * The RECORD is the daemon's, verbatim: status, attached clients, turn count,
15
+ * and `effectiveDetachPolicy` — what leaving would do right now. This feed
16
+ * never recomputes those; it stores the last record a verb or a lifecycle event
17
+ * handed it.
18
+ *
19
+ * The ROWS are this terminal's rendering of the transcript: the history
20
+ * `attach` backfilled, plus what the live `turn` and `tools` frames have said
21
+ * since. A row that is still being streamed is marked `streaming` so the panel
22
+ * can show it growing rather than waiting for the turn to end — the same thing
23
+ * a local turn does.
24
+ *
25
+ * ── Bounded, because it is a live buffer ──────────────────────────────────
26
+ *
27
+ * Rows are capped and the oldest are dropped with an honest note saying how
28
+ * many, rather than growing without limit for a session that runs for days. The
29
+ * daemon keeps the authoritative transcript; a reattach backfills it again.
30
+ */
31
+ import type {
32
+ HostedSessionHistoryMessage,
33
+ HostedSessionRecord,
34
+ } from '@pellux/goodvibes-sdk/platform/hosted-sessions';
35
+ import type { HostedSessionStreamEvent } from '../runtime/client/hosted-session-stream.ts';
36
+
37
+ /** How many transcript rows are kept before the oldest are dropped. */
38
+ export const MAX_HOSTED_ROWS = 400;
39
+
40
+ export type HostedRowKind = 'user' | 'assistant' | 'system' | 'tool' | 'error';
41
+
42
+ /** One rendered line-group of the hosted conversation. */
43
+ export interface HostedSessionRow {
44
+ readonly kind: HostedRowKind;
45
+ readonly text: string;
46
+ readonly at: number;
47
+ /** True while this row is still being appended to by a live stream. */
48
+ readonly streaming: boolean;
49
+ /** Set for tool rows: the call this row is about, so a cancel can name it. */
50
+ readonly callId?: string | undefined;
51
+ }
52
+
53
+ /** A tool call the stream says is running right now. */
54
+ export interface HostedRunningToolCall {
55
+ readonly callId: string;
56
+ readonly tool: string;
57
+ readonly startedAt: number;
58
+ }
59
+
60
+ /** Everything the panel renders and the command reports. */
61
+ export interface HostedSessionFeedState {
62
+ readonly record: HostedSessionRecord | null;
63
+ readonly rows: readonly HostedSessionRow[];
64
+ readonly runningToolCalls: readonly HostedRunningToolCall[];
65
+ /** True when a live event stream is open for this session. */
66
+ readonly streaming: boolean;
67
+ /** Why there is no live stream, when there is not one. Never a guess. */
68
+ readonly streamNote: string | null;
69
+ /** How many rows were dropped by the bound, for an honest header. */
70
+ readonly droppedRows: number;
71
+ }
72
+
73
+ const EMPTY_STATE: HostedSessionFeedState = {
74
+ record: null,
75
+ rows: [],
76
+ runningToolCalls: [],
77
+ streaming: false,
78
+ streamNote: null,
79
+ droppedRows: 0,
80
+ };
81
+
82
+ function historyRow(message: HostedSessionHistoryMessage): HostedSessionRow {
83
+ const kind: HostedRowKind = message.role === 'assistant'
84
+ ? 'assistant'
85
+ : message.role === 'user' ? 'user' : message.role === 'tool' ? 'tool' : 'system';
86
+ return { kind, text: message.content, at: message.at ?? 0, streaming: false };
87
+ }
88
+
89
+ function readString(payload: Record<string, unknown>, key: string): string {
90
+ const value = payload[key];
91
+ return typeof value === 'string' ? value : '';
92
+ }
93
+
94
+ /**
95
+ * The attached hosted session, as this terminal sees it.
96
+ *
97
+ * Deliberately a plain observable object rather than a store domain: nothing
98
+ * about a hosted session participates in the local conversation's state
99
+ * machine, and putting it there would make the local reducers answer for a
100
+ * conversation running in another process.
101
+ */
102
+ export class HostedSessionFeed {
103
+ private state: HostedSessionFeedState = EMPTY_STATE;
104
+ private readonly listeners = new Set<() => void>();
105
+ /** The assistant row currently being streamed, by index into `rows`. */
106
+ private streamingRowIndex: number | null = null;
107
+ /**
108
+ * How to close the live subscription feeding this session, when one is open.
109
+ *
110
+ * Held here rather than in whichever module opened it because two unrelated
111
+ * callers have to be able to close it: the `/hosted detach` command, and the
112
+ * app's own exit path, which must leave the session cleanly before the
113
+ * process goes away.
114
+ */
115
+ private streamCloser: (() => void) | null = null;
116
+
117
+ getState(): HostedSessionFeedState {
118
+ return this.state;
119
+ }
120
+
121
+ subscribe(listener: () => void): () => void {
122
+ this.listeners.add(listener);
123
+ return () => { this.listeners.delete(listener); };
124
+ }
125
+
126
+ /** True when this terminal is attached to a hosted session that has not ended. */
127
+ isAttached(): boolean {
128
+ return this.state.record !== null && this.state.record.status !== 'terminated';
129
+ }
130
+
131
+ /** Start rendering a session: the record the verb returned and its backfilled history. */
132
+ attach(record: HostedSessionRecord, history: readonly HostedSessionHistoryMessage[]): void {
133
+ this.streamingRowIndex = null;
134
+ this.state = {
135
+ record,
136
+ rows: history.map(historyRow).slice(-MAX_HOSTED_ROWS),
137
+ runningToolCalls: [],
138
+ streaming: false,
139
+ streamNote: null,
140
+ droppedRows: Math.max(0, history.length - MAX_HOSTED_ROWS),
141
+ };
142
+ this.emit();
143
+ }
144
+
145
+ /** Replace the record — every verb answer and every lifecycle notice lands here. */
146
+ setRecord(record: HostedSessionRecord): void {
147
+ if (this.state.record && this.state.record.id !== record.id) return;
148
+ this.state = { ...this.state, record };
149
+ this.emit();
150
+ }
151
+
152
+ /** Say whether a live stream is open, and why not when it is not. */
153
+ setStreaming(streaming: boolean, note: string | null = null): void {
154
+ this.state = { ...this.state, streaming, streamNote: note };
155
+ this.emit();
156
+ }
157
+
158
+ /** Hand over the live subscription so any owner of this feed can close it. */
159
+ bindStream(close: (() => void) | null): void {
160
+ this.streamCloser = close;
161
+ }
162
+
163
+ /** Close the live subscription, if one is open. Idempotent. */
164
+ closeStream(): void {
165
+ const close = this.streamCloser;
166
+ this.streamCloser = null;
167
+ close?.();
168
+ }
169
+
170
+ /** Append a note of this terminal's own — a detach, a refusal, a stream drop. */
171
+ note(text: string, kind: HostedRowKind = 'system'): void {
172
+ this.appendRow({ kind, text, at: Date.now(), streaming: false });
173
+ }
174
+
175
+ /** Forget the session entirely (detached, killed, or replaced). */
176
+ clear(): void {
177
+ this.closeStream();
178
+ this.streamingRowIndex = null;
179
+ this.state = EMPTY_STATE;
180
+ this.emit();
181
+ }
182
+
183
+ /**
184
+ * Fold one live frame into the transcript.
185
+ *
186
+ * Frames for another session never reach here (the stream filters on the id),
187
+ * but the guard stays because a feed that rendered another conversation's
188
+ * tokens would be indistinguishable from this one working.
189
+ */
190
+ apply(event: HostedSessionStreamEvent): void {
191
+ if (!this.state.record || event.sessionId !== this.state.record.id) return;
192
+ if (event.domain === 'turn') { this.applyTurnEvent(event); return; }
193
+ this.applyToolEvent(event);
194
+ }
195
+
196
+ private applyTurnEvent(event: HostedSessionStreamEvent): void {
197
+ switch (event.type) {
198
+ case 'TURN_SUBMITTED': {
199
+ const prompt = readString(event.payload, 'prompt');
200
+ if (prompt) this.appendRow({ kind: 'user', text: prompt, at: event.at, streaming: false });
201
+ return;
202
+ }
203
+ case 'STREAM_DELTA': {
204
+ // `accumulated` is the whole response so far, which is exactly what a
205
+ // row wants: a client that joined mid-turn renders the full text rather
206
+ // than the tail it happened to catch.
207
+ const accumulated = readString(event.payload, 'accumulated')
208
+ || readString(event.payload, 'content');
209
+ if (!accumulated) return;
210
+ this.updateStreamingRow(accumulated, event.at);
211
+ return;
212
+ }
213
+ case 'TURN_COMPLETED': {
214
+ const response = readString(event.payload, 'response');
215
+ if (response) this.updateStreamingRow(response, event.at);
216
+ this.settleStreamingRow();
217
+ return;
218
+ }
219
+ case 'TURN_ERROR': {
220
+ this.settleStreamingRow();
221
+ this.appendRow({
222
+ kind: 'error',
223
+ text: readString(event.payload, 'error') || 'the hosted turn ended with an error',
224
+ at: event.at,
225
+ streaming: false,
226
+ });
227
+ return;
228
+ }
229
+ case 'TURN_CANCEL': {
230
+ this.settleStreamingRow();
231
+ const reason = readString(event.payload, 'reason');
232
+ this.appendRow({
233
+ kind: 'system',
234
+ text: reason ? `turn cancelled — ${reason}` : 'turn cancelled',
235
+ at: event.at,
236
+ streaming: false,
237
+ });
238
+ return;
239
+ }
240
+ default:
241
+ return;
242
+ }
243
+ }
244
+
245
+ private applyToolEvent(event: HostedSessionStreamEvent): void {
246
+ const callId = readString(event.payload, 'callId');
247
+ const tool = readString(event.payload, 'tool');
248
+ if (!callId || !tool) return;
249
+ switch (event.type) {
250
+ case 'TOOL_EXECUTING': {
251
+ this.settleStreamingRow();
252
+ this.state = {
253
+ ...this.state,
254
+ runningToolCalls: [
255
+ ...this.state.runningToolCalls.filter((call) => call.callId !== callId),
256
+ { callId, tool, startedAt: event.at },
257
+ ],
258
+ };
259
+ this.appendRow({ kind: 'tool', text: `${tool} — running`, at: event.at, streaming: true, callId });
260
+ return;
261
+ }
262
+ case 'TOOL_SUCCEEDED':
263
+ case 'TOOL_FAILED':
264
+ case 'TOOL_CANCELLED': {
265
+ const outcome = event.type === 'TOOL_SUCCEEDED'
266
+ ? 'done'
267
+ : event.type === 'TOOL_FAILED'
268
+ ? `failed — ${readString(event.payload, 'error') || 'no reason reported'}`
269
+ : `cancelled${readString(event.payload, 'reason') ? ` — ${readString(event.payload, 'reason')}` : ''}`;
270
+ this.state = {
271
+ ...this.state,
272
+ runningToolCalls: this.state.runningToolCalls.filter((call) => call.callId !== callId),
273
+ rows: this.state.rows.map((row) => (
274
+ row.callId === callId && row.streaming
275
+ ? { ...row, text: `${tool} — ${outcome}`, streaming: false }
276
+ : row
277
+ )),
278
+ };
279
+ this.emit();
280
+ return;
281
+ }
282
+ default:
283
+ return;
284
+ }
285
+ }
286
+
287
+ /** Fold a hosted lifecycle transition in: the record, plus a line when it matters. */
288
+ applyLifecycle(update: { readonly event: string; readonly session: HostedSessionRecord; readonly detail?: string | undefined }): void {
289
+ this.setRecord(update.session);
290
+ if (update.event === 'hosted-session-terminated') {
291
+ this.settleStreamingRow();
292
+ const reason = update.session.terminatedReason ?? 'no reason recorded';
293
+ this.note(`this hosted session ended — ${reason}${update.detail ? ` (${update.detail})` : ''}`);
294
+ }
295
+ }
296
+
297
+ private updateStreamingRow(text: string, at: number): void {
298
+ if (this.streamingRowIndex === null) {
299
+ this.appendRow({ kind: 'assistant', text, at, streaming: true });
300
+ this.streamingRowIndex = this.state.rows.length - 1;
301
+ return;
302
+ }
303
+ const rows = [...this.state.rows];
304
+ const existing = rows[this.streamingRowIndex];
305
+ if (!existing) { this.streamingRowIndex = null; return; }
306
+ rows[this.streamingRowIndex] = { ...existing, text, at };
307
+ this.state = { ...this.state, rows };
308
+ this.emit();
309
+ }
310
+
311
+ private settleStreamingRow(): void {
312
+ if (this.streamingRowIndex === null) return;
313
+ const rows = [...this.state.rows];
314
+ const existing = rows[this.streamingRowIndex];
315
+ if (existing) rows[this.streamingRowIndex] = { ...existing, streaming: false };
316
+ this.streamingRowIndex = null;
317
+ this.state = { ...this.state, rows };
318
+ this.emit();
319
+ }
320
+
321
+ private appendRow(row: HostedSessionRow): void {
322
+ const rows = [...this.state.rows, row];
323
+ let dropped = this.state.droppedRows;
324
+ while (rows.length > MAX_HOSTED_ROWS) {
325
+ rows.shift();
326
+ dropped += 1;
327
+ if (this.streamingRowIndex !== null) this.streamingRowIndex -= 1;
328
+ }
329
+ if (this.streamingRowIndex !== null && this.streamingRowIndex < 0) this.streamingRowIndex = null;
330
+ this.state = { ...this.state, rows, droppedRows: dropped };
331
+ this.emit();
332
+ }
333
+
334
+ private emit(): void {
335
+ // Snapshot before iterating: a listener that unsubscribes during dispatch
336
+ // must not make the next listener be skipped.
337
+ for (const listener of [...this.listeners]) listener();
338
+ }
339
+ }
340
+
341
+ let sharedFeed: HostedSessionFeed | null = null;
342
+
343
+ /** The one feed the `/hosted` command writes and the Hosted Session panel reads. */
344
+ export function getSharedHostedSessionFeed(): HostedSessionFeed {
345
+ sharedFeed ??= new HostedSessionFeed();
346
+ return sharedFeed;
347
+ }
348
+
349
+ /** Tests build their own feed; this resets the shared one between them. */
350
+ export function resetSharedHostedSessionFeed(): void {
351
+ sharedFeed = null;
352
+ }
@@ -0,0 +1,221 @@
1
+ /**
2
+ * HostedSessionPanel — the conversation the daemon is running, rendered here.
3
+ *
4
+ * A hosted session's turn arrives on the same `turn` and `tools` event domains
5
+ * a local turn does, so what this panel shows is the same thing the transcript
6
+ * shows for a local conversation: what was said, what tool is running, and
7
+ * whether text is still streaming. The difference is where the loop lives, and
8
+ * the header says so plainly — including `effectiveDetachPolicy`, so a person
9
+ * about to quit knows whether that ends the work.
10
+ *
11
+ * The panel renders; it decides nothing. Every fact in the header is a field of
12
+ * the daemon's own record (hosted-session-feed.ts), and the rows are the
13
+ * backfilled history plus the live frames. When there is no stream open the
14
+ * panel says why rather than showing a still conversation that looks finished.
15
+ */
16
+ import type { Line } from '@pellux/goodvibes-sdk/platform/types';
17
+ import { BasePanel } from './base-panel.ts';
18
+ import {
19
+ buildEmptyState,
20
+ buildKeyboardHints,
21
+ buildPanelWorkspace,
22
+ buildStyledPanelLine,
23
+ DEFAULT_PANEL_PALETTE,
24
+ resolveScrollablePanelSection,
25
+ } from './polish.ts';
26
+ import { wrapText } from '../utils/terminal-width.ts';
27
+ import {
28
+ getSharedHostedSessionFeed,
29
+ type HostedSessionFeed,
30
+ type HostedSessionFeedState,
31
+ type HostedSessionRow,
32
+ } from './hosted-session-feed.ts';
33
+
34
+ const C = DEFAULT_PANEL_PALETTE;
35
+
36
+ const INTRO = 'A conversation whose loop runs inside the daemon. Steer it with /hosted say, leave it with /hosted detach — the header says what leaving would do.';
37
+
38
+ function rowColor(kind: HostedSessionRow['kind']): string {
39
+ switch (kind) {
40
+ case 'user': return C.accent;
41
+ case 'assistant': return C.value;
42
+ case 'tool': return C.info;
43
+ case 'error': return C.bad;
44
+ default: return C.dim;
45
+ }
46
+ }
47
+
48
+ function rowPrefix(kind: HostedSessionRow['kind']): string {
49
+ switch (kind) {
50
+ case 'user': return 'you';
51
+ case 'assistant': return 'hosted';
52
+ case 'tool': return 'tool';
53
+ case 'error': return 'error';
54
+ default: return '·';
55
+ }
56
+ }
57
+
58
+ /** Every line one transcript row needs. Text is wrapped in full, never clipped. */
59
+ export function renderHostedRow(row: HostedSessionRow, width: number): Line[] {
60
+ const lines: Line[] = [];
61
+ const fg = rowColor(row.kind);
62
+ const marker = row.streaming ? ' …' : '';
63
+ const body = `${rowPrefix(row.kind)}: ${row.text}${marker}`;
64
+ const wrapWidth = Math.max(1, width - 1);
65
+ for (const [index, wrapped] of wrapText(body, wrapWidth).entries()) {
66
+ lines.push(buildStyledPanelLine(width, [{ text: ` ${wrapped}`, fg, bold: index === 0 && row.kind === 'user' }]));
67
+ }
68
+ return lines;
69
+ }
70
+
71
+ /**
72
+ * The header block: who this session is, what it is doing, and what leaving it
73
+ * would do. Every value comes from the record; nothing is derived locally.
74
+ */
75
+ export function buildHostedHeaderLines(state: HostedSessionFeedState, width: number): Line[] {
76
+ const record = state.record;
77
+ if (!record) return [];
78
+ const policyText = record.effectiveDetachPolicy === 'survive'
79
+ ? 'detaching keeps it running (survive)'
80
+ : 'detaching ends it (kill)';
81
+ const policySource = record.detachPolicy === null ? 'from the setting' : 'per-session override';
82
+ const rows: { text: string; fg: string }[] = [
83
+ { text: `${record.title.trim() || record.id} — ${record.status}`, fg: C.header },
84
+ { text: `id ${record.id}`, fg: C.dim },
85
+ { text: `workspace ${record.workspaceRoot}`, fg: C.dim },
86
+ {
87
+ text: `${policyText}, ${policySource}`,
88
+ fg: record.effectiveDetachPolicy === 'survive' ? C.good : C.warn,
89
+ },
90
+ {
91
+ text: `${record.turnCount} turn(s), ${record.messageCount} message(s); attached: ${record.attachedClients.length > 0 ? record.attachedClients.join(', ') : 'nobody'}`,
92
+ fg: C.label,
93
+ },
94
+ ];
95
+ if (record.status === 'terminated') {
96
+ rows.push({ text: `ended — ${record.terminatedReason ?? 'no reason recorded'}`, fg: C.bad });
97
+ }
98
+ if (record.restoredFromDisk) {
99
+ rows.push({ text: 'restored from disk after a daemon restart', fg: C.warn });
100
+ }
101
+ rows.push(state.streaming
102
+ ? { text: 'live event stream open', fg: C.good }
103
+ : { text: `no live stream — ${state.streamNote ?? 'not subscribed'}`, fg: C.warn });
104
+ if (state.runningToolCalls.length > 0) {
105
+ rows.push({
106
+ text: `running: ${state.runningToolCalls.map((call) => `${call.tool} (${call.callId})`).join(', ')}`,
107
+ fg: C.info,
108
+ });
109
+ }
110
+ if (state.droppedRows > 0) {
111
+ rows.push({ text: `${state.droppedRows} earlier row(s) dropped by this panel's buffer — reattach to backfill`, fg: C.dim });
112
+ }
113
+ const lines: Line[] = [];
114
+ for (const row of rows) {
115
+ for (const wrapped of wrapText(row.text, Math.max(1, width - 1))) {
116
+ lines.push(buildStyledPanelLine(width, [{ text: ` ${wrapped}`, fg: row.fg }]));
117
+ }
118
+ }
119
+ return lines;
120
+ }
121
+
122
+ export class HostedSessionPanel extends BasePanel {
123
+ private readonly unsubscribe: () => void;
124
+ private scrollOffset = 0;
125
+ /** Off until the user scrolls: a live conversation should follow its own tail. */
126
+ private pinnedToTail = true;
127
+
128
+ constructor(private readonly feed: HostedSessionFeed = getSharedHostedSessionFeed()) {
129
+ // '◈' verified free against the registered builtin panel icons.
130
+ super('hosted', 'Hosted Session', '◈', 'session');
131
+ this.unsubscribe = this.feed.subscribe(() => {
132
+ if (this.pinnedToTail) this.scrollOffset = Number.MAX_SAFE_INTEGER;
133
+ this.markDirty();
134
+ });
135
+ }
136
+
137
+ override onDestroy(): void {
138
+ this.unsubscribe();
139
+ super.onDestroy();
140
+ }
141
+
142
+ handleInput(key: string): boolean {
143
+ switch (key) {
144
+ case 'up': return this.scroll(-1);
145
+ case 'down': return this.scroll(1);
146
+ case 'pageup': return this.scroll(-10);
147
+ case 'pagedown': return this.scroll(10);
148
+ case 'end': {
149
+ this.pinnedToTail = true;
150
+ this.scrollOffset = Number.MAX_SAFE_INTEGER;
151
+ this.markDirty();
152
+ return true;
153
+ }
154
+ default: return false;
155
+ }
156
+ }
157
+
158
+ private scroll(delta: number): boolean {
159
+ const rows = this.feed.getState().rows;
160
+ if (rows.length === 0) return false;
161
+ // Scrolling up unpins; reaching the bottom re-pins, so a reader who catches
162
+ // up starts following again without a second key.
163
+ this.pinnedToTail = false;
164
+ this.scrollOffset = Math.max(0, this.scrollOffset + delta);
165
+ this.markDirty();
166
+ return true;
167
+ }
168
+
169
+ render(width: number, height: number): Line[] {
170
+ if (width <= 0 || height <= 0) return [];
171
+ const state = this.feed.getState();
172
+ const hintRow = buildKeyboardHints(width, [
173
+ { keys: 'Up/Down', label: 'scroll' },
174
+ { keys: 'PgUp/PgDn', label: 'page' },
175
+ { keys: 'End', label: 'follow' },
176
+ ], DEFAULT_PANEL_PALETTE);
177
+
178
+ if (!state.record) {
179
+ return buildPanelWorkspace(width, height, {
180
+ title: ' Hosted Session',
181
+ intro: INTRO,
182
+ sections: [{
183
+ lines: buildEmptyState(
184
+ width,
185
+ ' Not attached to a hosted session',
186
+ 'A hosted session runs inside the daemon instead of this terminal, so it can outlive the window it was started from. Start one with /hosted new, or join one that already exists with /hosted list and /hosted attach <id>. Local sessions are unchanged and remain the default.',
187
+ [],
188
+ DEFAULT_PANEL_PALETTE,
189
+ ),
190
+ }],
191
+ footerLines: [hintRow],
192
+ palette: DEFAULT_PANEL_PALETTE,
193
+ });
194
+ }
195
+
196
+ const headerSection = { lines: buildHostedHeaderLines(state, width - 2) };
197
+ const scrollableLines = state.rows.flatMap((row) => renderHostedRow(row, width - 2));
198
+ const section = resolveScrollablePanelSection(width, height, {
199
+ intro: INTRO,
200
+ footerLines: [hintRow],
201
+ palette: DEFAULT_PANEL_PALETTE,
202
+ beforeSections: [headerSection],
203
+ section: {
204
+ title: `Transcript (${state.rows.length})`,
205
+ scrollableLines,
206
+ scrollOffset: this.scrollOffset,
207
+ minRows: 4,
208
+ appendWindowSummary: scrollableLines.length > 0 ? { dimColor: DEFAULT_PANEL_PALETTE.dim } : undefined,
209
+ },
210
+ });
211
+ this.scrollOffset = section.scrollOffset;
212
+
213
+ return buildPanelWorkspace(width, height, {
214
+ title: ' Hosted Session',
215
+ intro: INTRO,
216
+ sections: [headerSection, section.section],
217
+ footerLines: [hintRow],
218
+ palette: DEFAULT_PANEL_PALETTE,
219
+ });
220
+ }
221
+ }
@@ -1,5 +1,5 @@
1
- import type { Line } from '../types/grid.ts';
2
- import { createEmptyLine } from '../types/grid.ts';
1
+ import type { Line } from '@pellux/goodvibes-sdk/platform/types';
2
+ import { createEmptyLine } from '@pellux/goodvibes-sdk/platform/types';
3
3
  import { fitDisplay, truncateDisplay } from '../utils/terminal-width.ts';
4
4
  import { ScrollableListPanel } from './scrollable-list-panel.ts';
5
5
  import {
@@ -14,7 +14,7 @@ import {
14
14
  type PanelPalette,
15
15
  } from './polish.ts';
16
16
  import type { LocalAuthSnapshot, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
17
- import type { LocalAuthInspectionQuery } from '../runtime/ui-service-queries.ts';
17
+ import type { LocalAuthInspectionQuery } from '@/runtime/index.ts';
18
18
  import type { KeyName } from './types.ts';
19
19
  import { isTextBackspace } from '../input/delete-key-policy.ts';
20
20
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
@@ -7,7 +7,7 @@ import type {
7
7
  ConfigModalView,
8
8
  } from '../../input/config-modal-types.ts';
9
9
  import type { MintedPairingToken, PublicPairingToken } from '@pellux/goodvibes-sdk/platform/pairing';
10
- import { formatDeviceLine, shortTokenId } from '../../core/pairing-devices.ts';
10
+ import { formatDeviceLine, shortTokenId } from '@pellux/goodvibes-sdk/platform/pairing';
11
11
 
12
12
  // ---------------------------------------------------------------------------
13
13
  // Paired Devices — the settings security-domain device/token management surface.
@@ -1,5 +1,5 @@
1
1
  import type { ConfigModalAction, ConfigModalActionContext, ConfigModalRow, ConfigModalSurface, ConfigModalView } from '../../input/config-modal-types.ts';
2
- import type { LocalAuthInspectionQuery } from '../../runtime/ui-service-queries.ts';
2
+ import type { LocalAuthInspectionQuery } from '@/runtime/index.ts';
3
3
  import type { UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
4
4
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
5
5
  import { postureLine, kv } from './modal-surface-helpers.ts';
@@ -7,7 +7,7 @@ import type {
7
7
  ConfigModalView,
8
8
  } from '../../input/config-modal-types.ts';
9
9
  import { describeOriginPosture, generateQrMatrix, renderQrToString, type OriginPosture, type PairingHandoffOfferKind } from '@pellux/goodvibes-sdk/platform/pairing';
10
- import { formatPairingOffers, formatPostureCapabilities, pairingPostureNotice } from '../../core/pairing-offers.ts';
10
+ import { formatPairingOffers, formatPostureCapabilities, pairingPostureNotice } from '@pellux/goodvibes-sdk/platform/pairing';
11
11
 
12
12
  // ---------------------------------------------------------------------------
13
13
  // Device Pairing config-modal surface. Shows the web-app origin, the per-device
@@ -1,5 +1,5 @@
1
1
  import type { ConfigModalActionContext, ConfigModalSurface, ConfigModalView } from '../../input/config-modal-types.ts';
2
- import type { ServiceInspectionQuery, SubscriptionAccessQuery } from '../../runtime/ui-service-queries.ts';
2
+ import type { ServiceInspectionQuery, SubscriptionAccessQuery } from '@/runtime/index.ts';
3
3
  import type { ServiceConfig, ServiceInspection, ServiceConnectionTestResult } from '@pellux/goodvibes-sdk/platform/config';
4
4
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
5
5
  import { toneStyle, statusGlyph, pad, postureLine, kv, type Tone } from './modal-surface-helpers.ts';
@@ -1,6 +1,6 @@
1
1
  import type { ConfigModalAction, ConfigModalActionContext, ConfigModalRow, ConfigModalSurface, ConfigModalView } from '../../input/config-modal-types.ts';
2
2
  import { getSettingsControlPlaneSnapshot } from '@/runtime/index.ts';
3
- import type { ConfigManager } from '../../config/index.ts';
3
+ import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
4
4
  import { toneStyle, pad, postureLine, kv, type Tone } from './modal-surface-helpers.ts';
5
5
 
6
6
  type Snapshot = ReturnType<typeof getSettingsControlPlaneSnapshot>;
@@ -1,5 +1,5 @@
1
1
  import type { ConfigModalActionContext, ConfigModalSurface, ConfigModalView } from '../../input/config-modal-types.ts';
2
- import type { ServiceInspectionQuery, SubscriptionAccessQuery } from '../../runtime/ui-service-queries.ts';
2
+ import type { ServiceInspectionQuery, SubscriptionAccessQuery } from '@/runtime/index.ts';
3
3
  import type { ProviderSubscription, PendingSubscriptionLogin } from '@pellux/goodvibes-sdk/platform/config';
4
4
  import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
5
5
  import { formatElapsed } from '../../utils/format-elapsed.ts';
@@ -4,7 +4,7 @@ import type {
4
4
  ConfigModalSurface,
5
5
  ConfigModalView,
6
6
  } from '../../input/config-modal-types.ts';
7
- import type { WorkPlanItemStatus } from '../../work-plans/work-plan-store.ts';
7
+ import type { WorkPlanItemStatus } from '@pellux/goodvibes-sdk/platform/workflow';
8
8
 
9
9
  // ---------------------------------------------------------------------------
10
10
  // Work Plan → config-modal surface (group-B port). Lists the active
@@ -8,7 +8,7 @@
8
8
  * the conversation. Descriptive text (titles, bodies, reason descriptions)
9
9
  * is always wrapped in full — never clipped to a column width.
10
10
  */
11
- import type { Line } from '../types/grid.ts';
11
+ import type { Line } from '@pellux/goodvibes-sdk/platform/types';
12
12
  import type { RoutingDecision } from '@/runtime/index.ts';
13
13
  import { BasePanel } from './base-panel.ts';
14
14
  import {
@@ -12,7 +12,7 @@
12
12
  // way don't each hand-roll the same field + dispatch + render wiring.
13
13
  // ---------------------------------------------------------------------------
14
14
 
15
- import type { Line } from '../types/grid.ts';
15
+ import type { Line } from '@pellux/goodvibes-sdk/platform/types';
16
16
  import { type ConfirmState, handleConfirmInput, renderConfirmLines } from './confirm-state.ts';
17
17
 
18
18
  export interface PanelConfirmOverlayHandlers {