@pellux/goodvibes-tui 1.27.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (405) hide show
  1. package/CHANGELOG.md +127 -2
  2. package/README.md +7 -9
  3. package/bin/goodvibes +2 -2
  4. package/bin/launcher-support.js +8 -4
  5. package/docs/README.md +11 -2
  6. package/docs/foundation-artifacts/operator-contract.json +6403 -2347
  7. package/package.json +14 -25
  8. package/scripts/postinstall.js +35 -35
  9. package/src/audio/spoken-turn-model-routing.ts +1 -1
  10. package/src/cli/bundle-command.ts +5 -5
  11. package/src/cli/completions/generate.ts +1 -1
  12. package/src/cli/doctor.ts +3 -3
  13. package/src/cli/entrypoint.ts +12 -7
  14. package/src/cli/help.ts +4 -5
  15. package/src/cli/hooks-command.ts +1 -1
  16. package/src/cli/index.ts +1 -4
  17. package/src/cli/launch-auto-update.ts +59 -7
  18. package/src/cli/management-commands.ts +6 -6
  19. package/src/cli/management-utils.ts +5 -5
  20. package/src/cli/management.ts +7 -7
  21. package/src/cli/network-posture.ts +1 -1
  22. package/src/cli/package-verification.ts +7 -6
  23. package/src/cli/plugin-bundles-command.ts +1 -1
  24. package/src/cli/plugin-command.ts +2 -2
  25. package/src/cli/service-command.ts +2 -2
  26. package/src/cli/service-posture.ts +4 -4
  27. package/src/cli/status.ts +9 -8
  28. package/src/cli/surface-command.ts +4 -4
  29. package/src/cli/tui-startup.ts +3 -3
  30. package/src/cli-flags.ts +3 -3
  31. package/src/config/goodvibes-home-audit.ts +0 -2
  32. package/src/config/secret-config.ts +37 -5
  33. package/src/config/tui-extension-settings.ts +1 -1
  34. package/src/core/approval-alert.ts +2 -2
  35. package/src/core/budget-breach-notifier.ts +3 -3
  36. package/src/core/conversation-compaction-render.ts +1 -1
  37. package/src/core/conversation-line-cache.ts +1 -1
  38. package/src/core/conversation-render-context.ts +1 -1
  39. package/src/core/conversation-rendering.ts +2 -2
  40. package/src/core/conversation.ts +10 -10
  41. package/src/core/long-task-notifier.ts +2 -2
  42. package/src/core/memory-diagnostics-gateway.ts +1 -1
  43. package/src/core/scriptable-statusline.ts +1 -1
  44. package/src/core/session-auto-titler.ts +1 -1
  45. package/src/core/session-resume-core.ts +2 -2
  46. package/src/core/stream-event-wiring.ts +24 -44
  47. package/src/core/terminal-notifier.ts +3 -3
  48. package/src/core/turn-cancellation.ts +1 -1
  49. package/src/core/turn-event-wiring.ts +5 -5
  50. package/src/input/command-registry.ts +6 -6
  51. package/src/input/commands/channel-pairing.ts +1 -1
  52. package/src/input/commands/cluster-runtime.ts +1 -1
  53. package/src/input/commands/codebase-runtime.ts +1 -1
  54. package/src/input/commands/devices-runtime.ts +1 -1
  55. package/src/input/commands/hosted-runtime.ts +330 -0
  56. package/src/input/commands/local-setup-review.ts +1 -1
  57. package/src/input/commands/local-setup-transfer.ts +2 -2
  58. package/src/input/commands/local-setup.ts +3 -3
  59. package/src/input/commands/managed-runtime.ts +2 -2
  60. package/src/input/commands/operator-rpc.ts +24 -110
  61. package/src/input/commands/payment-card-intake.ts +1 -1
  62. package/src/input/commands/permissions-provenance.ts +2 -2
  63. package/src/input/commands/plugin-runtime.ts +1 -1
  64. package/src/input/commands/provider.ts +1 -1
  65. package/src/input/commands/relay-runtime.ts +18 -9
  66. package/src/input/commands/rewind-runtime.ts +1 -1
  67. package/src/input/commands/runtime-services.ts +1 -1
  68. package/src/input/commands/services-runtime.ts +1 -1
  69. package/src/input/commands/session-workflow.ts +1 -1
  70. package/src/input/commands/settings-sync-runtime.ts +2 -2
  71. package/src/input/commands/share-runtime.ts +1 -1
  72. package/src/input/commands/tasks-runtime.ts +145 -55
  73. package/src/input/commands/update-runtime.ts +31 -28
  74. package/src/input/commands/work-plan-runtime.ts +2 -2
  75. package/src/input/commands/workstream-attempts.ts +1 -1
  76. package/src/input/commands/workstream-runtime.ts +2 -2
  77. package/src/input/commands.ts +2 -0
  78. package/src/input/feature-unit-layout.ts +1 -1
  79. package/src/input/feed-context-factory.ts +3 -3
  80. package/src/input/handler-content-actions.ts +2 -2
  81. package/src/input/handler-feed-routes.ts +1 -1
  82. package/src/input/handler-feed.ts +3 -3
  83. package/src/input/handler-modal-token-routes.ts +1 -1
  84. package/src/input/handler-onboarding-daemon-adopt.ts +3 -2
  85. package/src/input/handler-onboarding.ts +1 -1
  86. package/src/input/handler-types.ts +2 -2
  87. package/src/input/handler-ui-state.ts +1 -1
  88. package/src/input/handler.ts +4 -4
  89. package/src/input/input-history.ts +1 -1
  90. package/src/input/onboarding/onboarding-feature-units.ts +2 -2
  91. package/src/input/onboarding/onboarding-runtime-status.ts +15 -1
  92. package/src/input/onboarding/onboarding-wizard-apply.ts +17 -8
  93. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +5 -3
  94. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +1 -1
  95. package/src/input/onboarding/onboarding-wizard-types.ts +1 -1
  96. package/src/input/payments-config.ts +6 -6
  97. package/src/input/search.ts +1 -1
  98. package/src/input/session-picker-modal.ts +46 -0
  99. package/src/input/settings-modal-activation.ts +1 -1
  100. package/src/input/settings-modal-behavior.ts +4 -4
  101. package/src/input/settings-modal-commit.ts +11 -0
  102. package/src/input/settings-modal-data.ts +9 -122
  103. package/src/input/settings-modal-mutations.ts +33 -0
  104. package/src/input/settings-modal-secrets.ts +34 -0
  105. package/src/input/settings-modal-subscriptions.ts +1 -1
  106. package/src/input/settings-modal-types.ts +15 -1
  107. package/src/input/settings-modal.ts +28 -3
  108. package/src/input/worktree-setup-config.ts +1 -1
  109. package/src/main.ts +11 -9
  110. package/src/panels/agent-inspector-shared.ts +2 -2
  111. package/src/panels/base-panel.ts +2 -2
  112. package/src/panels/builtin/operations.ts +6 -8
  113. package/src/panels/builtin/session.ts +17 -0
  114. package/src/panels/builtin/shared.ts +5 -5
  115. package/src/panels/builtin-modals.ts +3 -3
  116. package/src/panels/confirm-state.ts +1 -1
  117. package/src/panels/cost-tracker-panel.ts +4 -4
  118. package/src/panels/diff-panel.ts +2 -2
  119. package/src/panels/diff-review-panel.ts +2 -2
  120. package/src/panels/expandable-list-panel.ts +2 -2
  121. package/src/panels/fleet-acts.ts +1 -1
  122. package/src/panels/fleet-observed-render.ts +1 -1
  123. package/src/panels/fleet-panel-format.ts +1 -1
  124. package/src/panels/fleet-panel.ts +1 -1
  125. package/src/panels/fleet-spawn.ts +1 -1
  126. package/src/panels/fleet-steer.ts +1 -1
  127. package/src/panels/fleet-transcript.ts +1 -1
  128. package/src/panels/git-panel.ts +1 -1
  129. package/src/panels/hosted-session-feed.ts +352 -0
  130. package/src/panels/hosted-session-panel.ts +221 -0
  131. package/src/panels/local-auth-panel.ts +3 -3
  132. package/src/panels/modals/devices-modal.ts +1 -1
  133. package/src/panels/modals/local-auth-modal.ts +1 -1
  134. package/src/panels/modals/pairing-modal.ts +1 -1
  135. package/src/panels/modals/services-modal.ts +1 -1
  136. package/src/panels/modals/settings-sync-modal.ts +1 -1
  137. package/src/panels/modals/subscription-modal.ts +1 -1
  138. package/src/panels/modals/work-plan-modal.ts +1 -1
  139. package/src/panels/notifications-panel.ts +1 -1
  140. package/src/panels/panel-confirm-overlay.ts +1 -1
  141. package/src/panels/plugins-panel.ts +2 -2
  142. package/src/panels/polish-core.ts +2 -2
  143. package/src/panels/polish-tables.ts +1 -1
  144. package/src/panels/polish.ts +2 -2
  145. package/src/panels/scrollable-list-panel.ts +3 -3
  146. package/src/panels/skills-panel.ts +3 -3
  147. package/src/panels/token-budget-panel.ts +5 -5
  148. package/src/panels/types.ts +1 -2
  149. package/src/permissions/prompt.ts +1 -1
  150. package/src/renderer/autocomplete-overlay.ts +1 -1
  151. package/src/renderer/block-actions-overlay.ts +1 -1
  152. package/src/renderer/bookmark-modal.ts +1 -1
  153. package/src/renderer/buffer.ts +1 -1
  154. package/src/renderer/code-block.ts +1 -1
  155. package/src/renderer/composer-fragments.ts +1 -1
  156. package/src/renderer/compositor.ts +2 -2
  157. package/src/renderer/config-modal.ts +1 -1
  158. package/src/renderer/context-inspector.ts +1 -1
  159. package/src/renderer/conversation-layout.ts +2 -2
  160. package/src/renderer/conversation-overlays.ts +1 -1
  161. package/src/renderer/conversation-surface.ts +2 -2
  162. package/src/renderer/diff-view.ts +1 -1
  163. package/src/renderer/diff.ts +1 -1
  164. package/src/renderer/file-picker-overlay.ts +1 -1
  165. package/src/renderer/fleet-tab-strip.ts +1 -1
  166. package/src/renderer/fullscreen-primitives.ts +2 -2
  167. package/src/renderer/fullscreen-workspace.ts +1 -1
  168. package/src/renderer/header-line.ts +1 -1
  169. package/src/renderer/help-overlay.ts +1 -1
  170. package/src/renderer/history-search-overlay.ts +2 -2
  171. package/src/renderer/layout.ts +5 -8
  172. package/src/renderer/markdown-inline.ts +1 -1
  173. package/src/renderer/markdown-table.ts +1 -1
  174. package/src/renderer/markdown.ts +1 -1
  175. package/src/renderer/mcp-workspace.ts +1 -1
  176. package/src/renderer/modal-factory.ts +2 -2
  177. package/src/renderer/model-workspace.ts +2 -2
  178. package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
  179. package/src/renderer/overlay-box.ts +1 -1
  180. package/src/renderer/panel-composite.ts +1 -1
  181. package/src/renderer/panel-workspace-bar.ts +1 -1
  182. package/src/renderer/process-indicator.ts +1 -1
  183. package/src/renderer/profile-picker-modal.ts +1 -1
  184. package/src/renderer/search-overlay.ts +2 -2
  185. package/src/renderer/selection-modal-overlay.ts +1 -1
  186. package/src/renderer/session-picker-modal.ts +124 -3
  187. package/src/renderer/settings-modal-helpers.ts +2 -0
  188. package/src/renderer/settings-modal.ts +2 -2
  189. package/src/renderer/shell-surface.ts +2 -2
  190. package/src/renderer/system-message.ts +1 -1
  191. package/src/renderer/tab-strip.ts +1 -1
  192. package/src/renderer/theme-mode-config.ts +21 -33
  193. package/src/renderer/theme.ts +11 -12
  194. package/src/renderer/thinking.ts +1 -1
  195. package/src/renderer/tool-call.ts +2 -2
  196. package/src/renderer/tool-result-expanded-lines.ts +1 -1
  197. package/src/renderer/turn-injection.ts +7 -8
  198. package/src/renderer/ui-factory.ts +3 -3
  199. package/src/runtime/bootstrap-command-context.ts +4 -4
  200. package/src/runtime/bootstrap-command-parts.ts +5 -5
  201. package/src/runtime/bootstrap-core.ts +30 -30
  202. package/src/runtime/bootstrap-shell.ts +4 -4
  203. package/src/runtime/bootstrap.ts +128 -157
  204. package/src/runtime/client/approval-updates.ts +82 -0
  205. package/src/runtime/client/build-floors.ts +167 -0
  206. package/src/runtime/client/daemon-attach-handshake.ts +115 -0
  207. package/src/runtime/client/fleet-union.ts +147 -0
  208. package/src/runtime/client/host-service-status.ts +71 -0
  209. package/src/runtime/client/hosted-exit.ts +86 -0
  210. package/src/runtime/client/hosted-roster.ts +110 -0
  211. package/src/runtime/client/hosted-session-stream.ts +178 -0
  212. package/src/runtime/client/hosted-sessions.ts +187 -0
  213. package/src/runtime/client/operator-endpoint.ts +213 -0
  214. package/src/runtime/client/spine-adoption.ts +99 -0
  215. package/src/runtime/cloudflare-control-plane.ts +1 -1
  216. package/src/runtime/context-accounting-source.ts +1 -1
  217. package/src/runtime/context.ts +2 -2
  218. package/src/runtime/conversation-rewind-port.ts +42 -14
  219. package/src/runtime/daemon-attach-notices.ts +55 -19
  220. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  221. package/src/runtime/disposal-wiring.ts +4 -24
  222. package/src/runtime/index.ts +119 -105
  223. package/src/runtime/install-self-check-startup.ts +2 -2
  224. package/src/runtime/interaction-seams.ts +1 -1
  225. package/src/runtime/knowledge-services.ts +8 -2
  226. package/src/runtime/legacy-daemon-migration.ts +4 -3
  227. package/src/runtime/legacy-daemon-reconcile.ts +3 -2
  228. package/src/runtime/memory-spine-transport.ts +37 -267
  229. package/src/runtime/notification-dispatch.ts +2 -2
  230. package/src/runtime/onboarding/apply.ts +2 -2
  231. package/src/runtime/onboarding/derivation.ts +2 -2
  232. package/src/runtime/onboarding/markers.ts +2 -2
  233. package/src/runtime/onboarding/progress.ts +2 -2
  234. package/src/runtime/onboarding/snapshot.ts +1 -1
  235. package/src/runtime/onboarding/state.ts +2 -2
  236. package/src/runtime/onboarding/types.ts +2 -2
  237. package/src/runtime/orchestrator-core-services.ts +1 -1
  238. package/src/runtime/path-shadow-startup.ts +28 -221
  239. package/src/runtime/power-keepawake-remote.ts +3 -2
  240. package/src/runtime/process-lifecycle.ts +2 -2
  241. package/src/runtime/provider-fallback.ts +10 -66
  242. package/src/runtime/recovery-autosave.ts +1 -1
  243. package/src/runtime/recovery-offer-wiring.ts +39 -23
  244. package/src/runtime/recovery-prompt.ts +31 -17
  245. package/src/runtime/relay-reachability-bridge.ts +53 -42
  246. package/src/runtime/release-artifacts.ts +2 -1
  247. package/src/runtime/runtime-services-types.ts +82 -35
  248. package/src/runtime/services.ts +305 -300
  249. package/src/runtime/session-resume-liveness-confirm.ts +1 -1
  250. package/src/runtime/ui-services.ts +7 -6
  251. package/src/runtime/update-check.ts +23 -43
  252. package/src/runtime/workspace-checkpointing.ts +1 -1
  253. package/src/runtime/wrfc-persistence.ts +2 -2
  254. package/src/shell/ui-openers.ts +30 -7
  255. package/src/utils/clipboard.ts +1 -1
  256. package/src/verification/verification-ledger.ts +10 -8
  257. package/src/version.ts +1 -1
  258. package/bin/goodvibes-daemon +0 -90
  259. package/src/cli/config-overrides.ts +0 -267
  260. package/src/cli/endpoints.ts +0 -109
  261. package/src/cli/parser.ts +0 -395
  262. package/src/cli/redaction.ts +0 -170
  263. package/src/cli/types.ts +0 -84
  264. package/src/cluster/commands.ts +0 -382
  265. package/src/cluster/remote-daemon-target.ts +0 -225
  266. package/src/cluster/render.ts +0 -268
  267. package/src/config/atomic-write.ts +0 -70
  268. package/src/config/credential-availability.ts +0 -122
  269. package/src/config/goodvibes-home.ts +0 -149
  270. package/src/config/index.ts +0 -88
  271. package/src/config/provider-model.ts +0 -23
  272. package/src/config/read-versioned.ts +0 -228
  273. package/src/core/alert-gating.ts +0 -67
  274. package/src/core/consolidation-receipt.ts +0 -41
  275. package/src/core/focus-tracker.ts +0 -41
  276. package/src/core/history.ts +0 -45
  277. package/src/core/memory-status.ts +0 -118
  278. package/src/core/orchestrator.ts +0 -7
  279. package/src/core/pairing-devices.ts +0 -49
  280. package/src/core/pairing-handoff.ts +0 -101
  281. package/src/core/pairing-offers.ts +0 -83
  282. package/src/core/pairing-origin.ts +0 -78
  283. package/src/core/rewind-turn-anchors.ts +0 -311
  284. package/src/core/session-recovery.ts +0 -210
  285. package/src/core/stable-host.ts +0 -171
  286. package/src/core/transcript-journal.ts +0 -503
  287. package/src/daemon/cli.ts +0 -693
  288. package/src/daemon/fatal-boot-report.ts +0 -111
  289. package/src/daemon/handlers/context.ts +0 -29
  290. package/src/daemon/handlers/contracts.ts +0 -77
  291. package/src/daemon/handlers/credentials.ts +0 -139
  292. package/src/daemon/handlers/drafts/draft-store.ts +0 -427
  293. package/src/daemon/handlers/drafts/index.ts +0 -17
  294. package/src/daemon/handlers/drafts/register.ts +0 -331
  295. package/src/daemon/handlers/errors.ts +0 -18
  296. package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
  297. package/src/daemon/handlers/inbox/index.ts +0 -284
  298. package/src/daemon/handlers/inbox/mapping.ts +0 -192
  299. package/src/daemon/handlers/inbox/poller.ts +0 -212
  300. package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
  301. package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
  302. package/src/daemon/handlers/inbox/providers/email.ts +0 -152
  303. package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
  304. package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
  305. package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
  306. package/src/daemon/handlers/index.ts +0 -117
  307. package/src/daemon/handlers/register.ts +0 -168
  308. package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
  309. package/src/daemon/handlers/remote/backends/docker.ts +0 -79
  310. package/src/daemon/handlers/remote/backends/index.ts +0 -40
  311. package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
  312. package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
  313. package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
  314. package/src/daemon/handlers/remote/backends/types.ts +0 -97
  315. package/src/daemon/handlers/remote/dispatcher.ts +0 -181
  316. package/src/daemon/handlers/remote/index.ts +0 -119
  317. package/src/daemon/handlers/remote/peer-registry.ts +0 -357
  318. package/src/daemon/handlers/remote/service.ts +0 -191
  319. package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
  320. package/src/daemon/handlers/routing/index.ts +0 -261
  321. package/src/daemon/handlers/routing/route-store.ts +0 -319
  322. package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
  323. package/src/daemon/handlers/sqlite-store.ts +0 -278
  324. package/src/daemon/handlers/triage/index.ts +0 -57
  325. package/src/daemon/handlers/triage/integration.ts +0 -213
  326. package/src/daemon/handlers/triage/pipeline.ts +0 -274
  327. package/src/daemon/handlers/triage/scorer.ts +0 -287
  328. package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
  329. package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
  330. package/src/daemon/handlers/triage/tagger/index.ts +0 -184
  331. package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
  332. package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
  333. package/src/daemon/handlers/triage/types.ts +0 -50
  334. package/src/daemon/lifecycle.ts +0 -41
  335. package/src/daemon/provision-wake-model.ts +0 -81
  336. package/src/daemon/safe-serve.ts +0 -61
  337. package/src/daemon/send/channels.ts +0 -200
  338. package/src/daemon/send/command.ts +0 -332
  339. package/src/daemon/send/composition.ts +0 -99
  340. package/src/daemon/send/failure-text.ts +0 -93
  341. package/src/daemon/send/inert-text.ts +0 -225
  342. package/src/daemon/send/stdin.ts +0 -24
  343. package/src/daemon/service-commands.ts +0 -329
  344. package/src/export/cost-utils.ts +0 -319
  345. package/src/input/selection.ts +0 -135
  346. package/src/plugins/loader.ts +0 -15
  347. package/src/renderer/bottom-bar.ts +0 -58
  348. package/src/renderer/conversation-tree.ts +0 -228
  349. package/src/runtime/agent-graph-composition.ts +0 -78
  350. package/src/runtime/channel-composition.ts +0 -46
  351. package/src/runtime/cluster-composition.ts +0 -124
  352. package/src/runtime/cluster-group-composition.ts +0 -284
  353. package/src/runtime/code-index-services.ts +0 -167
  354. package/src/runtime/daemon-handler-composition.ts +0 -76
  355. package/src/runtime/device-posture-composition.ts +0 -110
  356. package/src/runtime/durability-housekeeping.ts +0 -183
  357. package/src/runtime/durability-services.ts +0 -155
  358. package/src/runtime/embedded-service-factories.ts +0 -74
  359. package/src/runtime/feature-settings.ts +0 -154
  360. package/src/runtime/fleet-needs-input-push.ts +0 -70
  361. package/src/runtime/fleet-services.ts +0 -41
  362. package/src/runtime/idle-power-services.ts +0 -85
  363. package/src/runtime/mail-composition.ts +0 -65
  364. package/src/runtime/memory-fold.ts +0 -55
  365. package/src/runtime/operator-token-cleanup.ts +0 -109
  366. package/src/runtime/path-shadow.ts +0 -418
  367. package/src/runtime/perf/panel-health-monitor.ts +0 -18
  368. package/src/runtime/provider-optimizer-wiring.ts +0 -55
  369. package/src/runtime/reachability-notice.ts +0 -100
  370. package/src/runtime/remote-execution-composition.ts +0 -62
  371. package/src/runtime/session-liveness-marker.ts +0 -257
  372. package/src/runtime/session-pointer-surface.ts +0 -22
  373. package/src/runtime/session-storage-services.ts +0 -41
  374. package/src/runtime/surface-feature-flags.ts +0 -96
  375. package/src/runtime/terminal-output-guard.ts +0 -235
  376. package/src/runtime/trust/workspace-registration.ts +0 -192
  377. package/src/runtime/trust/workspace-trust.ts +0 -229
  378. package/src/runtime/ui/index.ts +0 -39
  379. package/src/runtime/ui/model-picker/data-provider.ts +0 -182
  380. package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
  381. package/src/runtime/ui/model-picker/index.ts +0 -59
  382. package/src/runtime/ui/model-picker/types.ts +0 -153
  383. package/src/runtime/ui/provider-health/data-provider.ts +0 -244
  384. package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
  385. package/src/runtime/ui/provider-health/index.ts +0 -46
  386. package/src/runtime/ui/provider-health/types.ts +0 -146
  387. package/src/runtime/ui-events.ts +0 -1
  388. package/src/runtime/ui-read-model-helpers.ts +0 -1
  389. package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
  390. package/src/runtime/ui-read-models-observability-options.ts +0 -1
  391. package/src/runtime/ui-read-models-observability-remote.ts +0 -1
  392. package/src/runtime/ui-read-models-observability-security.ts +0 -1
  393. package/src/runtime/ui-read-models-observability-system.ts +0 -1
  394. package/src/runtime/ui-read-models-observability.ts +0 -1
  395. package/src/runtime/ui-service-queries.ts +0 -1
  396. package/src/runtime/voice-setup-services.ts +0 -98
  397. package/src/runtime/workstream-attempts-validation.ts +0 -77
  398. package/src/runtime/workstream-draft-edits.ts +0 -95
  399. package/src/runtime/workstream-draft-store.ts +0 -274
  400. package/src/runtime/workstream-draft-types.ts +0 -42
  401. package/src/runtime/workstream-services.ts +0 -373
  402. package/src/tools/index.ts +0 -1
  403. package/src/types/grid.ts +0 -48
  404. package/src/types/sql-js.d.ts +0 -15
  405. package/src/work-plans/work-plan-store.ts +0 -702
@@ -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 {