@pellux/goodvibes-tui 2.0.13 → 2.0.15

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 (464) hide show
  1. package/.goodvibes/GOODVIBES.md +1 -1
  2. package/.goodvibes/agents/reviewer.md +8 -8
  3. package/.goodvibes/skills/add-provider/SKILL.md +22 -22
  4. package/CHANGELOG.md +61 -0
  5. package/README.md +40 -29
  6. package/docs/README.md +1 -1
  7. package/docs/foundation-artifacts/README.md +5 -5
  8. package/docs/foundation-artifacts/operator-contract.json +123 -123
  9. package/package.json +12 -10
  10. package/scripts/postinstall.js +3 -3
  11. package/src/audio/activation-sound.ts +7 -7
  12. package/src/audio/capture.ts +7 -7
  13. package/src/audio/onnxruntime-assets.d.ts +1 -1
  14. package/src/audio/player.ts +4 -4
  15. package/src/audio/spoken-turn-wiring.ts +4 -4
  16. package/src/audio/voice-capture-wiring.ts +5 -5
  17. package/src/audio/voice-input-session.ts +3 -3
  18. package/src/audio/wake-inference.ts +13 -8
  19. package/src/audio/wake-runtime.ts +10 -10
  20. package/src/cli/completions/generate.ts +2 -2
  21. package/src/cli/doctor.ts +13 -13
  22. package/src/cli/ensure-goodvibes-gitignore.ts +3 -3
  23. package/src/cli/entrypoint.ts +3 -3
  24. package/src/cli/help.ts +6 -6
  25. package/src/cli/hooks-command.ts +4 -4
  26. package/src/cli/hooks-report.ts +4 -4
  27. package/src/cli/launch-auto-update.ts +17 -17
  28. package/src/cli/management-commands.ts +8 -8
  29. package/src/cli/management-utils.ts +3 -3
  30. package/src/cli/management.ts +1 -1
  31. package/src/cli/plugin-bundles-command.ts +10 -10
  32. package/src/cli/plugin-command.ts +9 -9
  33. package/src/cli/service-posture.ts +1 -1
  34. package/src/cli/status.ts +10 -10
  35. package/src/cli/surface-command.ts +4 -4
  36. package/src/cli/tui-startup.ts +23 -23
  37. package/src/config/run-daemon-config-migration.ts +3 -3
  38. package/src/config/secret-config.ts +10 -10
  39. package/src/config/surface.ts +1 -1
  40. package/src/config/tui-extension-settings.ts +8 -8
  41. package/src/core/active-model-identity.ts +7 -7
  42. package/src/core/approval-alert.ts +5 -5
  43. package/src/core/bookmark-navigation.ts +3 -3
  44. package/src/core/budget-breach-notifier.ts +6 -6
  45. package/src/core/compaction-receipt.ts +8 -8
  46. package/src/core/composer-state.ts +2 -2
  47. package/src/core/context-usage.ts +1 -1
  48. package/src/core/conversation-compaction-render.ts +3 -3
  49. package/src/core/conversation-event-navigation.ts +2 -2
  50. package/src/core/conversation-fold.ts +9 -9
  51. package/src/core/conversation-line-cache.ts +14 -14
  52. package/src/core/conversation-render-context.ts +6 -6
  53. package/src/core/conversation-rendering.ts +27 -30
  54. package/src/core/conversation-search-expansion.ts +6 -6
  55. package/src/core/conversation-splash-state.ts +3 -3
  56. package/src/core/conversation-turn-structure.ts +13 -13
  57. package/src/core/conversation-types.ts +3 -3
  58. package/src/core/conversation-user-receipts.ts +5 -5
  59. package/src/core/conversation.ts +17 -17
  60. package/src/core/format-user-error.ts +5 -5
  61. package/src/core/long-task-notifier.ts +9 -9
  62. package/src/core/memory-diagnostics-gateway.ts +8 -8
  63. package/src/core/memory-provenance.ts +5 -5
  64. package/src/core/model-routing-chip.ts +3 -3
  65. package/src/core/pairing-tailscale-gateway.ts +3 -3
  66. package/src/core/permission-mode.ts +5 -5
  67. package/src/core/power-chip-source.ts +3 -3
  68. package/src/core/power-status.ts +8 -8
  69. package/src/core/rewind-receipt.ts +6 -6
  70. package/src/core/session-resume-core.ts +8 -8
  71. package/src/core/stream-event-wiring.ts +36 -36
  72. package/src/core/stream-stall-watchdog.ts +4 -4
  73. package/src/core/system-message-noise.ts +7 -7
  74. package/src/core/system-message-router.ts +10 -10
  75. package/src/core/terminal-notifier.ts +5 -5
  76. package/src/core/turn-budget-outcome.ts +5 -5
  77. package/src/core/turn-cancellation.ts +3 -3
  78. package/src/core/turn-event-wiring.ts +16 -16
  79. package/src/core/voice-capture-status.ts +2 -2
  80. package/src/core/voice-provision-gateway.ts +12 -12
  81. package/src/core/voice-provision-status.ts +19 -19
  82. package/src/core/voice-stt-gateway.ts +6 -6
  83. package/src/core/wake-provision-runner.ts +7 -7
  84. package/src/core/wake-provision-status.ts +17 -17
  85. package/src/core/workstream-notification.ts +8 -8
  86. package/src/export/gist-uploader.ts +7 -7
  87. package/src/input/autocomplete.ts +3 -3
  88. package/src/input/bookmark-modal.ts +1 -1
  89. package/src/input/command-args-hint.ts +2 -2
  90. package/src/input/command-reference.ts +9 -9
  91. package/src/input/command-registry.ts +32 -32
  92. package/src/input/commands/acp-runtime.ts +6 -6
  93. package/src/input/commands/calendar-runtime.ts +9 -9
  94. package/src/input/commands/channel-pairing.ts +11 -11
  95. package/src/input/commands/channel-runtime.ts +1 -1
  96. package/src/input/commands/checkin-runtime.ts +4 -4
  97. package/src/input/commands/checkpoint-runtime.ts +4 -4
  98. package/src/input/commands/ci-runtime.ts +4 -4
  99. package/src/input/commands/cluster-runtime.ts +3 -3
  100. package/src/input/commands/codebase-runtime.ts +16 -16
  101. package/src/input/commands/config.ts +6 -6
  102. package/src/input/commands/connection-status.ts +12 -12
  103. package/src/input/commands/context-window.ts +2 -2
  104. package/src/input/commands/cost-attribution-format.ts +4 -4
  105. package/src/input/commands/cost-runtime.ts +2 -2
  106. package/src/input/commands/devices-runtime.ts +7 -7
  107. package/src/input/commands/diff-runtime.ts +2 -2
  108. package/src/input/commands/editor-runtime.ts +1 -1
  109. package/src/input/commands/eval.ts +4 -4
  110. package/src/input/commands/experience-runtime.ts +1 -1
  111. package/src/input/commands/git-runtime.ts +3 -3
  112. package/src/input/commands/graph-runtime.ts +3 -3
  113. package/src/input/commands/guidance-runtime.ts +1 -1
  114. package/src/input/commands/health-metrics-format.ts +2 -2
  115. package/src/input/commands/health-runtime.ts +8 -8
  116. package/src/input/commands/hosted-runtime.ts +13 -13
  117. package/src/input/commands/image-runtime.ts +6 -6
  118. package/src/input/commands/intelligence-runtime.ts +2 -2
  119. package/src/input/commands/local-auth-runtime.ts +3 -3
  120. package/src/input/commands/local-provider-runtime.ts +3 -3
  121. package/src/input/commands/local-runtime.ts +7 -7
  122. package/src/input/commands/mail-runtime.ts +9 -9
  123. package/src/input/commands/mcp-runtime.ts +1 -1
  124. package/src/input/commands/memory.ts +13 -13
  125. package/src/input/commands/notify-runtime.ts +1 -1
  126. package/src/input/commands/operator-panel-runtime.ts +8 -8
  127. package/src/input/commands/operator-rpc.ts +3 -3
  128. package/src/input/commands/operator-runtime.ts +3 -3
  129. package/src/input/commands/palette-runtime.ts +1 -1
  130. package/src/input/commands/payment-card-intake.ts +17 -17
  131. package/src/input/commands/permissions-provenance.ts +7 -7
  132. package/src/input/commands/permissions-runtime.ts +1 -1
  133. package/src/input/commands/planning-runtime.ts +9 -9
  134. package/src/input/commands/platform-services-runtime.ts +2 -2
  135. package/src/input/commands/policy-dispatch.ts +6 -6
  136. package/src/input/commands/power-runtime.ts +6 -6
  137. package/src/input/commands/principals-runtime.ts +3 -3
  138. package/src/input/commands/product-runtime.ts +3 -3
  139. package/src/input/commands/profile-render.ts +13 -13
  140. package/src/input/commands/profile-runtime.ts +13 -13
  141. package/src/input/commands/profile-types.ts +13 -13
  142. package/src/input/commands/provider-accounts-runtime.ts +5 -5
  143. package/src/input/commands/provider.ts +10 -10
  144. package/src/input/commands/qrcode-runtime.ts +3 -3
  145. package/src/input/commands/queue-runtime.ts +6 -6
  146. package/src/input/commands/recall-files-config.ts +4 -4
  147. package/src/input/commands/recall-files-git.ts +3 -3
  148. package/src/input/commands/recall-files.ts +12 -12
  149. package/src/input/commands/recall-query.ts +3 -3
  150. package/src/input/commands/recall-review.ts +3 -3
  151. package/src/input/commands/recall-shared.ts +1 -1
  152. package/src/input/commands/relay-runtime.ts +5 -5
  153. package/src/input/commands/remote-runtime.ts +3 -3
  154. package/src/input/commands/review-runtime.ts +8 -8
  155. package/src/input/commands/rewind-runtime.ts +21 -21
  156. package/src/input/commands/runtime-services.ts +1 -2
  157. package/src/input/commands/schedule-nl.ts +2 -2
  158. package/src/input/commands/schedule-runtime.ts +2 -2
  159. package/src/input/commands/secret-runtime.ts +3 -3
  160. package/src/input/commands/session-content.ts +7 -7
  161. package/src/input/commands/session-picker-filter.ts +3 -3
  162. package/src/input/commands/session-workflow.ts +10 -10
  163. package/src/input/commands/session.ts +15 -15
  164. package/src/input/commands/settings-sync-runtime.ts +2 -2
  165. package/src/input/commands/share-runtime.ts +4 -4
  166. package/src/input/commands/shell-core.ts +11 -11
  167. package/src/input/commands/tasks-runtime.ts +4 -4
  168. package/src/input/commands/test-runtime.ts +6 -6
  169. package/src/input/commands/tts-runtime.ts +4 -4
  170. package/src/input/commands/update-runtime.ts +27 -27
  171. package/src/input/commands/websearch-runtime.ts +2 -2
  172. package/src/input/commands/work-plan-runtime.ts +2 -2
  173. package/src/input/commands/workstream-attempt-dependents.ts +4 -4
  174. package/src/input/commands/workstream-attempts.ts +16 -16
  175. package/src/input/commands/workstream-runtime.ts +36 -36
  176. package/src/input/commands/worktree-runtime.ts +6 -6
  177. package/src/input/composer-capture.ts +5 -5
  178. package/src/input/concealed-input.ts +2 -2
  179. package/src/input/config-modal-types.ts +16 -16
  180. package/src/input/config-modal.ts +30 -30
  181. package/src/input/daemon-owned-settings-descriptions.ts +4 -4
  182. package/src/input/delete-key-policy.ts +1 -1
  183. package/src/input/exec-env-scrub-config.ts +7 -7
  184. package/src/input/feature-unit-layout.ts +5 -5
  185. package/src/input/feed-context-factory.ts +38 -38
  186. package/src/input/file-picker.ts +1 -1
  187. package/src/input/handler-command-route.ts +2 -2
  188. package/src/input/handler-content-actions.ts +8 -8
  189. package/src/input/handler-feed-routes.ts +13 -13
  190. package/src/input/handler-feed.ts +31 -31
  191. package/src/input/handler-interactions.ts +2 -2
  192. package/src/input/handler-modal-routes.ts +13 -13
  193. package/src/input/handler-modal-stack.ts +1 -1
  194. package/src/input/handler-modal-token-routes.ts +1 -1
  195. package/src/input/handler-onboarding-daemon-adopt.ts +6 -6
  196. package/src/input/handler-picker-routes.ts +7 -7
  197. package/src/input/handler-prompt-buffer.ts +1 -1
  198. package/src/input/handler-shortcuts.ts +12 -12
  199. package/src/input/handler-types.ts +3 -3
  200. package/src/input/handler-ui-state.ts +1 -1
  201. package/src/input/handler.ts +9 -9
  202. package/src/input/input-history.ts +1 -1
  203. package/src/input/keybindings.ts +13 -13
  204. package/src/input/kill-ring.ts +7 -11
  205. package/src/input/model-picker-filter.ts +3 -3
  206. package/src/input/model-picker-items.ts +5 -5
  207. package/src/input/model-picker-types.ts +2 -2
  208. package/src/input/model-picker.ts +18 -18
  209. package/src/input/onboarding/onboarding-feature-units.ts +9 -13
  210. package/src/input/onboarding/onboarding-provider-key-fields.ts +3 -3
  211. package/src/input/onboarding/onboarding-runtime-status.ts +3 -3
  212. package/src/input/onboarding/onboarding-wizard-apply.ts +6 -6
  213. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +1 -1
  214. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -1
  215. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +4 -4
  216. package/src/input/onboarding/onboarding-wizard-network-adopt.ts +6 -6
  217. package/src/input/onboarding/onboarding-wizard-steps.ts +2 -2
  218. package/src/input/panel-integration-actions.ts +3 -3
  219. package/src/input/panel-mouse-geometry.ts +1 -1
  220. package/src/input/panel-paste-flood-guard.ts +9 -9
  221. package/src/input/payments-config.ts +15 -15
  222. package/src/input/profile-picker-modal.ts +1 -1
  223. package/src/input/provider-key-intake.ts +9 -9
  224. package/src/input/relay-settings-descriptions.ts +3 -3
  225. package/src/input/sandbox-exec-config.ts +9 -9
  226. package/src/input/search.ts +18 -18
  227. package/src/input/selection-modal-queue.ts +10 -10
  228. package/src/input/selection-modal.ts +2 -2
  229. package/src/input/session-picker-modal.ts +7 -7
  230. package/src/input/settings-modal-activation.ts +1 -1
  231. package/src/input/settings-modal-adjustment.ts +2 -2
  232. package/src/input/settings-modal-commit.ts +6 -6
  233. package/src/input/settings-modal-connections.ts +2 -2
  234. package/src/input/settings-modal-data.ts +29 -29
  235. package/src/input/settings-modal-mutations.ts +7 -7
  236. package/src/input/settings-modal-reset.ts +3 -3
  237. package/src/input/settings-modal-search.ts +6 -6
  238. package/src/input/settings-modal-secrets.ts +3 -3
  239. package/src/input/settings-modal-types.ts +16 -16
  240. package/src/input/settings-modal.ts +4 -4
  241. package/src/input/voice-local-settings.ts +3 -3
  242. package/src/input/worktree-setup-config.ts +8 -8
  243. package/src/main.ts +15 -15
  244. package/src/panels/agent-inspector-shared.ts +5 -5
  245. package/src/panels/base-panel.ts +3 -3
  246. package/src/panels/builtin/agent.ts +3 -3
  247. package/src/panels/builtin/development.ts +4 -4
  248. package/src/panels/builtin/knowledge.ts +1 -1
  249. package/src/panels/builtin/operations.ts +12 -12
  250. package/src/panels/builtin/session.ts +8 -8
  251. package/src/panels/builtin/shared.ts +6 -6
  252. package/src/panels/builtin-modals.ts +8 -8
  253. package/src/panels/confirm-state.ts +5 -5
  254. package/src/panels/cost-tracker-panel.ts +22 -22
  255. package/src/panels/diff-panel.ts +20 -20
  256. package/src/panels/diff-review-model.ts +5 -5
  257. package/src/panels/diff-review-panel.ts +5 -5
  258. package/src/panels/eval-registry.ts +2 -2
  259. package/src/panels/expandable-list-panel.ts +5 -5
  260. package/src/panels/fleet-acts.ts +20 -20
  261. package/src/panels/fleet-deep-link.ts +5 -5
  262. package/src/panels/fleet-gateway.ts +12 -12
  263. package/src/panels/fleet-observed-render.ts +11 -11
  264. package/src/panels/fleet-panel-format.ts +14 -14
  265. package/src/panels/fleet-panel-worktree-detail.ts +8 -8
  266. package/src/panels/fleet-panel.ts +34 -34
  267. package/src/panels/fleet-read-model.ts +49 -49
  268. package/src/panels/fleet-spawn.ts +15 -15
  269. package/src/panels/fleet-steer.ts +7 -7
  270. package/src/panels/fleet-stop.ts +5 -5
  271. package/src/panels/fleet-tabs.ts +14 -14
  272. package/src/panels/fleet-transcript.ts +26 -26
  273. package/src/panels/git-panel.ts +8 -8
  274. package/src/panels/hosted-session-feed.ts +13 -13
  275. package/src/panels/hosted-session-panel.ts +7 -7
  276. package/src/panels/index.ts +1 -1
  277. package/src/panels/local-auth-panel.ts +15 -15
  278. package/src/panels/memory-consolidation-gateway.ts +8 -8
  279. package/src/panels/modals/devices-modal.ts +8 -8
  280. package/src/panels/modals/hooks-modal.ts +1 -1
  281. package/src/panels/modals/keybindings-modal.ts +5 -5
  282. package/src/panels/modals/knowledge-modal.ts +2 -2
  283. package/src/panels/modals/local-auth-modal.ts +4 -4
  284. package/src/panels/modals/marketplace-modal.ts +3 -3
  285. package/src/panels/modals/memory-modal.ts +19 -19
  286. package/src/panels/modals/modal-surface-helpers.ts +1 -1
  287. package/src/panels/modals/modal-theme.ts +3 -3
  288. package/src/panels/modals/pairing-modal.ts +19 -19
  289. package/src/panels/modals/planning-modal.ts +4 -4
  290. package/src/panels/modals/plugins-modal.ts +1 -1
  291. package/src/panels/modals/policy-modal.ts +4 -4
  292. package/src/panels/modals/provider-health-modal.ts +1 -1
  293. package/src/panels/modals/remote-modal.ts +1 -1
  294. package/src/panels/modals/sandbox-modal.ts +2 -2
  295. package/src/panels/modals/security-modal.ts +4 -4
  296. package/src/panels/modals/services-modal.ts +1 -1
  297. package/src/panels/modals/work-plan-modal.ts +4 -4
  298. package/src/panels/notifications-feed.ts +6 -6
  299. package/src/panels/notifications-panel.ts +6 -6
  300. package/src/panels/panel-confirm-overlay.ts +4 -4
  301. package/src/panels/panel-manager.ts +13 -13
  302. package/src/panels/plugins-panel.ts +6 -6
  303. package/src/panels/polish-core.ts +2 -2
  304. package/src/panels/polish-tables.ts +2 -2
  305. package/src/panels/polish.ts +1 -1
  306. package/src/panels/project-planning-answer-actions.ts +3 -3
  307. package/src/panels/scrollable-list-panel.ts +15 -15
  308. package/src/panels/search-focus.ts +1 -1
  309. package/src/panels/session-maintenance.ts +1 -1
  310. package/src/panels/skills-panel.ts +3 -3
  311. package/src/panels/token-budget-panel.ts +11 -11
  312. package/src/panels/types.ts +14 -14
  313. package/src/panels/workstream-graph-render.ts +5 -5
  314. package/src/panels/wrfc-panel-format.ts +1 -1
  315. package/src/permissions/broker-approval-card.ts +13 -13
  316. package/src/permissions/hunk-selection.ts +13 -13
  317. package/src/permissions/prompt.ts +22 -22
  318. package/src/permissions/sandbox-exec-gate.ts +5 -5
  319. package/src/providers/provider-classification.ts +1 -1
  320. package/src/providers/reasoning-effort-surface.ts +12 -12
  321. package/src/renderer/ansi-sanitize.ts +5 -6
  322. package/src/renderer/autocomplete-overlay.ts +5 -5
  323. package/src/renderer/block-actions-overlay.ts +1 -1
  324. package/src/renderer/bookmark-modal.ts +1 -1
  325. package/src/renderer/code-block.ts +2 -2
  326. package/src/renderer/compaction-history-modal.ts +4 -4
  327. package/src/renderer/compaction-preview.ts +5 -5
  328. package/src/renderer/compaction-quality.ts +5 -5
  329. package/src/renderer/composer-fragments.ts +6 -6
  330. package/src/renderer/compositor.ts +9 -9
  331. package/src/renderer/config-modal.ts +3 -3
  332. package/src/renderer/context-inspector.ts +1 -1
  333. package/src/renderer/context-status-hint.ts +10 -10
  334. package/src/renderer/conversation-layout.ts +2 -2
  335. package/src/renderer/conversation-overlays.ts +2 -2
  336. package/src/renderer/conversation-surface.ts +6 -6
  337. package/src/renderer/diff.ts +4 -4
  338. package/src/renderer/fleet-tab-strip.ts +2 -2
  339. package/src/renderer/footer-tips.ts +4 -4
  340. package/src/renderer/fullscreen-primitives.ts +1 -1
  341. package/src/renderer/git-status.ts +5 -5
  342. package/src/renderer/header-line.ts +5 -5
  343. package/src/renderer/help-overlay.ts +5 -5
  344. package/src/renderer/hint-grammar.ts +2 -2
  345. package/src/renderer/layout.ts +1 -1
  346. package/src/renderer/markdown-inline.ts +3 -3
  347. package/src/renderer/markdown-table.ts +7 -7
  348. package/src/renderer/modal-factory.ts +3 -3
  349. package/src/renderer/model-picker-overlay.ts +2 -2
  350. package/src/renderer/model-workspace.ts +7 -7
  351. package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
  352. package/src/renderer/overlay-box.ts +1 -1
  353. package/src/renderer/panel-composite.ts +5 -5
  354. package/src/renderer/panel-workspace-bar.ts +1 -1
  355. package/src/renderer/process-indicator.ts +8 -8
  356. package/src/renderer/profile-picker-modal.ts +3 -3
  357. package/src/renderer/prompt-content-width.ts +1 -1
  358. package/src/renderer/search-overlay.ts +3 -3
  359. package/src/renderer/selection-modal-overlay.ts +6 -6
  360. package/src/renderer/semantic-diff.ts +6 -7
  361. package/src/renderer/session-picker-modal.ts +24 -24
  362. package/src/renderer/settings-modal-connections.ts +3 -3
  363. package/src/renderer/settings-modal-helpers.ts +16 -16
  364. package/src/renderer/settings-modal.ts +10 -10
  365. package/src/renderer/shell-surface.ts +8 -8
  366. package/src/renderer/status-glyphs.ts +6 -6
  367. package/src/renderer/syntax-highlighter.ts +2 -3
  368. package/src/renderer/system-message.ts +3 -3
  369. package/src/renderer/tab-strip.ts +2 -2
  370. package/src/renderer/term-caps.ts +12 -12
  371. package/src/renderer/terminal-bg-probe.ts +10 -10
  372. package/src/renderer/terminal-escapes.ts +1 -1
  373. package/src/renderer/theme-mode-config.ts +3 -3
  374. package/src/renderer/theme.ts +34 -34
  375. package/src/renderer/thinking.ts +1 -1
  376. package/src/renderer/tool-call.ts +5 -5
  377. package/src/renderer/tool-result-expanded-lines.ts +3 -3
  378. package/src/renderer/tool-result-summary.ts +6 -6
  379. package/src/renderer/turn-injection.ts +9 -9
  380. package/src/renderer/ui-factory.ts +33 -33
  381. package/src/renderer/ui-primitives.ts +4 -4
  382. package/src/runtime/bootstrap-command-parts.ts +3 -3
  383. package/src/runtime/bootstrap-core.ts +21 -21
  384. package/src/runtime/bootstrap-hook-bridge.ts +8 -8
  385. package/src/runtime/bootstrap-shell.ts +9 -9
  386. package/src/runtime/bootstrap.ts +16 -16
  387. package/src/runtime/client/approval-updates.ts +3 -3
  388. package/src/runtime/client/build-floors.ts +7 -7
  389. package/src/runtime/client/daemon-attach-handshake.ts +5 -5
  390. package/src/runtime/client/fleet-union.ts +7 -7
  391. package/src/runtime/client/host-service-status.ts +2 -2
  392. package/src/runtime/client/hosted-exit.ts +4 -4
  393. package/src/runtime/client/hosted-roster.ts +4 -4
  394. package/src/runtime/client/hosted-session-stream.ts +5 -5
  395. package/src/runtime/client/hosted-sessions.ts +8 -8
  396. package/src/runtime/client/operator-endpoint.ts +14 -14
  397. package/src/runtime/client/spine-adoption.ts +8 -8
  398. package/src/runtime/context-accounting-source.ts +4 -4
  399. package/src/runtime/context.ts +2 -2
  400. package/src/runtime/conversation-rewind-port.ts +6 -6
  401. package/src/runtime/credential-composition.ts +2 -2
  402. package/src/runtime/daemon-attach-notices.ts +6 -6
  403. package/src/runtime/diagnostics/panels/index.ts +1 -1
  404. package/src/runtime/diagnostics/panels/ops.ts +2 -2
  405. package/src/runtime/disposal-wiring.ts +6 -6
  406. package/src/runtime/index.ts +11 -11
  407. package/src/runtime/install-self-check-startup.ts +4 -4
  408. package/src/runtime/install-self-check.ts +6 -6
  409. package/src/runtime/interaction-seams.ts +4 -4
  410. package/src/runtime/knowledge-services.ts +2 -2
  411. package/src/runtime/legacy-daemon-migration.ts +37 -37
  412. package/src/runtime/legacy-daemon-reconcile.ts +30 -30
  413. package/src/runtime/memory-governance-services.ts +3 -3
  414. package/src/runtime/memory-spine-transport.ts +3 -3
  415. package/src/runtime/notification-dispatch.ts +4 -4
  416. package/src/runtime/onboarding/apply.ts +1 -1
  417. package/src/runtime/onboarding/derivation.ts +1 -1
  418. package/src/runtime/onboarding/fast-path.ts +7 -7
  419. package/src/runtime/onboarding/progress.ts +2 -2
  420. package/src/runtime/onboarding/provider-key-capture.ts +4 -4
  421. package/src/runtime/onboarding/snapshot.ts +2 -2
  422. package/src/runtime/onboarding/state.ts +4 -4
  423. package/src/runtime/onboarding/types.ts +4 -4
  424. package/src/runtime/orchestrator-core-services.ts +5 -5
  425. package/src/runtime/path-shadow-startup.ts +3 -3
  426. package/src/runtime/perf/panel-contracts.ts +1 -1
  427. package/src/runtime/power-keepawake-remote.ts +6 -6
  428. package/src/runtime/process-lifecycle.ts +14 -14
  429. package/src/runtime/provider-fallback.ts +3 -3
  430. package/src/runtime/recovery-autosave.ts +3 -3
  431. package/src/runtime/recovery-decisions.ts +19 -19
  432. package/src/runtime/recovery-offer-wiring.ts +4 -4
  433. package/src/runtime/recovery-prompt.ts +20 -20
  434. package/src/runtime/relay-reachability-bridge.ts +3 -3
  435. package/src/runtime/release-artifacts.ts +1 -1
  436. package/src/runtime/resume-notice.ts +20 -20
  437. package/src/runtime/runtime-services-types.ts +20 -20
  438. package/src/runtime/services.ts +20 -20
  439. package/src/runtime/session-continuity-hints.ts +1 -1
  440. package/src/runtime/session-inbound-inputs.ts +12 -12
  441. package/src/runtime/session-resume-liveness-confirm.ts +4 -4
  442. package/src/runtime/session-spine-transport.ts +3 -3
  443. package/src/runtime/store/domains/panels.ts +2 -2
  444. package/src/runtime/store/domains/ui-perf.ts +2 -2
  445. package/src/runtime/store/index.ts +1 -1
  446. package/src/runtime/store/selectors/index.ts +1 -1
  447. package/src/runtime/store/state.ts +2 -2
  448. package/src/runtime/ui-services.ts +3 -3
  449. package/src/runtime/workspace-checkpointing.ts +3 -3
  450. package/src/runtime/wrfc-persistence.ts +15 -15
  451. package/src/scripts/process-messages.ts +1 -1
  452. package/src/shell/blocking-input.ts +9 -9
  453. package/src/shell/recovery-input-helpers.ts +2 -2
  454. package/src/shell/retry-affordance.ts +9 -9
  455. package/src/shell/ui-openers.ts +14 -14
  456. package/src/shell/voice-capture-shell.ts +3 -3
  457. package/src/tools/wrfc-agent-guard.ts +4 -4
  458. package/src/utils/browser.ts +2 -2
  459. package/src/utils/format-duration.ts +3 -3
  460. package/src/utils/format-number.ts +2 -2
  461. package/src/utils/splash-lines.ts +4 -4
  462. package/src/utils/terminal-width.ts +6 -6
  463. package/src/verification/verification-ledger.ts +25 -25
  464. package/src/version.ts +3 -3
