@pellux/goodvibes-tui 1.27.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/CHANGELOG.md +125 -2
  2. package/README.md +7 -9
  3. package/bin/goodvibes +2 -2
  4. package/bin/launcher-support.js +8 -4
  5. package/docs/README.md +11 -2
  6. package/docs/foundation-artifacts/operator-contract.json +6403 -2347
  7. package/package.json +14 -25
  8. package/scripts/postinstall.js +35 -35
  9. package/src/audio/spoken-turn-model-routing.ts +1 -1
  10. package/src/cli/bundle-command.ts +5 -5
  11. package/src/cli/completions/generate.ts +1 -1
  12. package/src/cli/doctor.ts +3 -3
  13. package/src/cli/entrypoint.ts +12 -7
  14. package/src/cli/help.ts +4 -5
  15. package/src/cli/hooks-command.ts +1 -1
  16. package/src/cli/index.ts +1 -4
  17. package/src/cli/launch-auto-update.ts +59 -7
  18. package/src/cli/management-commands.ts +6 -6
  19. package/src/cli/management-utils.ts +5 -5
  20. package/src/cli/management.ts +7 -7
  21. package/src/cli/network-posture.ts +1 -1
  22. package/src/cli/package-verification.ts +7 -6
  23. package/src/cli/plugin-bundles-command.ts +1 -1
  24. package/src/cli/plugin-command.ts +2 -2
  25. package/src/cli/service-command.ts +2 -2
  26. package/src/cli/service-posture.ts +4 -4
  27. package/src/cli/status.ts +9 -8
  28. package/src/cli/surface-command.ts +4 -4
  29. package/src/cli/tui-startup.ts +12 -3
  30. package/src/cli-flags.ts +3 -3
  31. package/src/config/goodvibes-home-audit.ts +0 -2
  32. package/src/config/secret-config.ts +37 -5
  33. package/src/config/tui-extension-settings.ts +1 -1
  34. package/src/core/approval-alert.ts +2 -2
  35. package/src/core/budget-breach-notifier.ts +3 -3
  36. package/src/core/conversation-compaction-render.ts +1 -1
  37. package/src/core/conversation-line-cache.ts +1 -1
  38. package/src/core/conversation-render-context.ts +1 -1
  39. package/src/core/conversation-rendering.ts +2 -2
  40. package/src/core/conversation.ts +10 -10
  41. package/src/core/long-task-notifier.ts +2 -2
  42. package/src/core/memory-diagnostics-gateway.ts +1 -1
  43. package/src/core/scriptable-statusline.ts +1 -1
  44. package/src/core/session-auto-titler.ts +1 -1
  45. package/src/core/session-resume-core.ts +2 -2
  46. package/src/core/stream-event-wiring.ts +24 -44
  47. package/src/core/terminal-notifier.ts +3 -3
  48. package/src/core/turn-cancellation.ts +1 -1
  49. package/src/core/turn-event-wiring.ts +5 -5
  50. package/src/input/command-registry.ts +6 -6
  51. package/src/input/commands/channel-pairing.ts +1 -1
  52. package/src/input/commands/cluster-runtime.ts +1 -1
  53. package/src/input/commands/codebase-runtime.ts +1 -1
  54. package/src/input/commands/devices-runtime.ts +1 -1
  55. package/src/input/commands/hosted-runtime.ts +330 -0
  56. package/src/input/commands/local-setup-review.ts +1 -1
  57. package/src/input/commands/local-setup-transfer.ts +2 -2
  58. package/src/input/commands/local-setup.ts +3 -3
  59. package/src/input/commands/managed-runtime.ts +2 -2
  60. package/src/input/commands/operator-rpc.ts +24 -110
  61. package/src/input/commands/payment-card-intake.ts +1 -1
  62. package/src/input/commands/permissions-provenance.ts +2 -2
  63. package/src/input/commands/plugin-runtime.ts +1 -1
  64. package/src/input/commands/provider.ts +1 -1
  65. package/src/input/commands/relay-runtime.ts +18 -9
  66. package/src/input/commands/rewind-runtime.ts +1 -1
  67. package/src/input/commands/runtime-services.ts +1 -1
  68. package/src/input/commands/services-runtime.ts +1 -1
  69. package/src/input/commands/session-workflow.ts +1 -1
  70. package/src/input/commands/settings-sync-runtime.ts +2 -2
  71. package/src/input/commands/share-runtime.ts +1 -1
  72. package/src/input/commands/tasks-runtime.ts +145 -55
  73. package/src/input/commands/update-runtime.ts +31 -28
  74. package/src/input/commands/work-plan-runtime.ts +2 -2
  75. package/src/input/commands/workstream-attempts.ts +1 -1
  76. package/src/input/commands/workstream-runtime.ts +2 -2
  77. package/src/input/commands.ts +2 -0
  78. package/src/input/feature-unit-layout.ts +1 -1
  79. package/src/input/feed-context-factory.ts +3 -3
  80. package/src/input/handler-content-actions.ts +2 -2
  81. package/src/input/handler-feed-routes.ts +1 -1
  82. package/src/input/handler-feed.ts +3 -3
  83. package/src/input/handler-modal-token-routes.ts +1 -1
  84. package/src/input/handler-onboarding-daemon-adopt.ts +3 -2
  85. package/src/input/handler-onboarding.ts +1 -1
  86. package/src/input/handler-types.ts +2 -2
  87. package/src/input/handler-ui-state.ts +1 -1
  88. package/src/input/handler.ts +4 -4
  89. package/src/input/input-history.ts +1 -1
  90. package/src/input/onboarding/onboarding-feature-units.ts +2 -2
  91. package/src/input/onboarding/onboarding-runtime-status.ts +15 -1
  92. package/src/input/onboarding/onboarding-wizard-apply.ts +17 -8
  93. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +5 -3
  94. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +1 -1
  95. package/src/input/onboarding/onboarding-wizard-types.ts +1 -1
  96. package/src/input/payments-config.ts +6 -6
  97. package/src/input/search.ts +1 -1
  98. package/src/input/session-picker-modal.ts +46 -0
  99. package/src/input/settings-modal-activation.ts +1 -1
  100. package/src/input/settings-modal-behavior.ts +4 -4
  101. package/src/input/settings-modal-commit.ts +11 -0
  102. package/src/input/settings-modal-data.ts +13 -80
  103. package/src/input/settings-modal-mutations.ts +33 -0
  104. package/src/input/settings-modal-secrets.ts +34 -0
  105. package/src/input/settings-modal-subscriptions.ts +1 -1
  106. package/src/input/settings-modal-types.ts +15 -1
  107. package/src/input/settings-modal.ts +28 -3
  108. package/src/input/worktree-setup-config.ts +1 -1
  109. package/src/main.ts +11 -9
  110. package/src/panels/agent-inspector-shared.ts +2 -2
  111. package/src/panels/base-panel.ts +2 -2
  112. package/src/panels/builtin/operations.ts +6 -8
  113. package/src/panels/builtin/session.ts +17 -0
  114. package/src/panels/builtin/shared.ts +5 -5
  115. package/src/panels/builtin-modals.ts +3 -3
  116. package/src/panels/confirm-state.ts +1 -1
  117. package/src/panels/cost-tracker-panel.ts +4 -4
  118. package/src/panels/diff-panel.ts +2 -2
  119. package/src/panels/diff-review-panel.ts +2 -2
  120. package/src/panels/expandable-list-panel.ts +2 -2
  121. package/src/panels/fleet-acts.ts +1 -1
  122. package/src/panels/fleet-observed-render.ts +1 -1
  123. package/src/panels/fleet-panel-format.ts +1 -1
  124. package/src/panels/fleet-panel.ts +1 -1
  125. package/src/panels/fleet-spawn.ts +1 -1
  126. package/src/panels/fleet-steer.ts +1 -1
  127. package/src/panels/fleet-transcript.ts +1 -1
  128. package/src/panels/git-panel.ts +1 -1
  129. package/src/panels/hosted-session-feed.ts +352 -0
  130. package/src/panels/hosted-session-panel.ts +221 -0
  131. package/src/panels/local-auth-panel.ts +3 -3
  132. package/src/panels/modals/devices-modal.ts +1 -1
  133. package/src/panels/modals/local-auth-modal.ts +1 -1
  134. package/src/panels/modals/pairing-modal.ts +1 -1
  135. package/src/panels/modals/services-modal.ts +1 -1
  136. package/src/panels/modals/settings-sync-modal.ts +1 -1
  137. package/src/panels/modals/subscription-modal.ts +1 -1
  138. package/src/panels/modals/work-plan-modal.ts +1 -1
  139. package/src/panels/notifications-panel.ts +1 -1
  140. package/src/panels/panel-confirm-overlay.ts +1 -1
  141. package/src/panels/plugins-panel.ts +2 -2
  142. package/src/panels/polish-core.ts +2 -2
  143. package/src/panels/polish-tables.ts +1 -1
  144. package/src/panels/polish.ts +2 -2
  145. package/src/panels/scrollable-list-panel.ts +3 -3
  146. package/src/panels/skills-panel.ts +3 -3
  147. package/src/panels/token-budget-panel.ts +5 -5
  148. package/src/panels/types.ts +1 -2
  149. package/src/permissions/prompt.ts +1 -1
  150. package/src/renderer/autocomplete-overlay.ts +1 -1
  151. package/src/renderer/block-actions-overlay.ts +1 -1
  152. package/src/renderer/bookmark-modal.ts +1 -1
  153. package/src/renderer/buffer.ts +1 -1
  154. package/src/renderer/code-block.ts +1 -1
  155. package/src/renderer/composer-fragments.ts +1 -1
  156. package/src/renderer/compositor.ts +2 -2
  157. package/src/renderer/config-modal.ts +1 -1
  158. package/src/renderer/context-inspector.ts +1 -1
  159. package/src/renderer/conversation-layout.ts +2 -2
  160. package/src/renderer/conversation-overlays.ts +1 -1
  161. package/src/renderer/conversation-surface.ts +2 -2
  162. package/src/renderer/diff-view.ts +1 -1
  163. package/src/renderer/diff.ts +1 -1
  164. package/src/renderer/file-picker-overlay.ts +1 -1
  165. package/src/renderer/fleet-tab-strip.ts +1 -1
  166. package/src/renderer/fullscreen-primitives.ts +2 -2
  167. package/src/renderer/fullscreen-workspace.ts +1 -1
  168. package/src/renderer/header-line.ts +1 -1
  169. package/src/renderer/help-overlay.ts +1 -1
  170. package/src/renderer/history-search-overlay.ts +2 -2
  171. package/src/renderer/layout.ts +5 -8
  172. package/src/renderer/markdown-inline.ts +1 -1
  173. package/src/renderer/markdown-table.ts +1 -1
  174. package/src/renderer/markdown.ts +1 -1
  175. package/src/renderer/mcp-workspace.ts +1 -1
  176. package/src/renderer/modal-factory.ts +2 -2
  177. package/src/renderer/model-workspace.ts +2 -2
  178. package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
  179. package/src/renderer/overlay-box.ts +1 -1
  180. package/src/renderer/panel-composite.ts +1 -1
  181. package/src/renderer/panel-workspace-bar.ts +1 -1
  182. package/src/renderer/process-indicator.ts +1 -1
  183. package/src/renderer/profile-picker-modal.ts +1 -1
  184. package/src/renderer/search-overlay.ts +2 -2
  185. package/src/renderer/selection-modal-overlay.ts +1 -1
  186. package/src/renderer/session-picker-modal.ts +124 -3
  187. package/src/renderer/settings-modal-helpers.ts +2 -0
  188. package/src/renderer/settings-modal.ts +2 -2
  189. package/src/renderer/shell-surface.ts +2 -2
  190. package/src/renderer/system-message.ts +1 -1
  191. package/src/renderer/tab-strip.ts +1 -1
  192. package/src/renderer/theme-mode-config.ts +1 -1
  193. package/src/renderer/theme.ts +11 -12
  194. package/src/renderer/thinking.ts +1 -1
  195. package/src/renderer/tool-call.ts +2 -2
  196. package/src/renderer/tool-result-expanded-lines.ts +1 -1
  197. package/src/renderer/turn-injection.ts +7 -8
  198. package/src/renderer/ui-factory.ts +3 -3
  199. package/src/runtime/bootstrap-command-context.ts +4 -4
  200. package/src/runtime/bootstrap-command-parts.ts +5 -5
  201. package/src/runtime/bootstrap-core.ts +30 -30
  202. package/src/runtime/bootstrap-shell.ts +4 -4
  203. package/src/runtime/bootstrap.ts +128 -157
  204. package/src/runtime/client/approval-updates.ts +82 -0
  205. package/src/runtime/client/build-floors.ts +167 -0
  206. package/src/runtime/client/daemon-attach-handshake.ts +115 -0
  207. package/src/runtime/client/fleet-union.ts +147 -0
  208. package/src/runtime/client/host-service-status.ts +71 -0
  209. package/src/runtime/client/hosted-exit.ts +86 -0
  210. package/src/runtime/client/hosted-roster.ts +110 -0
  211. package/src/runtime/client/hosted-session-stream.ts +178 -0
  212. package/src/runtime/client/hosted-sessions.ts +187 -0
  213. package/src/runtime/client/operator-endpoint.ts +213 -0
  214. package/src/runtime/client/spine-adoption.ts +99 -0
  215. package/src/runtime/cloudflare-control-plane.ts +1 -1
  216. package/src/runtime/context-accounting-source.ts +1 -1
  217. package/src/runtime/context.ts +2 -2
  218. package/src/runtime/conversation-rewind-port.ts +42 -14
  219. package/src/runtime/daemon-attach-notices.ts +55 -19
  220. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  221. package/src/runtime/disposal-wiring.ts +4 -24
  222. package/src/runtime/index.ts +119 -105
  223. package/src/runtime/install-self-check-startup.ts +2 -2
  224. package/src/runtime/interaction-seams.ts +1 -1
  225. package/src/runtime/knowledge-services.ts +8 -2
  226. package/src/runtime/legacy-daemon-migration.ts +15 -3
  227. package/src/runtime/legacy-daemon-reconcile.ts +3 -2
  228. package/src/runtime/memory-spine-transport.ts +37 -267
  229. package/src/runtime/notification-dispatch.ts +2 -2
  230. package/src/runtime/onboarding/apply.ts +2 -2
  231. package/src/runtime/onboarding/derivation.ts +2 -2
  232. package/src/runtime/onboarding/markers.ts +2 -2
  233. package/src/runtime/onboarding/progress.ts +2 -2
  234. package/src/runtime/onboarding/snapshot.ts +1 -1
  235. package/src/runtime/onboarding/state.ts +2 -2
  236. package/src/runtime/onboarding/types.ts +2 -2
  237. package/src/runtime/orchestrator-core-services.ts +1 -1
  238. package/src/runtime/path-shadow-startup.ts +28 -221
  239. package/src/runtime/power-keepawake-remote.ts +3 -2
  240. package/src/runtime/process-lifecycle.ts +2 -2
  241. package/src/runtime/provider-fallback.ts +10 -66
  242. package/src/runtime/recovery-autosave.ts +1 -1
  243. package/src/runtime/recovery-offer-wiring.ts +39 -23
  244. package/src/runtime/recovery-prompt.ts +31 -17
  245. package/src/runtime/relay-reachability-bridge.ts +53 -42
  246. package/src/runtime/release-artifacts.ts +2 -1
  247. package/src/runtime/runtime-services-types.ts +82 -35
  248. package/src/runtime/services.ts +305 -300
  249. package/src/runtime/session-resume-liveness-confirm.ts +1 -1
  250. package/src/runtime/ui-services.ts +7 -6
  251. package/src/runtime/update-check.ts +23 -43
  252. package/src/runtime/workspace-checkpointing.ts +1 -1
  253. package/src/runtime/wrfc-persistence.ts +2 -2
  254. package/src/shell/ui-openers.ts +30 -7
  255. package/src/utils/clipboard.ts +1 -1
  256. package/src/verification/verification-ledger.ts +10 -8
  257. package/src/version.ts +1 -1
  258. package/bin/goodvibes-daemon +0 -90
  259. package/src/cli/config-overrides.ts +0 -267
  260. package/src/cli/endpoints.ts +0 -109
  261. package/src/cli/parser.ts +0 -395
  262. package/src/cli/redaction.ts +0 -170
  263. package/src/cli/types.ts +0 -84
  264. package/src/cluster/commands.ts +0 -382
  265. package/src/cluster/remote-daemon-target.ts +0 -225
  266. package/src/cluster/render.ts +0 -268
  267. package/src/config/atomic-write.ts +0 -70
  268. package/src/config/credential-availability.ts +0 -122
  269. package/src/config/goodvibes-home.ts +0 -149
  270. package/src/config/index.ts +0 -88
  271. package/src/config/provider-model.ts +0 -23
  272. package/src/config/read-versioned.ts +0 -228
  273. package/src/core/alert-gating.ts +0 -67
  274. package/src/core/consolidation-receipt.ts +0 -41
  275. package/src/core/focus-tracker.ts +0 -41
  276. package/src/core/history.ts +0 -45
  277. package/src/core/memory-status.ts +0 -118
  278. package/src/core/orchestrator.ts +0 -7
  279. package/src/core/pairing-devices.ts +0 -49
  280. package/src/core/pairing-handoff.ts +0 -101
  281. package/src/core/pairing-offers.ts +0 -83
  282. package/src/core/pairing-origin.ts +0 -78
  283. package/src/core/rewind-turn-anchors.ts +0 -311
  284. package/src/core/session-recovery.ts +0 -210
  285. package/src/core/stable-host.ts +0 -171
  286. package/src/core/transcript-journal.ts +0 -503
  287. package/src/daemon/cli.ts +0 -641
  288. package/src/daemon/handlers/context.ts +0 -29
  289. package/src/daemon/handlers/contracts.ts +0 -77
  290. package/src/daemon/handlers/credentials.ts +0 -139
  291. package/src/daemon/handlers/drafts/draft-store.ts +0 -427
  292. package/src/daemon/handlers/drafts/index.ts +0 -17
  293. package/src/daemon/handlers/drafts/register.ts +0 -331
  294. package/src/daemon/handlers/errors.ts +0 -18
  295. package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
  296. package/src/daemon/handlers/inbox/index.ts +0 -284
  297. package/src/daemon/handlers/inbox/mapping.ts +0 -192
  298. package/src/daemon/handlers/inbox/poller.ts +0 -212
  299. package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
  300. package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
  301. package/src/daemon/handlers/inbox/providers/email.ts +0 -152
  302. package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
  303. package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
  304. package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
  305. package/src/daemon/handlers/index.ts +0 -117
  306. package/src/daemon/handlers/register.ts +0 -168
  307. package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
  308. package/src/daemon/handlers/remote/backends/docker.ts +0 -79
  309. package/src/daemon/handlers/remote/backends/index.ts +0 -40
  310. package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
  311. package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
  312. package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
  313. package/src/daemon/handlers/remote/backends/types.ts +0 -97
  314. package/src/daemon/handlers/remote/dispatcher.ts +0 -181
  315. package/src/daemon/handlers/remote/index.ts +0 -119
  316. package/src/daemon/handlers/remote/peer-registry.ts +0 -357
  317. package/src/daemon/handlers/remote/service.ts +0 -191
  318. package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
  319. package/src/daemon/handlers/routing/index.ts +0 -261
  320. package/src/daemon/handlers/routing/route-store.ts +0 -319
  321. package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
  322. package/src/daemon/handlers/sqlite-store.ts +0 -278
  323. package/src/daemon/handlers/triage/index.ts +0 -57
  324. package/src/daemon/handlers/triage/integration.ts +0 -213
  325. package/src/daemon/handlers/triage/pipeline.ts +0 -274
  326. package/src/daemon/handlers/triage/scorer.ts +0 -287
  327. package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
  328. package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
  329. package/src/daemon/handlers/triage/tagger/index.ts +0 -184
  330. package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
  331. package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
  332. package/src/daemon/handlers/triage/types.ts +0 -50
  333. package/src/daemon/lifecycle.ts +0 -41
  334. package/src/daemon/provision-wake-model.ts +0 -81
  335. package/src/daemon/safe-serve.ts +0 -61
  336. package/src/daemon/send/channels.ts +0 -200
  337. package/src/daemon/send/command.ts +0 -332
  338. package/src/daemon/send/composition.ts +0 -99
  339. package/src/daemon/send/failure-text.ts +0 -93
  340. package/src/daemon/send/inert-text.ts +0 -225
  341. package/src/daemon/send/stdin.ts +0 -24
  342. package/src/daemon/service-commands.ts +0 -329
  343. package/src/export/cost-utils.ts +0 -319
  344. package/src/input/selection.ts +0 -135
  345. package/src/plugins/loader.ts +0 -15
  346. package/src/renderer/bottom-bar.ts +0 -58
  347. package/src/renderer/conversation-tree.ts +0 -228
  348. package/src/runtime/agent-graph-composition.ts +0 -78
  349. package/src/runtime/channel-composition.ts +0 -46
  350. package/src/runtime/cluster-composition.ts +0 -124
  351. package/src/runtime/cluster-group-composition.ts +0 -284
  352. package/src/runtime/code-index-services.ts +0 -167
  353. package/src/runtime/daemon-handler-composition.ts +0 -76
  354. package/src/runtime/device-posture-composition.ts +0 -110
  355. package/src/runtime/durability-housekeeping.ts +0 -183
  356. package/src/runtime/durability-services.ts +0 -155
  357. package/src/runtime/embedded-service-factories.ts +0 -58
  358. package/src/runtime/feature-settings.ts +0 -154
  359. package/src/runtime/fleet-needs-input-push.ts +0 -70
  360. package/src/runtime/fleet-services.ts +0 -41
  361. package/src/runtime/idle-power-services.ts +0 -85
  362. package/src/runtime/mail-composition.ts +0 -65
  363. package/src/runtime/memory-fold.ts +0 -55
  364. package/src/runtime/operator-token-cleanup.ts +0 -109
  365. package/src/runtime/path-shadow.ts +0 -418
  366. package/src/runtime/perf/panel-health-monitor.ts +0 -18
  367. package/src/runtime/provider-optimizer-wiring.ts +0 -55
  368. package/src/runtime/reachability-notice.ts +0 -100
  369. package/src/runtime/remote-execution-composition.ts +0 -62
  370. package/src/runtime/session-liveness-marker.ts +0 -257
  371. package/src/runtime/session-pointer-surface.ts +0 -22
  372. package/src/runtime/session-storage-services.ts +0 -41
  373. package/src/runtime/surface-feature-flags.ts +0 -96
  374. package/src/runtime/terminal-output-guard.ts +0 -235
  375. package/src/runtime/trust/workspace-registration.ts +0 -192
  376. package/src/runtime/trust/workspace-trust.ts +0 -229
  377. package/src/runtime/ui/index.ts +0 -39
  378. package/src/runtime/ui/model-picker/data-provider.ts +0 -182
  379. package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
  380. package/src/runtime/ui/model-picker/index.ts +0 -59
  381. package/src/runtime/ui/model-picker/types.ts +0 -153
  382. package/src/runtime/ui/provider-health/data-provider.ts +0 -244
  383. package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
  384. package/src/runtime/ui/provider-health/index.ts +0 -46
  385. package/src/runtime/ui/provider-health/types.ts +0 -146
  386. package/src/runtime/ui-events.ts +0 -1
  387. package/src/runtime/ui-read-model-helpers.ts +0 -1
  388. package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
  389. package/src/runtime/ui-read-models-observability-options.ts +0 -1
  390. package/src/runtime/ui-read-models-observability-remote.ts +0 -1
  391. package/src/runtime/ui-read-models-observability-security.ts +0 -1
  392. package/src/runtime/ui-read-models-observability-system.ts +0 -1
  393. package/src/runtime/ui-read-models-observability.ts +0 -1
  394. package/src/runtime/ui-service-queries.ts +0 -1
  395. package/src/runtime/voice-setup-services.ts +0 -98
  396. package/src/runtime/workstream-attempts-validation.ts +0 -77
  397. package/src/runtime/workstream-draft-edits.ts +0 -95
  398. package/src/runtime/workstream-draft-store.ts +0 -274
  399. package/src/runtime/workstream-draft-types.ts +0 -42
  400. package/src/runtime/workstream-services.ts +0 -373
  401. package/src/tools/index.ts +0 -1
  402. package/src/types/grid.ts +0 -48
  403. package/src/types/sql-js.d.ts +0 -15
  404. package/src/work-plans/work-plan-store.ts +0 -702
