@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,88 +0,0 @@
1
- /**
2
- * Config system barrel export.
3
- *
4
- * Provides:
5
- * - ConfigManager class and all schema types
6
- * - Pure helpers that derive values from an explicit ConfigManager instance
7
- */
8
-
9
- export { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
10
- export type { DeepReadonly } from '@pellux/goodvibes-sdk/platform/config';
11
- export type { GoodVibesConfig, ConfigKey, ConfigValue, ConfigSetting, PermissionMode, PermissionAction, PermissionsToolConfig, NotificationsConfig } from '@pellux/goodvibes-sdk/platform/config';
12
- export { DEFAULT_CONFIG, CONFIG_SCHEMA } from '@pellux/goodvibes-sdk/platform/config';
13
- export { ConfigError } from '@pellux/goodvibes-sdk/platform/types';
14
-
15
- import { readFileSync } from 'fs';
16
- import { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
17
- import type { GoodVibesConfig } from '@pellux/goodvibes-sdk/platform/config';
18
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
19
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
20
- import { getProviderIdFromModel } from './provider-model.ts';
21
-
22
- export function getConfigSnapshot(configManager: Pick<ConfigManager, 'getRaw'>): Readonly<GoodVibesConfig> {
23
- return configManager.getRaw();
24
- }
25
-
26
- export function getConfiguredModelId(configManager: Pick<ConfigManager, 'get'>): string {
27
- return configManager.get('provider.model');
28
- }
29
-
30
- export function getConfiguredProviderId(configManager: Pick<ConfigManager, 'get'>): string {
31
- return getProviderIdFromModel(configManager.get('provider.model'));
32
- }
33
-
34
- export function getConfiguredEmbeddingProviderId(configManager: Pick<ConfigManager, 'get'>): string {
35
- return configManager.get('provider.embeddingProvider');
36
- }
37
-
38
- export function isAutoApproveEnabled(configManager: Pick<ConfigManager, 'get'>): boolean {
39
- return configManager.get('behavior.autoApprove');
40
- }
41
-
42
- /**
43
- * True when the current permission posture effectively auto-approves everything:
44
- * auto-approve on, permission mode `allow-all`, or a `custom` mode whose every
45
- * tool action is `allow`. Drives the footer's danger indicator.
46
- */
47
- export function isEffectiveDangerMode(configManager: Pick<ConfigManager, 'get' | 'getCategory'>): boolean {
48
- if (configManager.get('behavior.autoApprove')) return true;
49
- const permMode = configManager.get('permissions.mode');
50
- if (permMode === 'allow-all') return true;
51
- if (permMode === 'custom') {
52
- const tools = configManager.getCategory('permissions').tools;
53
- if (Object.values(tools).every((action) => action === 'allow')) return true;
54
- }
55
- return false;
56
- }
57
-
58
- export function getWorkingDirectory(configManager: Pick<ConfigManager, 'getWorkingDirectory'>): string | null {
59
- return configManager.getWorkingDirectory();
60
- }
61
-
62
- export function getConfiguredSystemPrompt(configManager: Pick<ConfigManager, 'get'>): string | undefined {
63
- const file = configManager.get('provider.systemPromptFile');
64
- if (!file) return undefined;
65
- try {
66
- return readFileSync(file, 'utf-8');
67
- } catch (err) {
68
- logger.debug('systemPrompt file read failed (non-fatal)', { file, error: summarizeError(err) });
69
- return undefined;
70
- }
71
- }
72
-
73
- export { getConfiguredApiKeys, resolveApiKeys } from '@pellux/goodvibes-sdk/platform/config';
74
-
75
- // Client-side credential-status read (honest-degrade, status-only). When the
76
- // TUI acts as a client of an adopted external daemon it reads provider/model/secret
77
- // STATUS from that daemon's `credentials.get`, never from its own surfaceRoot store.
78
- export {
79
- credentialReadModeFromHostMode,
80
- deriveCredentialAvailability,
81
- readClientCredentialStatus,
82
- } from './credential-availability.ts';
83
- export type {
84
- CredentialAvailability,
85
- CredentialReadMode,
86
- CredentialStatusEntry,
87
- CredentialStatusOutcome,
88
- } from './credential-availability.ts';
@@ -1,23 +0,0 @@
1
- import { DEFAULT_CONFIG } from '@pellux/goodvibes-sdk/platform/config';
2
-
3
- export function getProviderIdFromModel(model: unknown): string {
4
- const raw = String(model ?? '').trim();
5
- if (!raw) return getProviderIdFromModel(DEFAULT_CONFIG.provider.model);
6
- const separator = raw.indexOf(':');
7
- return separator > 0 ? raw.slice(0, separator) : raw;
8
- }
9
-
10
- export function getModelIdFromProviderModel(model: unknown): string {
11
- const raw = String(model ?? '').trim();
12
- if (!raw) return String(DEFAULT_CONFIG.provider.model);
13
- const separator = raw.indexOf(':');
14
- return separator > 0 ? raw.slice(separator + 1) : raw;
15
- }
16
-
17
- export function formatProviderModel(providerId: string, modelId: string): string {
18
- const provider = providerId.trim();
19
- const model = modelId.trim();
20
- if (!provider) return model;
21
- if (!model) return `${provider}:`;
22
- return model.includes(':') ? model : `${provider}:${model}`;
23
- }
@@ -1,228 +0,0 @@
1
- import { existsSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync } from 'node:fs';
2
- import { join } from 'node:path';
3
-
4
- /**
5
- * The suffix every quarantined file in this codebase gets. Exported so the
6
- * other producer of these files (the transcript journal's corrupt-tail
7
- * quarantine) and the reclaim sweep below all agree on one spelling.
8
- */
9
- export const UNRECOGNIZED_SUFFIX = '.unrecognized';
10
-
11
- /**
12
- * A migration function that transforms data from version N to N+1.
13
- * Receives the raw parsed object and must return the upgraded object.
14
- */
15
- export type VersionMigration = (data: Record<string, unknown>) => Record<string, unknown>;
16
-
17
- export interface ReadVersionedOptions {
18
- /**
19
- * The version number this reader expects. When the file version equals
20
- * `currentVersion`, no migrations are run. When it is lower, migrations
21
- * are applied stepwise. When it is higher or unrecognised, `onUnknown`
22
- * behaviour fires.
23
- */
24
- readonly currentVersion: number;
25
-
26
- /**
27
- * Optional stepwise migrations indexed by the FROM version.
28
- * `migrations[1]` upgrades version-1 data to version-2 data.
29
- * Applied in ascending order until `currentVersion` is reached.
30
- */
31
- readonly migrations?: Readonly<Record<number, VersionMigration>>;
32
-
33
- /**
34
- * What to do when the file version is unrecognised (higher than
35
- * `currentVersion` or missing/non-numeric).
36
- *
37
- * `'quarantine'` — rename the file to `<path>.unrecognized` and return null.
38
- */
39
- readonly onUnknown: 'quarantine';
40
- }
41
-
42
- /**
43
- * Migration-aware, quarantine-on-failure versioned file reader.
44
- *
45
- * Parse flow:
46
- * 1. If the file does not exist → return null.
47
- * 2. If JSON is corrupt → quarantine to `<path>.unrecognized`, return null.
48
- * 3. If the version field is missing or higher than currentVersion →
49
- * quarantine, return null.
50
- * 4. If the version is lower than currentVersion → apply stepwise migrations.
51
- * If no migration exists for a version gap, or a migration throws,
52
- * quarantine and return null.
53
- * 5. Return the (possibly migrated) object. Callers are responsible for
54
- * narrowing the returned value — this helper handles versioning and
55
- * corruption only, not schema validation.
56
- */
57
- export function readVersioned<T extends { version: number }>(
58
- path: string,
59
- options: ReadVersionedOptions,
60
- ): T | null {
61
- if (!existsSync(path)) return null;
62
-
63
- let raw: unknown;
64
- try {
65
- raw = JSON.parse(readFileSync(path, 'utf-8'));
66
- } catch {
67
- quarantine(path);
68
- return null;
69
- }
70
-
71
- if (!isPlainObject(raw)) {
72
- quarantine(path);
73
- return null;
74
- }
75
-
76
- const fileVersion = raw['version'];
77
- if (typeof fileVersion !== 'number' || !Number.isFinite(fileVersion)) {
78
- quarantine(path);
79
- return null;
80
- }
81
-
82
- if (fileVersion > options.currentVersion) {
83
- // Produced by a newer process — quarantine rather than corrupt.
84
- quarantine(path);
85
- return null;
86
- }
87
-
88
- let data: Record<string, unknown> = raw;
89
-
90
- if (fileVersion < options.currentVersion) {
91
- const migrations = options.migrations ?? {};
92
- for (let v = fileVersion; v < options.currentVersion; v++) {
93
- const migrate = migrations[v];
94
- if (!migrate) {
95
- // No migration path for this version gap — quarantine.
96
- quarantine(path);
97
- return null;
98
- }
99
- try {
100
- data = migrate(data);
101
- } catch {
102
- quarantine(path);
103
- return null;
104
- }
105
- }
106
- }
107
-
108
- return data as T;
109
- }
110
-
111
- // ─── Internal helpers ─────────────────────────────────────────────────────────
112
-
113
- function isPlainObject(value: unknown): value is Record<string, unknown> {
114
- return typeof value === 'object' && value !== null && !Array.isArray(value);
115
- }
116
-
117
- function quarantine(path: string): void {
118
- try {
119
- renameSync(path, `${path}${UNRECOGNIZED_SUFFIX}`);
120
- } catch {
121
- // Best-effort — if rename fails (e.g. race), proceed silently.
122
- }
123
- }
124
-
125
- // ─── Quarantine reclaim ───────────────────────────────────────────────────────
126
- //
127
- // Quarantining renames a bad file out of the way so a human can inspect it,
128
- // and until now nothing ever removed the result — every corrupt config file
129
- // and every torn journal tail left a `.unrecognized` file behind permanently.
130
- // Forensic value is real, so the retention window below is deliberately long,
131
- // but "keep forever" is a leak.
132
-
133
- /**
134
- * How long a quarantined file is kept before it is reclaimed: 30 days
135
- * (2_592_000_000 ms). These files exist so a person can look at what went
136
- * wrong, so the window is a month rather than the hours-to-days retention the
137
- * live durability artefacts get — long enough to survive a holiday, short
138
- * enough that a recurring corruption cannot fill a disk.
139
- */
140
- export const QUARANTINE_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
141
-
142
- /**
143
- * Hard ceiling on quarantined files kept per swept directory, newest kept.
144
- * The age rule alone cannot bound a fast repeating corruption (a boot loop
145
- * quarantining the same file every restart), so a count cap runs alongside it.
146
- */
147
- export const QUARANTINE_MAX_FILES_PER_DIR = 50;
148
-
149
- export interface QuarantineReapResult {
150
- /** Quarantined files examined across every directory. */
151
- readonly scanned: number;
152
- /** Quarantined files deleted. */
153
- readonly reaped: number;
154
- }
155
-
156
- export interface QuarantineReapOptions {
157
- readonly now?: () => number;
158
- /** Override the age window (tests). */
159
- readonly maxAgeMs?: number;
160
- /** Override the per-directory count cap (tests). */
161
- readonly maxFilesPerDir?: number;
162
- }
163
-
164
- /**
165
- * Delete `.unrecognized` quarantine files that are past the retention window,
166
- * plus any beyond the per-directory count cap (newest kept).
167
- *
168
- * Each directory is scanned non-recursively; a missing or unreadable directory
169
- * contributes nothing and is not an error. Idempotent, and safe to run
170
- * concurrently from several processes — a file another sweeper already
171
- * unlinked (ENOENT) counts as reclaimed rather than failing the sweep.
172
- */
173
- export function reapQuarantinedFiles(
174
- directories: readonly string[],
175
- options: QuarantineReapOptions = {},
176
- ): QuarantineReapResult {
177
- const now = options.now?.() ?? Date.now();
178
- const maxAgeMs = options.maxAgeMs ?? QUARANTINE_RETENTION_MS;
179
- const maxFilesPerDir = options.maxFilesPerDir ?? QUARANTINE_MAX_FILES_PER_DIR;
180
-
181
- let scanned = 0;
182
- let reaped = 0;
183
-
184
- for (const dir of new Set(directories)) {
185
- let names: string[];
186
- try {
187
- names = readdirSync(dir).filter((name) => name.endsWith(UNRECOGNIZED_SUFFIX));
188
- } catch {
189
- continue;
190
- }
191
- scanned += names.length;
192
-
193
- const survivors: { readonly path: string; readonly mtimeMs: number }[] = [];
194
- for (const name of names) {
195
- const path = join(dir, name);
196
- let mtimeMs: number;
197
- try {
198
- mtimeMs = statSync(path).mtimeMs;
199
- } catch {
200
- // Vanished under us (another sweeper) — nothing left to reclaim.
201
- continue;
202
- }
203
- if (now - mtimeMs > maxAgeMs) {
204
- if (unlinkQuarantined(path)) reaped++;
205
- continue;
206
- }
207
- survivors.push({ path, mtimeMs });
208
- }
209
-
210
- if (survivors.length > maxFilesPerDir) {
211
- survivors.sort((a, b) => a.mtimeMs - b.mtimeMs); // oldest first
212
- for (const victim of survivors.slice(0, survivors.length - maxFilesPerDir)) {
213
- if (unlinkQuarantined(victim.path)) reaped++;
214
- }
215
- }
216
- }
217
-
218
- return { scanned, reaped };
219
- }
220
-
221
- function unlinkQuarantined(path: string): boolean {
222
- try {
223
- unlinkSync(path);
224
- return true;
225
- } catch (err) {
226
- return (err as NodeJS.ErrnoException | undefined)?.code === 'ENOENT';
227
- }
228
- }
@@ -1,67 +0,0 @@
1
- /**
2
- * alert-gating — shared config + focus gating logic for the unfocused-user
3
- * alert classes (budget-breach, long-task, agent/chain failure,
4
- * awaiting-approval). Each alert class has its own on/off config key
5
- * (default true); a single master key, `behavior.notifyOnlyWhenUnfocused`
6
- * (default true), decides whether any of them additionally require the
7
- * terminal to be unfocused-or-unknown before firing.
8
- *
9
- * Extracted so every alert-class module (long-task-notifier.ts,
10
- * budget-breach-notifier.ts, approval-alert.ts, and the agent/chain-failure
11
- * wiring in turn-event-wiring.ts) shares one implementation of "should this
12
- * fire right now" instead of re-deriving the same two config reads and the
13
- * same focus check.
14
- */
15
- import type { FocusTracker } from './focus-tracker.ts';
16
-
17
- /** Minimal config-read surface every gating check needs. */
18
- export type ConfigGet = (key: string) => unknown;
19
-
20
- /** Read a TUI-local synthetic boolean setting, defaulting when absent/invalid. */
21
- export function readBooleanConfig(configGet: ConfigGet, key: string, defaultValue: boolean): boolean {
22
- const raw = configGet(key);
23
- if (typeof raw === 'boolean') return raw;
24
- if (raw === undefined || raw === null) return defaultValue;
25
- // Tolerate string/number forms the same way the rest of the config layer does
26
- // (settings-modal writes real booleans, but env/file edits may not).
27
- if (raw === 'true' || raw === 1) return true;
28
- if (raw === 'false' || raw === 0) return false;
29
- return defaultValue;
30
- }
31
-
32
- /** `behavior.notifyOnlyWhenUnfocused` — master gate, default on. */
33
- export function readNotifyOnlyWhenUnfocused(configGet: ConfigGet): boolean {
34
- return readBooleanConfig(configGet, 'behavior.notifyOnlyWhenUnfocused', true);
35
- }
36
-
37
- /**
38
- * Decide whether a given alert class should fire right now.
39
- *
40
- * `classConfigKey` is the per-class on/off switch (e.g.
41
- * 'behavior.notifyOnBudgetBreach'); default true when absent. When that key
42
- * is off, the class never fires regardless of focus. When it's on, the
43
- * result additionally depends on the master `notifyOnlyWhenUnfocused` gate:
44
- * if that master gate is off, the class fires unconditionally (today's
45
- * pre-focus-tracking behavior); if on (the default), it only fires when the
46
- * terminal is unfocused or focus state was never observed (see
47
- * FocusTracker.shouldAlertWhenUnfocused).
48
- */
49
- export function shouldFireAlert(
50
- focusTracker: Pick<FocusTracker, 'shouldAlertWhenUnfocused'>,
51
- configGet: ConfigGet,
52
- classConfigKey: string,
53
- ): boolean {
54
- if (!readBooleanConfig(configGet, classConfigKey, true)) return false;
55
- if (!readNotifyOnlyWhenUnfocused(configGet)) return true;
56
- return focusTracker.shouldAlertWhenUnfocused();
57
- }
58
-
59
- /**
60
- * notifyCompletion (SDK platform/utils) only rings the bell above 5s of
61
- * "duration" and only pops a desktop notification above 30s — a heuristic
62
- * tuned for long-running-turn notifications. The alert classes in this
63
- * directory are point-in-time events with no natural duration, so they pass
64
- * this constant as the `durationMs` argument to force both the bell and the
65
- * desktop popup unconditionally.
66
- */
67
- export const FORCE_NOTIFY_DURATION_MS = 30_001;
@@ -1,41 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // consolidation-receipt.ts — the one-line notice for an idle-time memory
3
- // consolidation run.
4
- //
5
- // The SDK's MemoryConsolidationScheduler runs at idle and produces a
6
- // MemoryConsolidationRunReceipt (merged / archived / decayed / proposed). This
7
- // formats it into the same one-line shape every other attach-time receipt
8
- // uses, so a run that changed something surfaces on the next attach like a
9
- // crash/update/migration receipt. A pure no-op run yields null — no noise.
10
- //
11
- // A run that PROPOSED something (a contradiction or cross-scope-duplicate
12
- // awaiting human judgment — never auto-applied) names where to actually look:
13
- // the Memory modal's Proposals tab (`/memory`, then the Proposals tab —
14
- // memory-modal.ts's proposalsTab()), which lists each proposal's kind,
15
- // reason, and affected record ids and jumps to them in the Review Queue.
16
- // Without this pointer the receipt line was the only trace a proposal ever
17
- // existed — a count with nowhere to go.
18
- // ---------------------------------------------------------------------------
19
-
20
- import type { MemoryConsolidationRunReceipt } from '@pellux/goodvibes-sdk/platform/state';
21
-
22
- /**
23
- * A one-line receipt for a consolidation run that changed something, or null
24
- * when the run merged/archived/decayed/proposed nothing (a quiet idle pass —
25
- * no notice, matching the check-in "stayed quiet" discipline).
26
- */
27
- export function formatConsolidationReceipt(receipt: MemoryConsolidationRunReceipt): string | null {
28
- const merged = receipt.merged.length;
29
- const archived = receipt.archived.length;
30
- const decayed = receipt.decayed.length;
31
- const proposed = receipt.proposed.length;
32
- if (merged + archived + decayed + proposed === 0) return null;
33
- const parts: string[] = [];
34
- if (merged) parts.push(`${merged} merged`);
35
- if (archived) parts.push(`${archived} archived`);
36
- if (decayed) parts.push(`${decayed} decayed`);
37
- if (proposed) parts.push(`${proposed} proposed`);
38
- const base = `Memory consolidation: ${parts.join(', ')} (scanned ${receipt.scanned}).`;
39
- if (proposed === 0) return base;
40
- return `${base} Review the ${proposed} proposed change${proposed === 1 ? '' : 's'} with /memory (Proposals tab).`;
41
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * focus-tracker — tracks whether the terminal window currently has OS-level
3
- * input focus, using the terminal focus-reporting protocol (DECSET ?1004h,
4
- * enabled at terminal setup in main.ts). The SDK's InputTokenizer already
5
- * parses the resulting `\x1b[I` (focus-in) / `\x1b[O` (focus-out) sequences
6
- * into `{ type: 'focus', action }` tokens (platform/core/tokenizer.ts); this
7
- * module is the single place those tokens land (consumed in
8
- * src/input/handler-feed.ts's feedInputTokens()).
9
- *
10
- * Honest degradation: a terminal that does not implement focus reporting
11
- * (or a multiplexer that swallows the sequences) never sends focus tokens.
12
- * In that case `isFocused()` stays `null` forever — "unknown", never a
13
- * guessed `true`/`false`. Callers that gate a user-facing behavior on focus
14
- * (e.g. the unfocused-alert notifiers in this directory) must treat `null`
15
- * the same as "not focused" per the fallback rule: alerts fire when the
16
- * terminal is definitely unfocused OR when focus state was never observed.
17
- */
18
- export class FocusTracker {
19
- private focused: boolean | null = null;
20
-
21
- /** True/false once at least one focus token has arrived; null if none ever has. */
22
- isFocused(): boolean | null {
23
- return this.focused;
24
- }
25
-
26
- /** Called from the input pipeline on every focus token. */
27
- setFocused(value: boolean): void {
28
- this.focused = value;
29
- }
30
-
31
- /**
32
- * The alert-gating rule shared by every unfocused-alert notifier: fire
33
- * when the terminal is known to be unfocused, or when focus was never
34
- * observed (honest fallback — never silently suppress on an unknown
35
- * terminal). Only `isFocused() === true` (a real, observed focus-in with
36
- * no observed focus-out since) suppresses an alert.
37
- */
38
- shouldAlertWhenUnfocused(): boolean {
39
- return this.focused !== true;
40
- }
41
- }
@@ -1,45 +0,0 @@
1
- import { type Line, createEmptyLine } from '../types/grid.ts';
2
-
3
- /**
4
- * InfiniteBuffer - Manages the complete conversation history as a list of lines.
5
- */
6
- export class InfiniteBuffer {
7
- private lines: Line[] = [];
8
-
9
- public addLine(line: Line): void {
10
- this.lines.push(line);
11
- }
12
-
13
- public addLines(lines: Line[]): void {
14
- this.lines.push(...lines);
15
- }
16
-
17
- public getLineCount(): number {
18
- return this.lines.length;
19
- }
20
-
21
- public getAllLines(): Line[] {
22
- return this.lines;
23
- }
24
-
25
- public getSnapshot(startLine: number, height: number, width: number): Line[] {
26
- const end = Math.min(this.lines.length, startLine + height);
27
- const slice = this.lines.slice(startLine, end);
28
-
29
- while (slice.length < height) {
30
- slice.unshift(createEmptyLine(width));
31
- }
32
-
33
- return slice;
34
- }
35
-
36
- public clear(): void {
37
- this.lines = [];
38
- }
39
-
40
- public truncateToLine(lineIndex: number): void {
41
- if (lineIndex >= 0 && lineIndex < this.lines.length) {
42
- this.lines.length = lineIndex;
43
- }
44
- }
45
- }
@@ -1,118 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // memory-status.ts — the surface-facing projection of the daemon's memory
3
- // governance (ops.memory.get + OPS_MEMORY_PRESSURE).
4
- //
5
- // The SDK's MemoryGovernor owns the policy: it samples RSS/heap against a
6
- // budget, sheds memory by tier (trimming registered caches, pausing deferrable
7
- // background jobs), refuses new expensive work at the critical tier, and trips
8
- // on a genuine leak before the OS OOM-kills it. This module is the read-only
9
- // projection the /health memory (doctor) surface renders from — the snapshot
10
- // rows — and the attention line OPS_MEMORY_PRESSURE produces when the tier
11
- // changes or the tripwire fires.
12
- //
13
- // Pure formatting only (no I/O): the command fetches the typed verb response
14
- // over the operator invoke seam (memory-diagnostics-gateway.ts) and hands it
15
- // here, so these builders are unit-testable against fixture shapes.
16
- // ---------------------------------------------------------------------------
17
-
18
- import type { OperatorMethodOutput } from '@pellux/goodvibes-sdk';
19
- import type { OpsEvent } from '@/runtime/index.ts';
20
-
21
- /** ops.memory.get output — the full governor snapshot. */
22
- export type MemoryGovernorSnapshotResult = OperatorMethodOutput<'ops.memory.get'>;
23
- /** The OPS_MEMORY_PRESSURE event payload (a tier change or a tripwire firing). */
24
- export type MemoryPressurePayload = Extract<OpsEvent, { type: 'OPS_MEMORY_PRESSURE' }>;
25
-
26
- /** Human MB (the governor already reports MB as numbers; round to 1 decimal). */
27
- export function formatMb(mb: number | null | undefined): string {
28
- if (mb === null || mb === undefined || !Number.isFinite(mb)) return 'unknown';
29
- return `${mb >= 100 ? Math.round(mb) : Math.round(mb * 10) / 10} MB`;
30
- }
31
-
32
- /** Human byte size for a cache footprint estimate. */
33
- export function formatMemoryBytes(bytes: number | null | undefined): string {
34
- if (bytes === null || bytes === undefined || !Number.isFinite(bytes) || bytes < 0) return 'size n/a';
35
- if (bytes < 1024) return `${bytes} B`;
36
- const units = ['KB', 'MB', 'GB'];
37
- let value = bytes / 1024;
38
- let unit = 0;
39
- while (value >= 1024 && unit < units.length - 1) {
40
- value /= 1024;
41
- unit += 1;
42
- }
43
- return `${value >= 10 ? value.toFixed(0) : value.toFixed(1)} ${units[unit]}`;
44
- }
45
-
46
- /** A plain-language note for the current tier (the governor's posture at this tier). */
47
- export function memoryTierNote(tier: MemoryGovernorSnapshotResult['tier']): string {
48
- switch (tier) {
49
- case 'normal': return 'footprint is comfortably within budget';
50
- case 'elevated': return 'trimming caches to a floor and running gc';
51
- case 'high': return 'flushing caches and pausing deferrable background jobs';
52
- case 'critical': return 'refusing new expensive work until the footprint recovers';
53
- default: return '';
54
- }
55
- }
56
-
57
- /**
58
- * The /health memory (doctor) rows — the honest account of the daemon defending
59
- * its footprint. Order: tier + posture, budget vs RSS, heap, tier thresholds,
60
- * per-cache footprints the governor can shrink, which deferrable jobs are
61
- * paused, and the leak-tripwire state.
62
- */
63
- export function memoryStatusLines(snapshot: MemoryGovernorSnapshotResult): string[] {
64
- const lines: string[] = [];
65
- lines.push(` tier: ${snapshot.tier} — ${memoryTierNote(snapshot.tier)}`);
66
- if (snapshot.refusingExpensiveWork) {
67
- lines.push(' expensive work: REFUSED (critical tier) — new ingestion / reindex / voice install is declined until RSS recovers');
68
- }
69
- lines.push(` budget: ${formatMb(snapshot.rssMb)} rss / ${formatMb(snapshot.budgetMb)} budget (${Math.round(snapshot.usedPct)}%)`);
70
- const heap = snapshot.heapTotalMb !== undefined
71
- ? `${formatMb(snapshot.heapUsedMb)} used / ${formatMb(snapshot.heapTotalMb)} total`
72
- : formatMb(snapshot.heapUsedMb);
73
- lines.push(` heap: ${heap}`);
74
- lines.push(` tiers: elevated ${snapshot.thresholds.elevatedPct}% · high ${snapshot.thresholds.highPct}% · critical ${snapshot.thresholds.criticalPct}%`);
75
-
76
- if (snapshot.caches.length === 0) {
77
- lines.push(' caches: none registered');
78
- } else {
79
- lines.push(` caches: ${snapshot.caches.length}`);
80
- for (const cache of snapshot.caches) {
81
- const size = cache.estimatedBytes !== undefined ? `, ~${formatMemoryBytes(cache.estimatedBytes)}` : '';
82
- lines.push(` ${cache.id} (${cache.name}): ${cache.entries} entries${size}`);
83
- }
84
- }
85
-
86
- lines.push(snapshot.pausedJobs.length === 0
87
- ? ' paused jobs: none'
88
- : ` paused jobs: ${snapshot.pausedJobs.join(', ')}`);
89
-
90
- if (snapshot.tripwire.armed) {
91
- lines.push(` tripwire: ARMED — watching for a sustained >${snapshot.tripwire.rateMbPerSec} MB/s post-flush leak (held ${Math.round(snapshot.tripwire.sustainedSec)}s)`);
92
- } else {
93
- lines.push(' tripwire: disarmed (no post-flush leak growth under watch)');
94
- }
95
- return lines;
96
- }
97
-
98
- /**
99
- * The attention line OPS_MEMORY_PRESSURE produces: a one-liner naming the new
100
- * tier and the RSS/budget, plus a distinct escalation when the leak tripwire
101
- * fires (the daemon is about to exit for a clean supervisor restart). Returned
102
- * as a single string so the notice/attention surface can push it directly.
103
- */
104
- export function memoryPressureLine(event: MemoryPressurePayload): string {
105
- const base = `memory pressure: ${event.previousTier} → ${event.tier} (${formatMb(event.rssMb)} rss / ${formatMb(event.budgetMb)} budget, ${Math.round(event.usedPct)}%)`;
106
- if (event.tripwire) {
107
- return `${base} — leak tripwire fired (${event.tripwire.rateMbPerSec} MB/s sustained ${Math.round(event.tripwire.sustainedSec)}s); the daemon will exit for a clean restart`;
108
- }
109
- if (event.note) return `${base} — ${event.note}`;
110
- return base;
111
- }
112
-
113
- /** Severity for the notice feed: critical tier (or a tripwire) is critical; high is a warning. */
114
- export function memoryPressureLevel(event: MemoryPressurePayload): 'info' | 'warning' | 'critical' {
115
- if (event.tripwire || event.tier === 'critical') return 'critical';
116
- if (event.tier === 'high') return 'warning';
117
- return 'info';
118
- }
@@ -1,7 +0,0 @@
1
- // Thin TUI wrapper — re-exports the SDK Orchestrator unchanged.
2
- // The SDK class already contains all behaviour including getSpinner().
3
- export {
4
- Orchestrator,
5
- type OrchestratorOptions,
6
- type OrchestratorUserInputOptions,
7
- } from '@pellux/goodvibes-sdk/platform/core';