@@ -1,5 +1,5 @@
1
1
  /**
2
- * renderSessionPickerModal — renders the /sessions picker modal as Line[]
2
+ * renderSessionPickerModal, renders the /sessions picker modal as Line[]
3
3
  * using ModalFactory.
4
4
  *
5
5
  * Shows a list of saved sessions with:
@@ -9,8 +9,8 @@
9
9
  * When the modal was wired with a cross-surface session union
10
10
  * (`modal.crossSurfaceView.mode !== 'local'`), an additional read-only
11
11
  * "Cross-surface sessions" section is appended, badged kind/status/project
12
- * (parity with the webui SessionsView) with one of three honest states —
13
- * true-empty, offline, or stale — never a silently-collapsed list. In
12
+ * (parity with the webui SessionsView) with one of three honest states,
13
+ * true-empty, offline, or stale, never a silently-collapsed list. In
14
14
  * 'local' mode (no sessionBroker wired, e.g. every pre-existing caller/test)
15
15
  * this section is entirely absent and the box sizing is unchanged.
16
16
  */
@@ -28,7 +28,7 @@ import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay
28
28
  // Cross-surface badge helpers (parity with webui's src/lib/sessions-union.ts)
29
29
  // ---------------------------------------------------------------------------
30
30
 
31
- /** Verbatim for unknown/future kinds — never dropped, never guessed. */
31
+ /** Verbatim for unknown/future kinds, never dropped, never guessed. */
32
32
  function kindLabel(kind: string): string {
33
33
  return kind.trim() || 'unknown';
34
34
  }