@@ -1,503 +0,0 @@
1
- /**
2
- * transcript-journal.ts — WAL-style append-only transcript journal.
3
- *
4
- * Purpose
5
- * ───────
6
- * Between full snapshots (written by persistConversation / writeRecoveryFile),
7
- * a SIGKILL loses every conversation turn since the last snapshot. This module
8
- * provides an append-only journal that records each durable conversation event
9
- * (user message submitted, assistant turn finalised, tool results appended,
10
- * compaction performed) so that a kill at any moment loses at most the
11
- * in-flight append — never a full turn.
12
- *
13
- * File format (NDJSON)
14
- * ────────────────────
15
- * Line 0 — header: { version: 1, sessionId: "...", createdAt: <epochMs> }
16
- * Line 1+ — records: { type, seq, ts, messages: ConversationMessageSnapshot[] }
17
- *
18
- * The header carries the schemaVersion so that a reader from a future process
19
- * can gate on it (readVersioned convention: unknown version → quarantine).
20
- *
21
- * Durability / performance tradeoff
22
- * ──────────────────────────────────
23
- * appendRecord() performs one appendFileSync + one fsyncSync per call.
24
- * This means one fsync per durable conversation event (user message,
25
- * assistant turn, tool result batch, compaction). It does NOT fsync per
26
- * streaming token — the streaming path never calls appendRecord().
27
- *
28
- * At typical usage (a few events per user turn), this is 2–6 fsyncs/min,
29
- * well within the durability/throughput envelope of any modern filesystem.
30
- * The tradeoff is explicit: we accept per-event write amplification in
31
- * exchange for at-most-one-record loss on SIGKILL.
32
- *
33
- * Recovery semantics
34
- * ──────────────────
35
- * 1. Read the header line. Gate on version — quarantine if unrecognised.
36
- * 2. Read subsequent lines until EOF. Stop at the first line that is not
37
- * valid JSON or lacks the expected shape. Quarantine the remainder of
38
- * the file from that point onward (rename to .unrecognized). Never crash.
39
- * 3. Return only records whose `ts` is strictly greater than the provided
40
- * `snapshotTimestamp` (i.e. events that occurred after the last snapshot).
41
- * 4. Caller replays the returned records in `seq` order atop the snapshot
42
- * to reconstruct the conversation, then writes a fresh snapshot and
43
- * calls `journal.rotate()` to truncate the journal.
44
- *
45
- * Rotation
46
- * ────────
47
- * After a fresh snapshot is written, call journal.rotate() which deletes the
48
- * journal file. The next append will recreate it with a fresh header.
49
- *
50
- * Journal path convention
51
- * ───────────────────────
52
- * <homeDirectory>/.goodvibes/tui/transcript-<sessionId>.journal
53
- * This mirrors the recovery-file location (homeDirectory-scoped, not
54
- * workingDir-scoped) so all per-session durability artefacts live together.
55
- */
56
-
57
- import {
58
- appendFileSync,
59
- closeSync,
60
- existsSync,
61
- fsyncSync,
62
- mkdirSync,
63
- openSync,
64
- readFileSync,
65
- readdirSync,
66
- renameSync,
67
- statSync,
68
- unlinkSync,
69
- } from 'node:fs';
70
- import { dirname, join } from 'node:path';
71
- import type { ConversationMessageSnapshot } from '@pellux/goodvibes-sdk/platform/core';
72
- import { UNRECOGNIZED_SUFFIX } from '@/config/read-versioned.ts';
73
- import type { SessionSurface } from '@/runtime/index.ts';
74
-
75
- // ─── Constants ──────────────────────────────────────────────────────────────
76
-
77
- export const JOURNAL_SCHEMA_VERSION = 1;
78
-
79
- // ─── Types ──────────────────────────────────────────────────────────────────
80
-
81
- export interface JournalHeader {
82
- readonly version: typeof JOURNAL_SCHEMA_VERSION;
83
- readonly sessionId: string;
84
- readonly createdAt: number;
85
- }
86
-
87
- export type JournalEventType =
88
- | 'user_message'
89
- | 'assistant_turn'
90
- | 'tool_results'
91
- | 'compaction';
92
-
93
- export interface JournalRecord {
94
- /** Discriminator for the kind of durable event. */
95
- readonly type: JournalEventType;
96
- /** Monotonically increasing sequence number (0-based, per journal file). */
97
- readonly seq: number;
98
- /** Wall-clock timestamp (Date.now()) when the record was appended. */
99
- readonly ts: number;
100
- /** Full conversation message snapshot at the time of the event. */
101
- readonly messages: ConversationMessageSnapshot[];
102
- }
103
-
104
- export interface ReplayResult {
105
- /** Records whose ts is strictly after snapshotTimestamp, in seq order. */
106
- readonly records: JournalRecord[];
107
- /**
108
- * True if the journal tail was corrupt (a partial write from a kill).
109
- * The corrupt tail has been quarantined; replay stopped at the last
110
- * good record.
111
- */
112
- readonly hadCorruptTail: boolean;
113
- }
114
-
115
- // ─── Public API ─────────────────────────────────────────────────────────────
116
-
117
- export interface TranscriptJournal {
118
- /**
119
- * Append one durable event record and fsync it to disk.
120
- *
121
- * Best-effort: if the write fails (e.g. disk full), the error is swallowed
122
- * — the journal is durability-enhancing, never a hard requirement.
123
- */
124
- appendRecord(type: JournalEventType, messages: ConversationMessageSnapshot[]): void;
125
-
126
- /**
127
- * Delete the journal file (called after a fresh snapshot is written).
128
- * The next appendRecord() will recreate the file with a fresh header.
129
- * Best-effort — silently swallows errors.
130
- */
131
- rotate(): void;
132
-
133
- /** Absolute path to the journal file. */
134
- readonly path: string;
135
-
136
- /**
137
- * Point this journal at a different session's file, resetting the sequence
138
- * counter and initialization flag. Used when the session a journal was
139
- * opened for is switched out from under it (e.g. `/session resume` or
140
- * `/session fork` reassigning `runtime.sessionId`) — without this, the
141
- * journal keeps appending the NEW session's records into the OLD session's
142
- * file. Does not touch the old file on disk; it is simply no longer
143
- * written to.
144
- */
145
- rebind(journalPath: string, sessionId: string): void;
146
- }
147
-
148
- // ─── Factory ────────────────────────────────────────────────────────────────
149
-
150
- /**
151
- * Create a TranscriptJournal for the given session.
152
- *
153
- * The journal file is created lazily on the first appendRecord() call.
154
- * Calling openTranscriptJournal() does not perform any I/O.
155
- */
156
- export function openTranscriptJournal(
157
- journalPath: string,
158
- sessionId: string,
159
- ): TranscriptJournal {
160
- return new TranscriptJournalImpl(journalPath, sessionId);
161
- }
162
-
163
- /**
164
- * Build the canonical journal path for a session.
165
- *
166
- * Both the home directory and the scope segment come off the caller's
167
- * SessionSurface, so the journal lands beside the sessions and recovery
168
- * snapshots it fills gaps for rather than under a separately-spelled scope.
169
- *
170
- * @param surface The app's declare-once session-storage handle.
171
- * @param sessionId The session identifier.
172
- */
173
- export function journalPathFor(surface: SessionSurface, sessionId: string): string {
174
- return join(surface.homeDirectory, '.goodvibes', surface.surfaceRoot, `transcript-${sessionId}.journal`);
175
- }
176
-
177
- /**
178
- * Replay journal records that post-date `snapshotTimestamp`.
179
- *
180
- * Returns an empty result if the journal file does not exist.
181
- * Corrupt tail lines (partial write from a kill) are quarantined; replay
182
- * stops at the first unparseable line.
183
- *
184
- * @param journalPath Absolute path to the journal file.
185
- * @param snapshotTimestamp The `writtenAt` / `timestamp` of the last known
186
- * good snapshot. Only records with ts > this value
187
- * are returned.
188
- */
189
- export function replayJournal(
190
- journalPath: string,
191
- snapshotTimestamp: number,
192
- ): ReplayResult {
193
- if (!existsSync(journalPath)) {
194
- return { records: [], hadCorruptTail: false };
195
- }
196
-
197
- let raw: string;
198
- try {
199
- raw = readFileSync(journalPath, 'utf-8');
200
- } catch {
201
- return { records: [], hadCorruptTail: false };
202
- }
203
-
204
- const lines = raw.split('\n').filter((l) => l.trim().length > 0);
205
- if (lines.length === 0) {
206
- return { records: [], hadCorruptTail: false };
207
- }
208
-
209
- // ── Validate header ─────────────────────────────────────────────────────
210
- let header: unknown;
211
- try {
212
- header = JSON.parse(lines[0]);
213
- } catch {
214
- quarantineJournal(journalPath);
215
- return { records: [], hadCorruptTail: true };
216
- }
217
-
218
- if (
219
- !isPlainObject(header) ||
220
- typeof header['version'] !== 'number' ||
221
- header['version'] !== JOURNAL_SCHEMA_VERSION
222
- ) {
223
- quarantineJournal(journalPath);
224
- return { records: [], hadCorruptTail: true };
225
- }
226
-
227
- // ── Read records ────────────────────────────────────────────────────────
228
- const records: JournalRecord[] = [];
229
- let firstBadLine = -1;
230
-
231
- for (let i = 1; i < lines.length; i++) {
232
- let parsed: unknown;
233
- try {
234
- parsed = JSON.parse(lines[i]);
235
- } catch {
236
- firstBadLine = i;
237
- break;
238
- }
239
-
240
- if (!isValidRecord(parsed)) {
241
- firstBadLine = i;
242
- break;
243
- }
244
-
245
- if (parsed.ts > snapshotTimestamp) {
246
- records.push(parsed);
247
- }
248
- }
249
-
250
- // ── Quarantine corrupt tail ──────────────────────────────────────────────
251
- let hadCorruptTail = false;
252
- if (firstBadLine !== -1) {
253
- hadCorruptTail = true;
254
- // Quarantine the remainder: rename the file. Caller will rotate after
255
- // replay anyway, but we quarantine now so the original file is not
256
- // accidentally replayed again if the process is killed during recovery.
257
- quarantineJournal(journalPath);
258
- }
259
-
260
- // Sort by seq to guarantee ordering in case lines were reordered (they
261
- // should not be, but be defensive).
262
- records.sort((a, b) => a.seq - b.seq);
263
-
264
- return { records, hadCorruptTail };
265
- }
266
-
267
- // ─── Implementation ─────────────────────────────────────────────────────────
268
-
269
- class TranscriptJournalImpl implements TranscriptJournal {
270
- // Not `readonly` at the class level (unlike the public interface) so
271
- // rebind() can repoint it; external callers only ever see it through the
272
- // `TranscriptJournal` interface, which keeps it read-only for them.
273
- path: string;
274
- private _sessionId: string;
275
- private _seq = 0;
276
- private _initialised = false;
277
-
278
- constructor(journalPath: string, sessionId: string) {
279
- this.path = journalPath;
280
- this._sessionId = sessionId;
281
- }
282
-
283
- rebind(journalPath: string, sessionId: string): void {
284
- this.path = journalPath;
285
- this._sessionId = sessionId;
286
- this._seq = 0;
287
- this._initialised = false;
288
- }
289
-
290
- appendRecord(type: JournalEventType, messages: ConversationMessageSnapshot[]): void {
291
- try {
292
- this._ensureInitialised();
293
- const record: JournalRecord = {
294
- type,
295
- seq: this._seq++,
296
- ts: Date.now(),
297
- messages,
298
- };
299
- const line = JSON.stringify(record) + '\n';
300
- appendFileSync(this.path, line, { mode: 0o600 });
301
- // fsync to flush the append to durable storage before returning.
302
- const fd = openSync(this.path, 'r+');
303
- try {
304
- fsyncSync(fd);
305
- } finally {
306
- closeSync(fd);
307
- }
308
- } catch {
309
- // Best-effort — never crash the TUI over a journal failure.
310
- }
311
- }
312
-
313
- rotate(): void {
314
- try {
315
- if (existsSync(this.path)) {
316
- unlinkSync(this.path);
317
- }
318
- this._initialised = false;
319
- this._seq = 0;
320
- } catch {
321
- // Best-effort.
322
- }
323
- }
324
-
325
- private _ensureInitialised(): void {
326
- if (this._initialised && journalHasContent(this.path)) return;
327
-
328
- mkdirSync(dirname(this.path), { recursive: true });
329
- const header: JournalHeader = {
330
- version: JOURNAL_SCHEMA_VERSION,
331
- sessionId: this._sessionId,
332
- createdAt: Date.now(),
333
- };
334
- // Append the header as the first line. If the file already exists with
335
- // content (e.g. process restarted mid-session), we start appending records
336
- // after whatever is already there — the replay function handles seq
337
- // ordering.
338
- //
339
- // The guard is `journalHasContent`, not `existsSync`: a crash between
340
- // creating the file and writing the header leaves a zero-byte journal, and
341
- // an existence-only check would then skip the header forever. Every record
342
- // appended after that would sit in a header-less file, so the next replay
343
- // would read record 0 where the header belongs, fail the version gate, and
344
- // quarantine the entire journal — losing exactly the turns this module
345
- // exists to preserve. Deciding on content instead means a zero-byte
346
- // journal is re-headered and stays replayable.
347
- if (!journalHasContent(this.path)) {
348
- appendFileSync(this.path, JSON.stringify(header) + '\n', { mode: 0o600 });
349
- }
350
- this._initialised = true;
351
- }
352
- }
353
-
354
- // ─── Internal helpers ────────────────────────────────────────────────────────
355
-
356
- function isPlainObject(value: unknown): value is Record<string, unknown> {
357
- return typeof value === 'object' && value !== null && !Array.isArray(value);
358
- }
359
-
360
- function isValidRecord(value: unknown): value is JournalRecord {
361
- if (!isPlainObject(value)) return false;
362
- const v = value as Record<string, unknown>;
363
- return (
364
- typeof v['type'] === 'string' &&
365
- typeof v['seq'] === 'number' &&
366
- typeof v['ts'] === 'number' &&
367
- Array.isArray(v['messages'])
368
- );
369
- }
370
-
371
- function quarantineJournal(journalPath: string): void {
372
- try {
373
- renameSync(journalPath, `${journalPath}${UNRECOGNIZED_SUFFIX}`);
374
- } catch {
375
- // Best-effort — if rename fails, proceed silently.
376
- }
377
- }
378
-
379
- /** True when the journal file exists AND holds at least one byte. */
380
- function journalHasContent(journalPath: string): boolean {
381
- try {
382
- return statSync(journalPath).size > 0;
383
- } catch {
384
- return false;
385
- }
386
- }
387
-
388
- // ─── Reaping orphaned journals ──────────────────────────────────────────────
389
- //
390
- // `rotate()` deletes a journal once its records have been folded into a
391
- // snapshot or replayed. A session that crashes and is never resumed never
392
- // reaches either, so its journal stays on disk forever — one file per
393
- // abandoned session. The SDK's registered append-only retention sweep does not
394
- // cover this home-scoped path, so the reclaim happens here.
395
-
396
- const JOURNAL_PREFIX = 'transcript-';
397
- const JOURNAL_SUFFIX = '.journal';
398
-
399
- /** How long an untouched journal for a non-live session is kept: 7 days. */
400
- export const JOURNAL_ORPHAN_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
401
-
402
- /**
403
- * Hard ceiling on reapable journals kept after the age rule, newest kept.
404
- * A burst of crashes inside the age window is still bounded.
405
- */
406
- export const JOURNAL_ORPHAN_MAX_FILES = 50;
407
-
408
- export interface JournalReapResult {
409
- /** Journal files examined this sweep. */
410
- readonly scanned: number;
411
- /** Journal files deleted this sweep. */
412
- readonly reaped: number;
413
- }
414
-
415
- export interface JournalReapOptions {
416
- /**
417
- * Is this session open in a still-running process? Injected rather than
418
- * imported so this module keeps no dependency on the liveness marker — the
419
- * composition point (runtime/durability-housekeeping.ts) supplies the real
420
- * check, and tests supply their own.
421
- */
422
- readonly isSessionLive: (sessionId: string) => boolean;
423
- /** The session this process is writing right now; never reaped. */
424
- readonly currentSessionId?: string | null;
425
- readonly now?: () => number;
426
- /** Override the age window (tests). */
427
- readonly maxAgeMs?: number;
428
- /** Override the count cap (tests). */
429
- readonly maxFiles?: number;
430
- }
431
-
432
- /**
433
- * Delete transcript journals belonging to sessions that crashed and were never
434
- * resumed.
435
- *
436
- * A journal is reapable only when it is neither the current session's nor
437
- * apparently open in another running process. Of those, one is deleted when it
438
- * is empty (a zero-byte file holds no records, so nothing can be lost) or
439
- * untouched for longer than the age window; whatever survives both rules is
440
- * then capped by count, newest kept.
441
- *
442
- * The rules are deliberately mtime- and liveness-based, never parse-based: an
443
- * unparseable TAIL is the normal, expected shape of a journal killed
444
- * mid-append and is exactly the data replay is there to salvage, so a parse
445
- * failure must never make a journal reapable.
446
- *
447
- * Idempotent and concurrency-safe: a journal another sweeper unlinked between
448
- * the listing and this unlink (ENOENT) counts as reaped, not as an error.
449
- */
450
- export function reapOrphanedJournals(surface: SessionSurface, options: JournalReapOptions): JournalReapResult {
451
- const dir = join(surface.homeDirectory, '.goodvibes', surface.surfaceRoot);
452
- let names: string[];
453
- try {
454
- names = readdirSync(dir).filter((n) => n.startsWith(JOURNAL_PREFIX) && n.endsWith(JOURNAL_SUFFIX));
455
- } catch {
456
- return { scanned: 0, reaped: 0 };
457
- }
458
-
459
- const now = options.now?.() ?? Date.now();
460
- const maxAgeMs = options.maxAgeMs ?? JOURNAL_ORPHAN_MAX_AGE_MS;
461
- const maxFiles = options.maxFiles ?? JOURNAL_ORPHAN_MAX_FILES;
462
-
463
- let reaped = 0;
464
- const survivors: { readonly path: string; readonly mtimeMs: number }[] = [];
465
-
466
- for (const name of names) {
467
- const sessionId = name.slice(JOURNAL_PREFIX.length, name.length - JOURNAL_SUFFIX.length);
468
- if (sessionId.length === 0) continue;
469
- if (options.currentSessionId && sessionId === options.currentSessionId) continue;
470
- if (options.isSessionLive(sessionId)) continue;
471
-
472
- const path = join(dir, name);
473
- let stats: { size: number; mtimeMs: number };
474
- try {
475
- stats = statSync(path);
476
- } catch {
477
- continue; // vanished under us
478
- }
479
- if (stats.size === 0 || now - stats.mtimeMs > maxAgeMs) {
480
- if (unlinkJournalIfPresent(path)) reaped++;
481
- continue;
482
- }
483
- survivors.push({ path, mtimeMs: stats.mtimeMs });
484
- }
485
-
486
- if (survivors.length > maxFiles) {
487
- survivors.sort((a, b) => a.mtimeMs - b.mtimeMs); // oldest first
488
- for (const victim of survivors.slice(0, survivors.length - maxFiles)) {
489
- if (unlinkJournalIfPresent(victim.path)) reaped++;
490
- }
491
- }
492
-
493
- return { scanned: names.length, reaped };
494
- }
495
-
496
- function unlinkJournalIfPresent(path: string): boolean {
497
- try {
498
- unlinkSync(path);
499
- return true;
500
- } catch (err) {
501
- return (err as NodeJS.ErrnoException | undefined)?.code === 'ENOENT';
502
- }
503
- }