@@ -44,10 +44,10 @@ function isClosedStatus(status: string): boolean {
44
44
  /**
45
45
  * Closed sessions carry an optional, honest reason for WHY they
46
46
  * closed under `metadata.closeReason` (SDK's `SharedSessionCloseReason`,
47
- * 'closeReason' key — see `@pellux/goodvibes-sdk` platform/control-plane
47
+ * 'closeReason' key, see `@pellux/goodvibes-sdk` platform/control-plane
48
48
  * session-broker-sessions.ts's `readSessionCloseReason`). `metadata` is an
49
49
  * open record so old readers and records from a build that predates this
50
- * field ignore it safely — read it duck-typed here rather than importing the
50
+ * field ignore it safely, read it duck-typed here rather than importing the
51
51
  * SDK's helper, and tolerate `metadata` itself being absent or malformed.
52
52
  */
53
53
  function readCloseReason(record: SharedSessionRecord): string | undefined {
@@ -57,7 +57,7 @@ function readCloseReason(record: SharedSessionRecord): string | undefined {
57
57
 
58
58
  /**
59
59
  * A GC sweep closing an idle session ('idle-reaped') auto-reopens on the next
60
- * heartbeat — it is NOT the same event as a deliberate user/surface close, so
60
+ * heartbeat, it is NOT the same event as a deliberate user/surface close, so
61
61
  * it must never render under the same "closed" badge. Tolerant of
62
62
  * records without the field (pre-feature builds, or a deliberate close).
63
63
  */
@@ -67,16 +67,16 @@ function isReapedRecord(record: SharedSessionRecord): boolean {
67
67
 
68
68
  /**
69
69
  * UX-lens note: 'reaped' names a mechanism (the idle-session sweep),
70
- * not a state a first-time reader can guess — the webui pairs its own
70
+ * not a state a first-time reader can guess, the webui pairs its own
71
71
  * 'reaped' badge with a tooltip explaining it
72
- * (SessionsView.tsx: "Closed by the idle-session sweep — reopens
72
+ * (SessionsView.tsx: "Closed by the idle-session sweep, reopens
73
73
  * automatically on the next activity"). The TUI has no hover/tooltip
74
74
  * surface, so the plain-language explanation is rendered as its own short
75
- * line under the cross-surface list instead — shown ONLY when at least one
75
+ * line under the cross-surface list instead, shown ONLY when at least one
76
76
  * visible row actually carries the badge, so it never adds noise to a list
77
77
  * with no reaped rows.
78
78
  */
79
- const REAPED_BADGE_HINT = 'reaped = closed by the idle sweep — reopens on next activity';
79
+ const REAPED_BADGE_HINT = 'reaped = closed by the idle sweep; reopens on next activity';
80
80
 
81
81
  /** True when at least one of the currently-rendered (post-truncation) cross-surface rows carries the 'reaped' badge. */
82
82
  function hasVisibleReapedRow(modal: SessionPickerModal): boolean {
@@ -114,8 +114,8 @@ function hostedRosterNote(roster: SessionPickerModal['hostedRoster']): string |
114
114
  * One hosted row: the id first, then what it is doing, what leaving it would
115
115
  * do, and finally its title.
116
116
  *
117
- * The id leads because it is the ACTIONABLE part — the row exists so `/hosted
118
- * attach <id>` can be typed off it — and a narrow terminal clips the tail. What
117
+ * The id leads because it is the ACTIONABLE part, the row exists so `/hosted
118
+ * attach <id>` can be typed off it, and a narrow terminal clips the tail. What
119
119
  * gets clipped must therefore be the descriptive end of the line, never the
120
120
  * thing the user has to retype.
121
121
  */
@@ -140,8 +140,8 @@ function hostedRowLabel(
140
140
  *
141
141
  * Absent when NOTHING is known: no roster was wired (every pre-existing caller
142
142
  * and test), so the box size and content are unchanged for them. The moment the
143
- * roster has an answer — rows, an empty-but-read list, or a reason it could not
144
- * read — the section appears, because each of those is a fact worth showing.
143
+ * roster has an answer, rows, an empty-but-read list, or a reason it could not
144
+ * read, the section appears, because each of those is a fact worth showing.
145
145
  */
146
146
  function hostedSectionVisible(modal: SessionPickerModal): boolean {
147
147
  const roster = modal.hostedRoster;
@@ -155,7 +155,7 @@ function hostedRowCount(modal: SessionPickerModal): number {
155
155
  /**
156
156
  * Extra content rows the hosted section needs: separator + header (+note)
157
157
  * + rows (+overflow line + the attach hint). Counted for the same reason the
158
- * cross-surface section counts its own — an uncounted trailing row is silently
158
+ * cross-surface section counts its own, an uncounted trailing row is silently
159
159
  * eaten by modal-factory's tail clip.
160
160
  */
161
161
  function hostedExtraRows(modal: SessionPickerModal): number {
@@ -170,12 +170,12 @@ function hostedExtraRows(modal: SessionPickerModal): number {
170
170
  /**
171
171
  * The exact honest note for the current state, or null when the union view
172
172
  * needs no caveat (fresh, with rows). Precedence: offline > stale >
173
- * true-empty — the three designed states, never collapsed into
173
+ * true-empty, the three designed states, never collapsed into
174
174
  * each other (an offline view never silently renders as "no sessions yet").
175
175
  */
176
176
  function crossSurfaceNote(view: SessionPickerModal['crossSurfaceView'], rowCount: number): string | null {
177
177
  if (view.mode === 'local') return null;
178
- if (view.offlineNote) return `${view.offlineNote} — showing local sessions only`;
178
+ if (view.offlineNote) return `${view.offlineNote}: showing local sessions only`;
179
179
  if (view.stale) {
180
180
  if (view.lastSyncAt === null) return 'Union view may be stale.';
181
181
  const ageSeconds = Math.max(0, Math.round((Date.now() - view.lastSyncAt) / 1000));
@@ -192,7 +192,7 @@ function crossSurfaceRowCount(modal: SessionPickerModal): number {
192
192
  /**
193
193
  * Extra content rows the cross-surface section needs: separator + header
194
194
  * (+note) + rows (+the "[showing N of M]" overflow line when the union has
195
- * more records than MAX_CROSS_SURFACE_ROWS — previously uncounted here, which
195
+ * more records than MAX_CROSS_SURFACE_ROWS, previously uncounted here, which
196
196
  * let modal-factory's tail-clip silently eat that trailing line even though
197
197
  * the rest of the budget accounting held; see W3 Finding 1).
198
198
  */
@@ -201,7 +201,7 @@ function crossSurfaceExtraRows(modal: SessionPickerModal): number {
201
201
  const rows = crossSurfaceRowCount(modal);
202
202
  const noteRow = crossSurfaceNote(modal.crossSurfaceView, rows) ? 1 : 0;
203
203
  const overflowRow = modal.crossSurfaceSessions.length > MAX_CROSS_SURFACE_ROWS ? 1 : 0;
204
- // W4 UX-lens: the plain-language 'reaped' explainer is its own row —
204
+ // W4 UX-lens: the plain-language 'reaped' explainer is its own row,
205
205
  // uncounted here it would be silently eaten by modal-factory's tail-clip
206
206
  // exactly the way W3 Finding 1 describes above.
207
207
  const reapedHintRow = hasVisibleReapedRow(modal) ? 1 : 0;
@@ -236,7 +236,7 @@ export function renderSessionPickerModal(
236
236
 
237
237
  // W3 Finding 1: when a cross-surface union section is present, cap the
238
238
  // LOCAL list's window to what's left after reserving extraRows for the
239
- // union — otherwise the local list expands to fill metrics.contentRows
239
+ // union, otherwise the local list expands to fill metrics.contentRows
240
240
  // (which already includes the union's reservation) and modal-factory's
241
241
  // single tail-clip (createModal, targetContentRows) silently drops the
242
242
  // union section, or its trailing rows, once the box fills up. In local
@@ -312,7 +312,7 @@ export function renderSessionPickerModal(
312
312
  }
313
313
  }
314
314
 
315
- // Cross-surface session union — visible only when a sessionBroker
315
+ // Cross-surface session union, visible only when a sessionBroker
316
316
  // was wired (mode !== 'local'); absent entirely otherwise, so the box size
317
317
  // and content of every pre-existing (local-only) caller is unaffected.
318
318
  if (modal.crossSurfaceView.mode !== 'local') {
@@ -353,7 +353,7 @@ export function renderSessionPickerModal(
353
353
  });
354
354
  }
355
355
  // W4 UX-lens: only ever rendered when a visible row actually carries
356
- // the 'reaped' badge — never speculative noise.
356
+ // the 'reaped' badge, never speculative noise.
357
357
  if (hasVisibleReapedRow(modal)) {
358
358
  sections.push({
359
359
  type: 'text',
@@ -364,7 +364,7 @@ export function renderSessionPickerModal(
364
364
  }
365
365
  }
366
366
 
367
- // Daemon-hosted sessions — conversations whose loop runs in the daemon rather
367
+ // Daemon-hosted sessions, conversations whose loop runs in the daemon rather
368
368
  // than in this terminal. Read-only here: joining one is `/hosted attach <id>`,
369
369
  // which opens a live stream this modal has no business owning, so the full id
370
370
  // is rendered for the command to be typed straight off the row.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * settings-modal-connections.ts — rendering for the Connections category of the
2
+ * settings-modal-connections.ts, rendering for the Connections category of the
3
3
  * settings workspace.
4
4
  *
5
5
  * Split out of settings-modal.ts for the 800-line file cap, the same reason
@@ -18,7 +18,7 @@ import { clamp, padDisplay, stableWindow } from './fullscreen-workspace.ts';
18
18
  *
19
19
  * `checking` is rendered as its own state rather than blanked, because a row
20
20
  * that showed nothing while the probe was in flight would read as "nothing
21
- * configured" — the one thing this category exists to stop claiming falsely.
21
+ * configured", the one thing this category exists to stop claiming falsely.
22
22
  */
23
23
  export function renderConnectionRows(modal: SettingsModal, width: number, height: number): string[] {
24
24
  const rows: string[] = [];
@@ -44,7 +44,7 @@ export function renderConnectionRows(modal: SettingsModal, width: number, height
44
44
  /**
45
45
  * The detail pane for one connection: the state, what it means, and every next
46
46
  * step verbatim. The next steps are the daemon's requirements, so they are
47
- * listed in full rather than summarized — a truncated instruction is a wrong
47
+ * listed in full rather than summarized, a truncated instruction is a wrong
48
48
  * instruction.
49
49
  */
50
50
  export function buildConnectionContext(modal: SettingsModal): string[] {
@@ -10,7 +10,7 @@ import { isSecretConfigKey, isSecretReferenceValue } from '../config/secret-conf
10
10
  import { UI_TONES } from './ui-primitives.ts';
11
11
 
12
12
  /**
13
- * "Modified / active" accent for settings rows — cyan-green, no UI_TONES
13
+ * "Modified / active" accent for settings rows, cyan-green, no UI_TONES
14
14
  * role matches it (preserved byte-exact as a named constant).
15
15
  */
16
16
  const SETTINGS_ACCENT = '#00ffcc';
@@ -32,7 +32,7 @@ export function formatValue(entry: SettingEntry): string {
32
32
  // comma-separated list, matching how they're edited (see worktree-setup-config.ts).
33
33
  if (Array.isArray(val)) return val.length > 0 ? val.join(', ') : '(empty)';
34
34
  // Object-backed settings (e.g. pricing.modelPrices) display their JSON when
35
- // short, or an honest entry count — never the useless "[object Object]".
35
+ // short, or an honest entry count, never the useless "[object Object]".
36
36
  if (typeof val === 'object') {
37
37
  const keys = Object.keys(val as Record<string, unknown>);
38
38
  if (keys.length === 0) return '(none set)';
@@ -77,7 +77,7 @@ export const CATEGORY_INFO: Record<SettingsCategory, string> = {
77
77
  wrfc: 'Work-review-fix-cycle thresholds, retry limits, and automatic commit behavior.',
78
78
  helper: 'Helper model defaults used by helper subsystems when they do not use the main chat route.',
79
79
  tts: 'Text-to-speech provider, voice, and optional spoken-turn LLM overrides.',
80
- voice: 'Two independent voice capabilities. Local engines (voice.local.*): the STT and TTS engine, binary, and model-path for whisper.cpp/faster-whisper and Piper/Kokoro — all empty by default, configurable-not-configured, nothing auto-downloads, and an unconfigured machine reports honestly (never an error); once set, "Local engines" appears in the TTS provider picker beside elevenlabs, with no billing dimension. Wake-word detection (voice.wake.*, rendered as its own unit below): listening continuously for a spoken wake phrase and handing the utterance that follows to speech-to-text — off by default, because holding a microphone open is meant to be an explicit act. It is live on this terminal: enabling it starts a recorder subprocess (voice.wake.captureCommand), scores every frame with the pinned classifier through a WASM runtime, plays voice.wake.activationSound at a confirmed wake, shows a persistent footer row per voice.wake.indicator, and sends what follows to the same speech-to-text call — into the composer, or submitted outright when voice.wake.autoSubmit is on. The same capture path backs push-to-talk voice input (Alt+V by default), which always lands in the composer. voice.wake.noiseSuppression: speex runs here — the filter travels with the platform, so there is nothing to install for it — and voice.wake.vadThreshold above 0 screens frames with the pinned speech gate once provisioning has fetched it, refusing to start before that rather than scoring frames it claims to be screening. The model is already on this machine: installing goodvibes downloads and checksum-verifies it, and a running daemon retries at boot if the install could not reach the network — so switching this on normally needs no setup step. Switching it on never downloads anything itself; a host whose artifacts are missing or fail verification says which and names /voice wake setup rather than pretending to listen. Its published recall figures are measured on synthesised speech only, so no human recording of the phrase is behind them.',
80
+ voice: 'Two independent voice capabilities. Local engines (voice.local.*): the STT and TTS engine, binary, and model-path for whisper.cpp/faster-whisper and Piper/Kokoro; all empty by default, configurable-not-configured, nothing auto-downloads, and an unconfigured machine reports honestly (never an error); once set, "Local engines" appears in the TTS provider picker beside elevenlabs, with no billing dimension. Wake-word detection (voice.wake.*, rendered as its own unit below): listening continuously for a spoken wake phrase and handing the utterance that follows to speech-to-text; off by default, because holding a microphone open is meant to be an explicit act. It is live on this terminal: enabling it starts a recorder subprocess (voice.wake.captureCommand), scores every frame with the pinned classifier through a WASM runtime, plays voice.wake.activationSound at a confirmed wake, shows a persistent footer row per voice.wake.indicator, and sends what follows to the same speech-to-text call: into the composer, or submitted outright when voice.wake.autoSubmit is on. The same capture path backs push-to-talk voice input (Alt+V by default), which always lands in the composer. voice.wake.noiseSuppression: speex runs here, the filter travels with the platform, so there is nothing to install for it, and voice.wake.vadThreshold above 0 screens frames with the pinned speech gate once provisioning has fetched it, refusing to start before that rather than scoring frames it claims to be screening. The model is already on this machine: installing goodvibes downloads and checksum-verifies it, and a running daemon retries at boot if the install could not reach the network, so switching this on normally needs no setup step. Switching it on never downloads anything itself; a host whose artifacts are missing or fail verification says which and names /voice wake setup rather than pretending to listen. Its published recall figures are measured on synthesised speech only, so no human recording of the phrase is behind them.',
81
81
  service: 'Background service posture: enabled state, autostart, restart behavior, service name, platform, and logs.',
82
82
  daemon: 'Local session daemon. It hosts the shared session broker and companion chat so a session started here is visible and steerable from other surfaces. On by default, bound to loopback (127.0.0.1) only.',
83
83
  controlPlane: 'Daemon control-plane settings for local admin/API access.',
@@ -85,10 +85,10 @@ export const CATEGORY_INFO: Record<SettingsCategory, string> = {
85
85
  web: 'Browser surface settings for the local or network web UI.',
86
86
  batch: 'Batch execution settings, including local vs Cloudflare queue behavior.',
87
87
  automation: 'Scheduled and automated run settings, concurrency, timeout, catch-up, cooldown, and retention behavior.',
88
- checkin: 'Proactive check-in: on a cadence, a briefing is judged and you are contacted only when something warrants it. Off by default; every run — scheduled or manual — leaves a receipt (see /checkin) recording whether it stayed quiet, delivered a message, or was skipped.',
89
- occasions: 'Proactive occasions and plans: dated, usually-recurring things that need an action (birthdays, anniversaries) and dated ranges that need only to be known about (a vacation). On by default. Lead time before a date, active hours nudges are allowed to arrive in, the nudge channel (empty makes it pull-only through /occasions), cadence while a window is open and the daily final stretch before it closes, whether an away plan moves a nudge earlier, whether a confirmed occasion mirrors to the calendar and whether a mirrored one suppresses its own nudge, how many questions the gift interview asks, how many years of gift history it keeps, and how often the sweep pass runs. The nudge itself never names the date — only how soon.',
90
- hostedSessions: 'Sessions whose conversation loop runs INSIDE the daemon instead of this terminal, so the work does not end when the window that started it closes. What happens when the last client leaves is the detach policy: the shipped default is `kill` — exactly what closing a client has always done — and `survive` is the opt-in that leaves the session idle and reattachable. A session created with /hosted new --survive or --kill overrides the setting for itself. The remaining rows bound the capability: how many hosted sessions may run at once, how many messages one keeps, and how long a terminated session\'s record (with the reason it ended) is retained before it is retired.',
91
- watchers: 'File/process watcher heartbeat, polling, and recovery-window behavior, plus the trigger family (watchers.triggers.*, rendered as its own unit): stream watchers that regex-filter and batch a long-lived command\'s output, model-free condition checks running a probe/extract/rule pipeline with no LLM in the loop, and one-shot on-exit triggers that fire exactly one payload when a launched command terminates. The trigger family is off by default — a trigger supervises real processes with nobody watching — and its rows tune the backoff ladder, the strike breaker, retention bounds, batching, and process caps.',
88
+ checkin: 'Proactive check-in: on a cadence, a briefing is judged and you are contacted only when something warrants it. Off by default; every run, scheduled or manual, leaves a receipt (see /checkin) recording whether it stayed quiet, delivered a message, or was skipped.',
89
+ occasions: 'Proactive occasions and plans: dated, usually-recurring things that need an action (birthdays, anniversaries) and dated ranges that need only to be known about (a vacation). On by default. Lead time before a date, active hours nudges are allowed to arrive in, the nudge channel (empty makes it pull-only through /occasions), cadence while a window is open and the daily final stretch before it closes, whether an away plan moves a nudge earlier, whether a confirmed occasion mirrors to the calendar and whether a mirrored one suppresses its own nudge, how many questions the gift interview asks, how many years of gift history it keeps, and how often the sweep pass runs. The nudge itself never names the date; only how soon.',
90
+ hostedSessions: 'Sessions whose conversation loop runs INSIDE the daemon instead of this terminal, so the work does not end when the window that started it closes. What happens when the last client leaves is the detach policy: the shipped default is `kill`, exactly what closing a client has always done, and `survive` is the opt-in that leaves the session idle and reattachable. A session created with /hosted new --survive or --kill overrides the setting for itself. The remaining rows bound the capability: how many hosted sessions may run at once, how many messages one keeps, and how long a terminated session\'s record (with the reason it ended) is retained before it is retired.',
91
+ watchers: 'File/process watcher heartbeat, polling, and recovery-window behavior, plus the trigger family (watchers.triggers.*, rendered as its own unit): stream watchers that regex-filter and batch a long-lived command\'s output, model-free condition checks running a probe/extract/rule pipeline with no LLM in the loop, and one-shot on-exit triggers that fire exactly one payload when a launched command terminates. The trigger family is off by default, a trigger supervises real processes with nobody watching, and its rows tune the backoff ladder, the strike breaker, retention bounds, batching, and process caps.',
92
92
  runtime: 'Runtime guardrails such as companion chat limiter and event bus listener caps.',
93
93
  telemetry: 'Telemetry payload policy.',
94
94
  cache: 'Provider and model cache behavior, TTL, and hit-rate monitoring.',
@@ -96,12 +96,12 @@ export const CATEGORY_INFO: Record<SettingsCategory, string> = {
96
96
  mcp: 'MCP server trust and scope review. Trust changes can expose local files, tools, databases, browsers, or remote automation depending on the server.',
97
97
  sandbox: 'Isolation strategy for REPL, MCP, Windows, and QEMU-backed execution. Use these settings to separate risky tools from the host shell.',
98
98
  surfaces: 'External app surfaces such as Slack, Discord, ntfy, Home Assistant, Telegram, webhooks, chat bridges, and messaging providers.',
99
- device: 'Posture for using a PAIRED phone as a tool — its cameras, its screen, its location, its clipboard, and a small set of device effects. Every row here changes behaviour, and every change applies to the next request without a restart. device.capabilities.mode is the master switch: off stops every capability request reaching any paired device (nothing is dispatched and nobody is asked), ask-every-time asks on every single request and never consults or offers a durable grant, and honor-grants (stock) asks the first time and every time after unless you chose "always allow" for that one capability on that one phone. allowAlwaysOffer decides which capabilities may offer that durable grant at all: every-capability (stock), standard-only (the elevated ones — front camera, screen capture, precise location, clipboard read — keep asking and an "always" answer is honoured for that one request only), or never. requestTimeoutSeconds is the deadline on three things at once: how long the phone has to answer, the deadline written into the request the phone receives, and how long the confirmation prompt itself stays open. device.location.precision gates the street-level fix (coarse-only refuses it and still serves approximate; ask-precise serves it but never remembers it), and device.clipboard.readMode gates reading the clipboard the same way — putting text ON the clipboard is a different capability and is unaffected. Captures from the camera and the screen are kept for capture.retentionHours and capped at capture.maxArtifacts, whichever bites first; housekeeping runs at every start and then every capture.sweepIntervalMinutes, deleting expired grants and captures and recording what it removed and why. A grant lasts grants.expiryDays and is never honoured past it, one phone holds at most grants.maxPerNode grants (the oldest are reaped past the cap), and the ledger of grants given, used, revoked and expired is kept for grants.auditRetentionDays. device.nodes.maxPaired is enforced at the moment a device pairs: at the cap a NEW device is refused with a message naming the setting, the cap and how many are already paired, while a phone that is already in the list simply supersedes its own record and keeps working. Lowering the cap below the number already paired unpairs no one — existing devices keep working and only the next new pairing is refused; a device moving off the legacy shared token to its own is exempt so it cannot be stranded. A nonsensical value anywhere here (zero, negative, not a number, an enum value that is not on the list) is read as the stock value rather than passed through, so a broken setting can neither lock you out of your own daemon nor widen the posture.',
100
- conversationGate: 'What a message arriving from one of those channels does. By default it gets a conversational answer, and work is proposed and waits for your agreement rather than starting on its own; you can instead confirm every run, or restore the old behavior where a message starts work immediately. Also how long a pending proposal stays answerable and how many can wait at once. This governs messages from channels only — what you type here always runs, and schedules and triggers were authorized when created.',
99
+ device: 'Posture for using a PAIRED phone as a tool: its cameras, its screen, its location, its clipboard, and a small set of device effects. Every row here changes behaviour, and every change applies to the next request without a restart. device.capabilities.mode is the master switch: off stops every capability request reaching any paired device (nothing is dispatched and nobody is asked), ask-every-time asks on every single request and never consults or offers a durable grant, and honor-grants (stock) asks the first time and every time after unless you chose "always allow" for that one capability on that one phone. allowAlwaysOffer decides which capabilities may offer that durable grant at all: every-capability (stock), standard-only (the elevated ones: front camera, screen capture, precise location, clipboard read; keep asking and an "always" answer is honoured for that one request only), or never. requestTimeoutSeconds is the deadline on three things at once: how long the phone has to answer, the deadline written into the request the phone receives, and how long the confirmation prompt itself stays open. device.location.precision gates the street-level fix (coarse-only refuses it and still serves approximate; ask-precise serves it but never remembers it), and device.clipboard.readMode gates reading the clipboard the same way; putting text ON the clipboard is a different capability and is unaffected. Captures from the camera and the screen are kept for capture.retentionHours and capped at capture.maxArtifacts, whichever bites first; housekeeping runs at every start and then every capture.sweepIntervalMinutes, deleting expired grants and captures and recording what it removed and why. A grant lasts grants.expiryDays and is never honoured past it, one phone holds at most grants.maxPerNode grants (the oldest are reaped past the cap), and the ledger of grants given, used, revoked and expired is kept for grants.auditRetentionDays. device.nodes.maxPaired is enforced at the moment a device pairs: at the cap a NEW device is refused with a message naming the setting, the cap and how many are already paired, while a phone that is already in the list simply supersedes its own record and keeps working. Lowering the cap below the number already paired unpairs no one; existing devices keep working and only the next new pairing is refused; a device moving off the legacy shared token to its own is exempt so it cannot be stranded. A nonsensical value anywhere here (zero, negative, not a number, an enum value that is not on the list) is read as the stock value rather than passed through, so a broken setting can neither lock you out of your own daemon nor widen the posture.',
100
+ conversationGate: 'What a message arriving from one of those channels does. By default it gets a conversational answer, and work is proposed and waits for your agreement rather than starting on its own; you can instead confirm every run, or restore the old behavior where a message starts work immediately. Also how long a pending proposal stays answerable and how many can wait at once. This governs messages from channels only; what you type here always runs, and schedules and triggers were authorized when created.',
101
101
  cloudflare: 'Optional Cloudflare control plane, batch queue, Worker, Tunnel, Access, DNS, KV, Durable Objects, Secrets Store, and R2 settings.',
102
102
  release: 'Release-channel preference.',
103
- power: 'Host sleep ownership. Keep-awake holds the host awake (the always-visible "sleep disabled" chip is the safety mechanism — no timer, no AC-only option); automatic inhibition keeps the host awake while real work runs, with an honest hard cap on that work hold.',
104
- memory: 'Memory provenance surfacing. Whether turns that drew on your standing memories show a small "used N memories" chip with a drill-in listing them. Off by default — when off, nothing is rendered and no context is added.',
103
+ power: 'Host sleep ownership. Keep-awake holds the host awake (the always-visible "sleep disabled" chip is the safety mechanism; no timer, no AC-only option); automatic inhibition keeps the host awake while real work runs, with an honest hard cap on that work hold.',
104
+ memory: 'Memory provenance surfacing. Whether turns that drew on your standing memories show a small "used N memories" chip with a drill-in listing them. Off by default: when off, nothing is rendered and no context is added.',
105
105
  danger: 'High-impact switches for daemon and HTTP listener behavior. These are operational overrides, not normal preferences.',
106
106
  tools: 'Tool LLM and helper model routing. Empty provider/model values inherit the active chat route unless a specific helper/tool route is set.',
107
107
  network: 'Combined network view for daemon control-plane, HTTP listener, browser web surface, and general outbound network settings.',
@@ -112,13 +112,13 @@ export const CATEGORY_INFO: Record<SettingsCategory, string> = {
112
112
  connections: 'Whether mail and calendar are actually usable right now. Each row is answered by asking the daemon that owns the connection, not by reading config here, so a row says ready only when a real request succeeded.',
113
113
  policy: 'Policy-as-code bundle loading: where the startup policy bundle is loaded from and its file path. Gated by the Policy-as-Code feature.',
114
114
  notifications: 'Notification router burst-suppression tuning: burst window, threshold, and cooldown. Gated by the Adaptive Notification Suppression feature.',
115
- relay: 'Outbound zero-knowledge relay reachability, for reaching this daemon from outside the LAN without opening an inbound port. Off by default — relay.enabled is the switch. The relay operator sees only ciphertext and connection metadata — self-host your own relay for full control.',
116
- learning: 'Idle-time memory consolidation: merging duplicate standing memory records and decaying/archiving stale ones. Off by default — nothing runs until enabled.',
117
- payments: 'Payment card on file for daemon-initiated purchases: card number, expiry, CVV, cardholder name, billing and shipping address, and whether the CVV is stored or requested at purchase time. Card fields are entered through /payments card (concealed input) and are secret-tier — never rendered in plaintext.',
118
- email: 'The daemon\'s own mailbox connection — IMAP and SMTP hosts, ports and security, the mailbox and drafts folders, and the username. Password fields hold secret-store references, never values; /google connects a Gmail-backed setup in one action.',
115
+ relay: 'Outbound zero-knowledge relay reachability, for reaching this daemon from outside the LAN without opening an inbound port. Off by default: relay.enabled is the switch. The relay operator sees only ciphertext and connection metadata; self-host your own relay for full control.',
116
+ learning: 'Idle-time memory consolidation: merging duplicate standing memory records and decaying/archiving stale ones. Off by default; nothing runs until enabled.',
117
+ payments: 'Payment card on file for daemon-initiated purchases: card number, expiry, CVV, cardholder name, billing and shipping address, and whether the CVV is stored or requested at purchase time. Card fields are entered through /payments card (concealed input) and are secret-tier; never rendered in plaintext.',
118
+ email: 'The daemon\'s own mailbox connection; IMAP and SMTP hosts, ports and security, the mailbox and drafts folders, and the username. Password fields hold secret-store references, never values; /google connects a Gmail-backed setup in one action.',
119
119
  calendar: 'Calendar connections the daemon reads and writes: the Google or Microsoft OAuth client for CalDAV-free access, or a read-only ICS URL. Secret fields hold secret-store references, never values.',
120
120
  google: 'The Google OAuth connection record: project id, publishing status, and the refresh-token reference the mail and calendar services share. Established by /google in one action; a dead grant is diagnosed in plain words there.',
121
- profile: 'What the platform knows about you — your name, how to reach you, where you are, how you like answers written, the people and places you mention — kept as one Markdown file at daemon scope that you can open and edit by hand at any time; your edits win and are never rewritten. These rows decide whether it is loaded at all, whether the assistant records facts it learns from things you say directly to it, whether it tells you in one line each time it does, whether the harmless part (how you are addressed, your city, your timezone, your formatting preferences, your style) is put in the model\'s context so it stops guessing, whether using a private detail such as your address is announced in the reply, whether settings left unset read their value from the profile, and where the file lives. Everything private — your name, contact details, home address, billing and shipping details, quiet hours, and the People, Places, Work and Notes sections — is never put in context in bulk and is reachable only by a named lookup that is disclosed when it happens. Run /profile to read the whole thing, /profile where <field> to see the surface, date and your exact words behind any recorded line, and /profile forget <field> to delete one.',
121
+ profile: 'What the platform knows about you: your name, how to reach you, where you are, how you like answers written, the people and places you mention, kept as one Markdown file at daemon scope that you can open and edit by hand at any time; your edits win and are never rewritten. These rows decide whether it is loaded at all, whether the assistant records facts it learns from things you say directly to it, whether it tells you in one line each time it does, whether the harmless part (how you are addressed, your city, your timezone, your formatting preferences, your style) is put in the model\'s context so it stops guessing, whether using a private detail such as your address is announced in the reply, whether settings left unset read their value from the profile, and where the file lives. Everything private: your name, contact details, home address, billing and shipping details, quiet hours, and the People, Places, Work and Notes sections, is never put in context in bulk and is reachable only by a named lookup that is disclosed when it happens. Run /profile to read the whole thing, /profile where <field> to see the surface, date and your exact words behind any recorded line, and /profile forget <field> to delete one.',
122
122
  };
123
123
 
124
124
  export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], string> = {
@@ -30,7 +30,7 @@ import {
30
30
 
31
31
  const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
32
32
  'display.themeMode': {
33
- auto: 'Probe the terminal background colour (OSC 11) once at startup and pick light or dark. Falls back to dark on unreadable/unsupported terminals. Only evaluated at startup — selecting auto takes effect next launch.',
33
+ auto: 'Probe the terminal background colour (OSC 11) once at startup and pick light or dark. Falls back to dark on unreadable/unsupported terminals. Only evaluated at startup: selecting auto takes effect next launch.',
34
34
  dark: 'Force the dark theme regardless of terminal background. Applies immediately.',
35
35
  light: 'Force the light theme regardless of terminal background. Applies immediately.',
36
36
  },
@@ -46,7 +46,7 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
46
46
  },
47
47
  'permissions.mode': {
48
48
  prompt: 'Normal: ask before powerful or risky actions according to tool policy.',
49
- plan: 'Plan mode: read-only planning posture — writes, commands, and network calls are blocked so the model can plan without changing anything. Toggle with /plan or Shift+Tab.',
49
+ plan: 'Plan mode: read-only planning posture; writes, commands, and network calls are blocked so the model can plan without changing anything. Toggle with /plan or Shift+Tab.',
50
50
  'accept-edits': 'Accept edits: file writes and edits are auto-approved, but exec, network, and escalations are still gated.',
51
51
  'allow-all': 'Auto: allow all actions without prompting. Fast, but removes an important safety gate.',
52
52
  custom: 'Use per-tool-class permission settings from the rows below.',
@@ -128,11 +128,11 @@ function formatDefaultValue(value: unknown): string {
128
128
 
129
129
  function currentSettingValue(modal: SettingsModal, entry: SettingEntry, selected: boolean): string {
130
130
  if (selected && modal.editingMode) {
131
- // Secret-backed keys (surfaces.*.botToken, .signingSecret, etc. — see
131
+ // Secret-backed keys (surfaces.*.botToken, .signingSecret, etc., see
132
132
  // secret-config.ts) must never echo the in-progress plaintext buffer:
133
133
  // not in the row, not in the "Current: ..." context line, not in search
134
134
  // results. Reuse the composer's concealed-input mask (concealed-input.ts)
135
- // rather than a second masking implementation — same bullet-per-character
135
+ // rather than a second masking implementation, same bullet-per-character
136
136
  // shape, so keystrokes still visibly register without revealing content.
137
137
  const buffer = isSecretConfigKey(entry.setting.key) ? maskConcealedText(modal.editBuffer) : modal.editBuffer;
138
138
  return `${buffer}${GLYPHS.surface.cursor}`;
@@ -254,7 +254,7 @@ function buildFlagContext(entry: SettingEntry | null): string[] {
254
254
  `State: ${displayState}`,
255
255
  // A capability the registry declares not operable reads as disabled no
256
256
  // matter what its settings key says. Without this line the row shows a
257
- // value of true beside a state of disabled and explains nothing — the
257
+ // value of true beside a state of disabled and explains nothing, the
258
258
  // written reason exists in the registry, so render it where the user meets
259
259
  // the contradiction rather than leaving it to be discovered.
260
260
  ...(feature.operable === false && feature.inoperableDetail
@@ -680,10 +680,10 @@ function footerText(modal: SettingsModal, width: number): string {
680
680
  { key: 'Esc', verb: 'Close' },
681
681
  ]));
682
682
  // Every topical category that hosts feature units flows through the default
683
- // settings footer below — Enter/Space toggles a feature-unit header exactly
683
+ // settings footer below, Enter/Space toggles a feature-unit header exactly
684
684
  // as it edits/toggles any setting row.
685
685
  // Default settings pane: tier the reset affordances by available width.
686
- // W<80: minimal — only the most critical action survives.
686
+ // W<80: minimal, only the most critical action survives.
687
687
  // W<160: compact but still shows both reset affordances.
688
688
  // W≥160: standard with all navigation tokens.
689
689
  if (width < 80)
@@ -720,18 +720,18 @@ export function renderSettingsModal(
720
720
  const metrics = getFullscreenWorkspaceMetrics({ width, height: viewportHeight });
721
721
  const categoryRows = renderCategories(modal, metrics.leftWidth - 2, metrics.bodyRows);
722
722
  // Documentation pane: long content SCROLLS (PgUp/PgDn) with honest
723
- // more-above/below markers — it is never silently clipped.
723
+ // more-above/below markers, it is never silently clipped.
724
724
  const allContextLines = buildContextLines(modal, metrics.contextWidth);
725
725
  const visibleContext = metrics.contextRows;
726
726
  const maxContextScroll = Math.max(0, allContextLines.length - visibleContext);
727
727
  const contextOffset = Math.min(Math.max(0, modal.contextScroll ?? 0), maxContextScroll);
728
728
  const windowedContext = allContextLines.slice(contextOffset, contextOffset + visibleContext);
729
729
  if (contextOffset > 0) {
730
- windowedContext[0] = `${GLYPHS.navigation.moreAbove} ${contextOffset} more line(s) above — PgUp`;
730
+ windowedContext[0] = `${GLYPHS.navigation.moreAbove} ${contextOffset} more line(s) above; PgUp`;
731
731
  }
732
732
  if (contextOffset + visibleContext < allContextLines.length) {
733
733
  const below = allContextLines.length - contextOffset - visibleContext;
734
- windowedContext[windowedContext.length - 1] = `${GLYPHS.navigation.moreBelow} ${below} more line(s) below — PgDn`;
734
+ windowedContext[windowedContext.length - 1] = `${GLYPHS.navigation.moreBelow} ${below} more line(s) below; PgDn`;
735
735
  }
736
736
  const contextRows = windowedContext.map((text, row): WorkspaceRow => {
737
737
  const selectedSetting = modal.getSelected();
@@ -11,7 +11,7 @@ export interface ShellFooterBuildOptions {
11
11
  readonly promptFocused?: boolean;
12
12
  /**
13
13
  * True when the panel workspace owns keyboard focus. Only consulted as a
14
- * fallback when `promptFocused` is not supplied — see buildShellFooter's
14
+ * fallback when `promptFocused` is not supplied, see buildShellFooter's
15
15
  * default expression. Callers that already compute `promptFocused`
16
16
  * themselves (main.ts does) do not need to also pass this.
17
17
  */
@@ -64,7 +64,7 @@ export interface ShellFooterBuildOptions {
64
64
  /**
65
65
  * The one-key retry/switch-model affordance's transient hint text (see
66
66
  * retry-affordance.ts). Rendered as its own line ABOVE the context
67
- * pressure hint while armed; present here only means "show it now" — the
67
+ * pressure hint while armed; present here only means "show it now", the
68
68
  * caller is responsible for passing null the instant it disarms, so this
69
69
  * is a time-bounded status line, never a lingering claim.
70
70
  */
@@ -83,10 +83,10 @@ export interface ShellFooterBuildOptions {
83
83
  readonly sessionSpineStatus?: 'online' | 'offline';
84
84
  /** The web surface's reachable URL, when that surface is enabled; a persistent footer segment. */
85
85
  readonly webSurfaceUrl?: string;
86
- /** True while power.keepAwake holds — renders the always-visible "sleep disabled" chip. */
86
+ /** True while power.keepAwake holds, renders the always-visible "sleep disabled" chip. */
87
87
  readonly powerKeepAwake?: boolean;
88
88
  /**
89
- * Live microphone state — a push-to-talk recording, or the wake detector for
89
+ * Live microphone state, a push-to-talk recording, or the wake detector for
90
90
  * as long as it runs. Rendered as a persistent row beside the process
91
91
  * indicator, because a capture device held open with nothing on screen saying
92
92
  * so is the one state a voice feature must never be in. Null (or a wake state
@@ -131,7 +131,7 @@ const DIM_STATUS_FG = '#64748b';
131
131
  let lastRenderedFooterHeight: { compact: boolean; height: number } | null = null;
132
132
 
133
133
  /**
134
- * The wrapped-prompt shape the composer reports each frame — the subset
134
+ * The wrapped-prompt shape the composer reports each frame, the subset
135
135
  * promptCursorOffset needs (see InputHandler.getWrappedPromptInfo).
136
136
  */
137
137
  export interface WrappedPromptCursorInfo {
@@ -226,17 +226,17 @@ export function buildShellFooter(
226
226
  // indicator: an open microphone is a live condition the user is acting inside,
227
227
  // while the process indicator is a background summary.
228
228
  lines.splice(inputBoxRows, 0, ...renderVoiceCaptureIndicator(options.width, options.voiceCapture ?? null), ...processIndicator);
229
- // Scriptable status line — dim informational line above the prompt. Unshifted
229
+ // Scriptable status line, dim informational line above the prompt. Unshifted
230
230
  // before the context hint so the context hint (if any) sits above it.
231
231
  if (options.scriptableStatusLine) {
232
232
  lines.unshift(UIFactory.stringToLine(options.scriptableStatusLine, options.width, { fg: DIM_STATUS_FG }));
233
233
  }
234
- // Passive context status hint — rendered as a dim informational line before the prompt.
234
+ // Passive context status hint, rendered as a dim informational line before the prompt.
235
235
  if (options.contextStatusHint) {
236
236
  const hintLine = UIFactory.stringToLine(options.contextStatusHint, options.width, { fg: DIM_STATUS_FG });
237
237
  lines.unshift(hintLine);
238
238
  }
239
- // Retry affordance — topmost of the passive hint lines while armed (an
239
+ // Retry affordance, topmost of the passive hint lines while armed (an
240
240
  // actionable, time-bounded prompt outranks the passive status hints
241
241
  // below it); simply absent the instant it disarms.
242
242
  if (options.retryHint) {
@@ -1,5 +1,5 @@
1
1
  // ---------------------------------------------------------------------------
2
- // status-glyphs.ts — canonical glyph map for status states.
2
+ // status-glyphs.ts, canonical glyph map for status states.
3
3
  //
4
4
  // Extracted as a neutral module so both status-token.ts and polish.ts can
5
5
  // import from here without creating a circular ESM dependency.
@@ -11,12 +11,12 @@
11
11
  // drift from the registry again. Re-exported under the historical name so
12
12
  // status-token.ts and polish.ts import unchanged.
13
13
  //
14
- // Glyphs (unchanged — this module's historical values, the TUI reference the
14
+ // Glyphs (unchanged, this module's historical values, the TUI reference the
15
15
  // contract was extracted from):
16
- // good ✓ (CHECK MARK U+2713) — GLYPHS.status.success
17
- // warn ⚠ (WARNING SIGN U+26A0) — GLYPHS.status.warn
18
- // bad ✕ (MULTIPLICATION X U+2715) — GLYPHS.status.failure
19
- // info ○ (WHITE CIRCLE U+25CB) — GLYPHS.status.info
16
+ // good ✓ (CHECK MARK U+2713) , GLYPHS.status.success
17
+ // warn ⚠ (WARNING SIGN U+26A0) , GLYPHS.status.warn
18
+ // bad ✕ (MULTIPLICATION X U+2715), GLYPHS.status.failure
19
+ // info ○ (WHITE CIRCLE U+25CB) , GLYPHS.status.info
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
22
  export { STATE_GLYPHS, type StatusState } from '@pellux/goodvibes-sdk/platform/presentation';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * SyntaxHighlighter — Tree-sitter-powered syntax highlighting for code blocks.
2
+ * SyntaxHighlighter, Tree-sitter-powered syntax highlighting for code blocks.
3
3
  *
4
4
  * Designed for the synchronous TUI render loop:
5
5
  * - Initializes tree-sitter WASM and grammar parsers asynchronously in background
@@ -372,7 +372,6 @@ function isLeafLike(node: Node): boolean {
372
372
  * Handles multi-line spans (e.g., block comments, template literals).
373
373
  */
374
374
  function spansToLines(spans: Span[], codeLines: string[]): HighlightedLine[] {
375
- // Initialize result: one entry per code line, each starting with no tokens
376
375
  const result: HighlightedLine[] = codeLines.map(() => []);
377
376
 
378
377
  // Track the current position to emit default-colored text for gaps
@@ -491,7 +490,7 @@ export class SyntaxHighlighter {
491
490
  }
492
491
 
493
492
  /**
494
- * Schedule an async parse. Fires and forgets — result lands in cache.
493
+ * Schedule an async parse. Fires and forgets, result lands in cache.
495
494
  * Callers will pick it up on the next render cycle.
496
495
  */
497
496
  private scheduleParse(code: string, langId: string, key: string): void {
@@ -15,7 +15,7 @@ export function classifySystemMessage(content: string): SystemMessageType {
15
15
 
16
16
  // [WRFC] messages
17
17
  if (/^\[WRFC\]/.test(content)) {
18
- // Failed gate result → error (red) — must be checked before generic FAILED
18
+ // Failed gate result → error (red), must be checked before generic FAILED
19
19
  if (/Gate:.*FAILED/i.test(content)) return 'error';
20
20
  // Hard failures and cascade aborts → error (red)
21
21
  if (/FAILED|cascade abort/i.test(content)) return 'error';
@@ -40,13 +40,13 @@ export function classifySystemMessage(content: string): SystemMessageType {
40
40
  // [Plan] messages are always informational
41
41
  if (/^\[Plan\]/.test(content)) return 'info';
42
42
 
43
- // [Model] messages — "Unknown model" is a warning, switch is info
43
+ // [Model] messages, "Unknown model" is a warning, switch is info
44
44
  if (/^\[Model\]/.test(content)) {
45
45
  if (/Unknown model/i.test(content)) return 'warning';
46
46
  return 'info';
47
47
  }
48
48
 
49
- // [Routing] chip — a mid-session model change is informational (the [Failover]
49
+ // [Routing] chip, a mid-session model change is informational (the [Failover]
50
50
  // line, not this, carries the alarming transport-error cases).
51
51
  if (/^\[Routing\]/.test(content)) return 'info';
52
52
 
@@ -43,7 +43,7 @@ export interface TabStripConfig {
43
43
  readonly overflowIndicatorLeft?: string;
44
44
  /**
45
45
  * Optional callback invoked with the absolute column ranges of each rendered
46
- * tab. Used by the compositor to hit-test mouse clicks onto tabs. Additive —
46
+ * tab. Used by the compositor to hit-test mouse clicks onto tabs. Additive,
47
47
  * the function still returns a `Line` so existing callers are unaffected.
48
48
  */
49
49
  readonly onLayout?: (regions: readonly TabHitRegion[]) => void;
@@ -91,7 +91,7 @@ function makeSegments(
91
91
  let used = entryWidths[activeIndex] + closing;
92
92
 
93
93
  if (totalAll <= maxWidth) {
94
- // Everything fits — show all tabs, no windowing.
94
+ // Everything fits, show all tabs, no windowing.
95
95
  start = 0;
96
96
  end = n - 1;
97
97
  } else {
@@ -1,15 +1,15 @@
1
1
  /**
2
- * term-caps.ts — Terminal capability detection and color downsampling.
2
+ * term-caps.ts, Terminal capability detection and color downsampling.
3
3
  *
4
4
  * Probes the terminal's color support level once at renderer init and exposes
5
5
  * a `downsampleColor` function that maps hex/RGB color strings to the
6
6
  * appropriate SGR parameter string for the detected capability level.
7
7
  *
8
8
  * Capability levels (in ascending order):
9
- * none — NO_COLOR set or TERM=dumb; emit no SGR color sequences.
10
- * basic16 — 16 ANSI colors (\x1b[30-37m / \x1b[90-97m / \x1b[40-47m).
11
- * ansi256 — 256-color palette (\x1b[38;5;Nm).
12
- * truecolor — 24-bit RGB (\x1b[38;2;R;G;Bm).
9
+ * none , NO_COLOR set or TERM=dumb; emit no SGR color sequences.
10
+ * basic16 , 16 ANSI colors (\x1b[30-37m / \x1b[90-97m / \x1b[40-47m).
11
+ * ansi256 , 256-color palette (\x1b[38;5;Nm).
12
+ * truecolor, 24-bit RGB (\x1b[38;2;R;G;Bm).
13
13
  *
14
14
  * References:
15
15
  * - NO_COLOR spec: https://no-color.org/ (any non-empty value disables color)
@@ -89,7 +89,7 @@ function parseHex(hex: string): [number, number, number] | null {
89
89
  * Parse a sanitized color string in one of two forms:
90
90
  * - "#rrggbb" → RGB tuple
91
91
  * - "r;g;b" → RGB tuple (already decomposed by sanitizeColor)
92
- * - "N" → null (already a palette index — pass through)
92
+ * - "N" → null (already a palette index, pass through)
93
93
  * Returns [r, g, b] or null (non-RGB / palette index).
94
94
  */
95
95
  function parseRgbString(color: string): [number, number, number] | null {
@@ -114,7 +114,7 @@ function parseRgbString(color: string): [number, number, number] | null {
114
114
  * Map [r, g, b] (0-255 each) to the nearest xterm-256 palette index.
115
115
  *
116
116
  * The 256-color palette is structured as:
117
- * 0-15: System colors (16 named colors) — we avoid these for predictability
117
+ * 0-15: System colors (16 named colors), we avoid these for predictability
118
118
  * and instead target the 6×6×6 cube + grayscale ramp.
119
119
  * 16-231: 6×6×6 color cube, index = 16 + 36*r6 + 6*g6 + b6
120
120
  * where r6/g6/b6 ∈ 0-5 map via [0,95,135,175,215,255]
@@ -240,11 +240,11 @@ function ansi16FgToBg(fgCode: number): number {
240
240
  * sanitizeColor() decomposition. Supported forms:
241
241
  * - "#rrggbb" hex
242
242
  * - "r;g;b" pre-decomposed RGB (from sanitizeColor)
243
- * - "N" already a palette index — returned as-is for ansi256/truecolor,
243
+ * - "N" already a palette index, returned as-is for ansi256/truecolor,
244
244
  * or omitted for none
245
245
  *
246
246
  * @param caps - The probed terminal capabilities.
247
- * @param role - 'fg' or 'bg' — determines which SGR range to use for basic16.
247
+ * @param role - 'fg' or 'bg', determines which SGR range to use for basic16.
248
248
  *
249
249
  * @returns The SGR parameter string suitable for embedding in \x1b[38;2;...m
250
250
  * (truecolor), \x1b[38;5;Nm (ansi256), \x1b[Nm (basic16 fg), etc.
@@ -257,7 +257,7 @@ function ansi16FgToBg(fgCode: number): number {
257
257
  * style += isRgb ? `\x1b[38;2;${fg}m` : `\x1b[38;5;${fg}m`;
258
258
  * }
259
259
  *
260
- * For basic16 the caller must use a different SGR prefix — see applyStyles.
260
+ * For basic16 the caller must use a different SGR prefix, see applyStyles.
261
261
  */
262
262
  export function downsampleColor(
263
263
  rawColor: string,
@@ -272,13 +272,13 @@ export function downsampleColor(
272
272
  if (caps.capability === 'truecolor') {
273
273
  // Pass hex through as r;g;b decomposed, pass r;g;b through as-is
274
274
  if (rgb) return `${rgb[0]};${rgb[1]};${rgb[2]}`;
275
- // Already a palette index — emit as 256-color
275
+ // Already a palette index, emit as 256-color
276
276
  return rawColor; // caller will use 38;5;N or 48;5;N
277
277
  }
278
278
 
279
279
  if (caps.capability === 'ansi256') {
280
280
  if (rgb) return String(nearestAnsi256(rgb[0], rgb[1], rgb[2]));
281
- // Already a palette index — pass through
281
+ // Already a palette index, pass through
282
282
  return rawColor;
283
283
  }
284
284