@pellux/goodvibes-tui 0.18.4

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 (732) hide show
  1. package/.goodvibes/GOODVIBES.md +35 -0
  2. package/.goodvibes/agents/reviewer.md +89 -0
  3. package/.goodvibes/skills/add-provider/SKILL.md +199 -0
  4. package/CHANGELOG.md +1681 -0
  5. package/README.md +1607 -0
  6. package/bin/goodvibes +66 -0
  7. package/docs/README.md +32 -0
  8. package/docs/foundation-artifacts/README.md +16 -0
  9. package/docs/foundation-artifacts/knowledge-graphql.graphql +397 -0
  10. package/docs/foundation-artifacts/knowledge-store.sql +183 -0
  11. package/docs/foundation-artifacts/operator-contract.json +55157 -0
  12. package/docs/foundation-artifacts/peer-contract.json +2384 -0
  13. package/package.json +114 -0
  14. package/scripts/postinstall.mjs +203 -0
  15. package/src/acp/connection.ts +447 -0
  16. package/src/acp/index.ts +7 -0
  17. package/src/acp/manager.ts +133 -0
  18. package/src/adapters/bluebubbles/index.ts +127 -0
  19. package/src/adapters/discord/index.ts +297 -0
  20. package/src/adapters/github/index.ts +73 -0
  21. package/src/adapters/google-chat/index.ts +119 -0
  22. package/src/adapters/imessage/index.ts +92 -0
  23. package/src/adapters/index.ts +15 -0
  24. package/src/adapters/matrix/index.ts +116 -0
  25. package/src/adapters/mattermost/index.ts +151 -0
  26. package/src/adapters/msteams/index.ts +180 -0
  27. package/src/adapters/ntfy/index.ts +118 -0
  28. package/src/adapters/signal/index.ts +92 -0
  29. package/src/adapters/slack/index.ts +323 -0
  30. package/src/adapters/telegram/index.ts +160 -0
  31. package/src/adapters/types.ts +97 -0
  32. package/src/adapters/webhook/index.ts +178 -0
  33. package/src/adapters/whatsapp/index.ts +135 -0
  34. package/src/agents/message-bus-core.ts +312 -0
  35. package/src/agents/message-bus.ts +2 -0
  36. package/src/agents/orchestrator-prompts.ts +351 -0
  37. package/src/agents/orchestrator-runner.ts +668 -0
  38. package/src/agents/orchestrator.ts +437 -0
  39. package/src/agents/session.ts +108 -0
  40. package/src/agents/worktree.ts +153 -0
  41. package/src/agents/wrfc-config.ts +47 -0
  42. package/src/agents/wrfc-controller.ts +747 -0
  43. package/src/agents/wrfc-gate-runtime.ts +75 -0
  44. package/src/agents/wrfc-reporting.ts +284 -0
  45. package/src/agents/wrfc-runtime-events.ts +150 -0
  46. package/src/agents/wrfc-types.ts +67 -0
  47. package/src/automation/delivery-manager.ts +368 -0
  48. package/src/automation/index.ts +72 -0
  49. package/src/automation/manager-runtime-delivery.ts +139 -0
  50. package/src/automation/manager-runtime-events.ts +131 -0
  51. package/src/automation/manager-runtime-execution.ts +511 -0
  52. package/src/automation/manager-runtime-helpers.ts +433 -0
  53. package/src/automation/manager-runtime-job-mutations.ts +175 -0
  54. package/src/automation/manager-runtime-reconcile.ts +148 -0
  55. package/src/automation/manager-runtime-scheduling.ts +189 -0
  56. package/src/automation/manager-runtime-sync.ts +54 -0
  57. package/src/automation/manager-runtime.ts +721 -0
  58. package/src/automation/manager.ts +10 -0
  59. package/src/automation/service.ts +242 -0
  60. package/src/channels/builtin/account-actions.ts +490 -0
  61. package/src/channels/builtin/accounts.ts +433 -0
  62. package/src/channels/builtin/contracts.ts +405 -0
  63. package/src/channels/builtin/plugins.ts +308 -0
  64. package/src/channels/builtin/rendering.ts +174 -0
  65. package/src/channels/builtin/setup-schema.ts +504 -0
  66. package/src/channels/builtin/shared.ts +96 -0
  67. package/src/channels/builtin/surfaces.ts +57 -0
  68. package/src/channels/builtin/targets.ts +693 -0
  69. package/src/channels/builtin-runtime.ts +443 -0
  70. package/src/channels/delivery/shared.ts +199 -0
  71. package/src/channels/delivery/strategies-bridge.ts +246 -0
  72. package/src/channels/delivery/strategies-core.ts +299 -0
  73. package/src/channels/delivery/strategies-enterprise.ts +178 -0
  74. package/src/channels/delivery/types.ts +59 -0
  75. package/src/channels/delivery-router.ts +127 -0
  76. package/src/channels/index.ts +77 -0
  77. package/src/channels/plugin-registry.ts +551 -0
  78. package/src/channels/provider-runtime.ts +330 -0
  79. package/src/channels/reply-pipeline.ts +522 -0
  80. package/src/channels/route-manager.ts +340 -0
  81. package/src/channels/surface-registry.ts +186 -0
  82. package/src/config/helper-model.ts +233 -0
  83. package/src/config/index.ts +193 -0
  84. package/src/config/manager.ts +404 -0
  85. package/src/config/secrets.ts +547 -0
  86. package/src/config/service-registry.ts +329 -0
  87. package/src/config/subscription-auth.ts +31 -0
  88. package/src/config/subscription-providers.ts +127 -0
  89. package/src/config/tool-llm.ts +110 -0
  90. package/src/control-plane/approval-broker.ts +351 -0
  91. package/src/control-plane/gateway.ts +713 -0
  92. package/src/control-plane/index.ts +54 -0
  93. package/src/control-plane/media-contract-schemas.ts +208 -0
  94. package/src/control-plane/method-catalog-admin.ts +136 -0
  95. package/src/control-plane/method-catalog-channels.ts +591 -0
  96. package/src/control-plane/method-catalog-control-automation.ts +475 -0
  97. package/src/control-plane/method-catalog-control-core.ts +594 -0
  98. package/src/control-plane/method-catalog-control.ts +8 -0
  99. package/src/control-plane/method-catalog-events.ts +74 -0
  100. package/src/control-plane/method-catalog-knowledge.ts +531 -0
  101. package/src/control-plane/method-catalog-media.ts +279 -0
  102. package/src/control-plane/method-catalog-runtime.ts +304 -0
  103. package/src/control-plane/method-catalog-shared.ts +223 -0
  104. package/src/control-plane/method-catalog.ts +242 -0
  105. package/src/control-plane/operator-contract-schemas-admin.ts +639 -0
  106. package/src/control-plane/operator-contract-schemas-channels.ts +375 -0
  107. package/src/control-plane/operator-contract-schemas-control.ts +226 -0
  108. package/src/control-plane/operator-contract-schemas-domains.ts +4 -0
  109. package/src/control-plane/operator-contract-schemas-knowledge.ts +582 -0
  110. package/src/control-plane/operator-contract-schemas-media.ts +297 -0
  111. package/src/control-plane/operator-contract-schemas-permissions.ts +100 -0
  112. package/src/control-plane/operator-contract-schemas-remote.ts +38 -0
  113. package/src/control-plane/operator-contract-schemas-runtime.ts +563 -0
  114. package/src/control-plane/operator-contract-schemas-shared.ts +85 -0
  115. package/src/control-plane/operator-contract-schemas-telemetry.ts +349 -0
  116. package/src/control-plane/operator-contract-schemas.ts +6 -0
  117. package/src/control-plane/operator-contract.ts +163 -0
  118. package/src/control-plane/session-broker.ts +780 -0
  119. package/src/core/compaction-sections.ts +492 -0
  120. package/src/core/compaction-types.ts +147 -0
  121. package/src/core/composer-state.ts +59 -0
  122. package/src/core/context-compaction.ts +542 -0
  123. package/src/core/conversation-compaction.ts +68 -0
  124. package/src/core/conversation-diff.ts +55 -0
  125. package/src/core/conversation-rendering.ts +343 -0
  126. package/src/core/conversation-utils.ts +72 -0
  127. package/src/core/conversation.ts +775 -0
  128. package/src/core/event-replay.ts +287 -0
  129. package/src/core/orchestrator-context-runtime.ts +407 -0
  130. package/src/core/orchestrator-follow-up-runtime.ts +134 -0
  131. package/src/core/orchestrator-runtime.ts +132 -0
  132. package/src/core/orchestrator-tool-runtime.ts +468 -0
  133. package/src/core/orchestrator-turn-helpers.ts +355 -0
  134. package/src/core/orchestrator-turn-loop.ts +443 -0
  135. package/src/core/orchestrator.ts +733 -0
  136. package/src/core/plan-command-handler.ts +169 -0
  137. package/src/core/system-message-router.ts +210 -0
  138. package/src/core/transcript-events/classify.ts +95 -0
  139. package/src/core/transcript-events/index.ts +15 -0
  140. package/src/daemon/cli.ts +88 -0
  141. package/src/daemon/control-plane.ts +522 -0
  142. package/src/daemon/facade-composition.ts +397 -0
  143. package/src/daemon/facade.ts +638 -0
  144. package/src/daemon/helpers.ts +74 -0
  145. package/src/daemon/http/router-route-contexts.ts +370 -0
  146. package/src/daemon/http/router.ts +531 -0
  147. package/src/daemon/http-listener.ts +301 -0
  148. package/src/daemon/index.ts +3 -0
  149. package/src/daemon/server.ts +1 -0
  150. package/src/daemon/service-manager.ts +413 -0
  151. package/src/daemon/surface-actions.ts +183 -0
  152. package/src/daemon/surface-delivery.ts +530 -0
  153. package/src/daemon/surface-policy.ts +60 -0
  154. package/src/daemon/transport-events.ts +110 -0
  155. package/src/daemon/types.ts +191 -0
  156. package/src/export/markdown.ts +213 -0
  157. package/src/export/session-export.ts +633 -0
  158. package/src/git/index.ts +1 -0
  159. package/src/git/service.ts +414 -0
  160. package/src/hooks/chain-engine.ts +414 -0
  161. package/src/hooks/dispatcher.ts +414 -0
  162. package/src/hooks/hook-api.ts +170 -0
  163. package/src/hooks/index.ts +48 -0
  164. package/src/hooks/runners/agent.ts +93 -0
  165. package/src/hooks/runners/prompt.ts +69 -0
  166. package/src/hooks/workbench.ts +360 -0
  167. package/src/input/autocomplete.ts +96 -0
  168. package/src/input/bookmark-modal.ts +115 -0
  169. package/src/input/command-registry.ts +300 -0
  170. package/src/input/commands/branch-runtime.ts +72 -0
  171. package/src/input/commands/config.ts +515 -0
  172. package/src/input/commands/control-room-runtime.ts +255 -0
  173. package/src/input/commands/conversation-runtime.ts +207 -0
  174. package/src/input/commands/diff-runtime.ts +161 -0
  175. package/src/input/commands/discovery-runtime.ts +45 -0
  176. package/src/input/commands/eval.ts +204 -0
  177. package/src/input/commands/experience-runtime.ts +278 -0
  178. package/src/input/commands/git-runtime.ts +81 -0
  179. package/src/input/commands/guidance-runtime.ts +101 -0
  180. package/src/input/commands/health-runtime.ts +434 -0
  181. package/src/input/commands/hooks-runtime.ts +148 -0
  182. package/src/input/commands/incident-runtime.ts +95 -0
  183. package/src/input/commands/integration-runtime.ts +394 -0
  184. package/src/input/commands/intelligence-runtime.ts +223 -0
  185. package/src/input/commands/knowledge.ts +368 -0
  186. package/src/input/commands/local-auth-runtime.ts +105 -0
  187. package/src/input/commands/local-provider-runtime.ts +170 -0
  188. package/src/input/commands/local-runtime.ts +458 -0
  189. package/src/input/commands/local-setup-review.ts +192 -0
  190. package/src/input/commands/local-setup-transfer.ts +134 -0
  191. package/src/input/commands/local-setup.ts +292 -0
  192. package/src/input/commands/managed-runtime.ts +208 -0
  193. package/src/input/commands/marketplace-runtime.ts +290 -0
  194. package/src/input/commands/mcp-runtime.ts +202 -0
  195. package/src/input/commands/memory-product-runtime.ts +111 -0
  196. package/src/input/commands/memory.ts +151 -0
  197. package/src/input/commands/notify-runtime.ts +83 -0
  198. package/src/input/commands/operator-panel-runtime.ts +141 -0
  199. package/src/input/commands/operator-runtime.ts +392 -0
  200. package/src/input/commands/permissions-runtime.ts +104 -0
  201. package/src/input/commands/planning-runtime.ts +97 -0
  202. package/src/input/commands/platform-access-runtime.ts +422 -0
  203. package/src/input/commands/platform-runtime.ts +6 -0
  204. package/src/input/commands/platform-sandbox-qemu.ts +137 -0
  205. package/src/input/commands/platform-sandbox-runtime.ts +406 -0
  206. package/src/input/commands/platform-sandbox-session.ts +128 -0
  207. package/src/input/commands/platform-services-runtime.ts +246 -0
  208. package/src/input/commands/policy-dispatch.ts +339 -0
  209. package/src/input/commands/policy.ts +17 -0
  210. package/src/input/commands/product-runtime.ts +351 -0
  211. package/src/input/commands/profile-sync-runtime.ts +99 -0
  212. package/src/input/commands/provider-accounts-runtime.ts +113 -0
  213. package/src/input/commands/provider.ts +363 -0
  214. package/src/input/commands/quit-shared.ts +162 -0
  215. package/src/input/commands/recall-bundle.ts +132 -0
  216. package/src/input/commands/recall-capture.ts +152 -0
  217. package/src/input/commands/recall-query.ts +229 -0
  218. package/src/input/commands/recall-review.ts +98 -0
  219. package/src/input/commands/recall-shared.ts +22 -0
  220. package/src/input/commands/remote-runtime-pool.ts +106 -0
  221. package/src/input/commands/remote-runtime-setup.ts +199 -0
  222. package/src/input/commands/remote-runtime.ts +531 -0
  223. package/src/input/commands/replay-runtime.ts +18 -0
  224. package/src/input/commands/runtime-services.ts +279 -0
  225. package/src/input/commands/schedule-runtime.ts +332 -0
  226. package/src/input/commands/services-runtime.ts +207 -0
  227. package/src/input/commands/session-content.ts +408 -0
  228. package/src/input/commands/session-workflow.ts +464 -0
  229. package/src/input/commands/session.ts +376 -0
  230. package/src/input/commands/settings-sync-runtime.ts +173 -0
  231. package/src/input/commands/share-runtime.ts +114 -0
  232. package/src/input/commands/shell-core.ts +320 -0
  233. package/src/input/commands/skills-runtime.ts +221 -0
  234. package/src/input/commands/subscription-runtime.ts +434 -0
  235. package/src/input/commands/tasks-runtime.ts +230 -0
  236. package/src/input/commands/teamwork-runtime.ts +374 -0
  237. package/src/input/commands/teleport-runtime.ts +57 -0
  238. package/src/input/commands/worktree-runtime.ts +137 -0
  239. package/src/input/commands.ts +127 -0
  240. package/src/input/file-picker.ts +192 -0
  241. package/src/input/handler-command-route.ts +106 -0
  242. package/src/input/handler-content-actions.ts +465 -0
  243. package/src/input/handler-feed-routes.ts +541 -0
  244. package/src/input/handler-feed.ts +361 -0
  245. package/src/input/handler-modal-routes.ts +335 -0
  246. package/src/input/handler-modal-stack.ts +237 -0
  247. package/src/input/handler-modal-token-routes.ts +272 -0
  248. package/src/input/handler-picker-routes.ts +416 -0
  249. package/src/input/handler-prompt-buffer.ts +320 -0
  250. package/src/input/handler-shortcuts.ts +195 -0
  251. package/src/input/handler-ui-state.ts +294 -0
  252. package/src/input/handler.ts +798 -0
  253. package/src/input/input-history.ts +267 -0
  254. package/src/input/keybindings.ts +256 -0
  255. package/src/input/model-picker.ts +730 -0
  256. package/src/input/panel-integration-actions.ts +77 -0
  257. package/src/input/profile-picker-modal.ts +222 -0
  258. package/src/input/search.ts +100 -0
  259. package/src/input/selection-modal.ts +163 -0
  260. package/src/input/selection.ts +135 -0
  261. package/src/input/session-picker-modal.ts +136 -0
  262. package/src/input/settings-modal.ts +718 -0
  263. package/src/input/submission-intent.ts +18 -0
  264. package/src/input/submission-router.ts +64 -0
  265. package/src/integrations/index.ts +42 -0
  266. package/src/integrations/notifier.ts +206 -0
  267. package/src/integrations/webhooks.ts +177 -0
  268. package/src/knowledge/consolidation.ts +346 -0
  269. package/src/knowledge/graphql.ts +324 -0
  270. package/src/knowledge/index.ts +60 -0
  271. package/src/knowledge/ingest-compile.ts +386 -0
  272. package/src/knowledge/ingest-context.ts +18 -0
  273. package/src/knowledge/ingest-inputs.ts +387 -0
  274. package/src/knowledge/ingest.ts +20 -0
  275. package/src/knowledge/internal.ts +257 -0
  276. package/src/knowledge/knowledge-api.ts +432 -0
  277. package/src/knowledge/lint.ts +121 -0
  278. package/src/knowledge/memory-sync.ts +62 -0
  279. package/src/knowledge/packet.ts +370 -0
  280. package/src/knowledge/scheduling.ts +283 -0
  281. package/src/knowledge/service.ts +715 -0
  282. package/src/main.ts +798 -0
  283. package/src/mcp/client.ts +383 -0
  284. package/src/mcp/index.ts +12 -0
  285. package/src/mcp/mcp-api.ts +90 -0
  286. package/src/mcp/registry.ts +508 -0
  287. package/src/media/builtin-image-understanding.ts +303 -0
  288. package/src/media/builtin-providers.ts +26 -0
  289. package/src/media/index.ts +18 -0
  290. package/src/multimodal/index.ts +13 -0
  291. package/src/multimodal/service.ts +492 -0
  292. package/src/panels/agent-inspector-panel.ts +515 -0
  293. package/src/panels/agent-inspector-shared.ts +94 -0
  294. package/src/panels/agent-logs-panel.ts +539 -0
  295. package/src/panels/agent-logs-shared.ts +129 -0
  296. package/src/panels/approval-panel.ts +169 -0
  297. package/src/panels/automation-control-panel.ts +253 -0
  298. package/src/panels/base-panel.ts +72 -0
  299. package/src/panels/builtin/agent.ts +88 -0
  300. package/src/panels/builtin/development.ts +111 -0
  301. package/src/panels/builtin/knowledge.ts +26 -0
  302. package/src/panels/builtin/operations.ts +385 -0
  303. package/src/panels/builtin/session.ts +61 -0
  304. package/src/panels/builtin/shared.ts +240 -0
  305. package/src/panels/builtin-panels.ts +23 -0
  306. package/src/panels/cockpit-panel.ts +183 -0
  307. package/src/panels/communication-panel.ts +191 -0
  308. package/src/panels/context-visualizer-panel.ts +199 -0
  309. package/src/panels/control-plane-panel.ts +266 -0
  310. package/src/panels/cost-tracker-panel.ts +444 -0
  311. package/src/panels/debug-panel.ts +432 -0
  312. package/src/panels/diff-panel.ts +518 -0
  313. package/src/panels/docs-panel.ts +283 -0
  314. package/src/panels/eval-panel.ts +399 -0
  315. package/src/panels/file-explorer-panel.ts +556 -0
  316. package/src/panels/file-preview-panel.ts +412 -0
  317. package/src/panels/forensics-panel.ts +364 -0
  318. package/src/panels/git-panel.ts +630 -0
  319. package/src/panels/hooks-panel.ts +274 -0
  320. package/src/panels/incident-review-panel.ts +247 -0
  321. package/src/panels/index.ts +48 -0
  322. package/src/panels/intelligence-panel.ts +176 -0
  323. package/src/panels/knowledge-panel.ts +328 -0
  324. package/src/panels/local-auth-panel.ts +146 -0
  325. package/src/panels/marketplace-panel.ts +223 -0
  326. package/src/panels/mcp-panel.ts +260 -0
  327. package/src/panels/memory-panel.ts +293 -0
  328. package/src/panels/ops-control-panel.ts +184 -0
  329. package/src/panels/ops-strategy-panel.ts +235 -0
  330. package/src/panels/orchestration-panel.ts +254 -0
  331. package/src/panels/panel-list-panel.ts +508 -0
  332. package/src/panels/panel-manager.ts +538 -0
  333. package/src/panels/panel-picker.ts +106 -0
  334. package/src/panels/plan-dashboard-panel.ts +272 -0
  335. package/src/panels/plugins-panel.ts +201 -0
  336. package/src/panels/policy-panel.ts +308 -0
  337. package/src/panels/polish.ts +668 -0
  338. package/src/panels/provider-account-snapshot.ts +259 -0
  339. package/src/panels/provider-accounts-panel.ts +221 -0
  340. package/src/panels/provider-health-domains.ts +211 -0
  341. package/src/panels/provider-health-panel.ts +725 -0
  342. package/src/panels/provider-health-tracker.ts +115 -0
  343. package/src/panels/provider-stats-panel.ts +366 -0
  344. package/src/panels/remote-panel.ts +449 -0
  345. package/src/panels/routes-panel.ts +228 -0
  346. package/src/panels/sandbox-panel.ts +289 -0
  347. package/src/panels/schedule-panel.ts +344 -0
  348. package/src/panels/search-focus.ts +32 -0
  349. package/src/panels/security-panel.ts +329 -0
  350. package/src/panels/services-panel.ts +271 -0
  351. package/src/panels/session-browser-panel.ts +399 -0
  352. package/src/panels/session-maintenance.ts +125 -0
  353. package/src/panels/settings-sync-panel.ts +164 -0
  354. package/src/panels/skills-panel.ts +475 -0
  355. package/src/panels/subscription-panel.ts +273 -0
  356. package/src/panels/symbol-outline-panel.ts +486 -0
  357. package/src/panels/system-messages-panel.ts +224 -0
  358. package/src/panels/tasks-panel.ts +448 -0
  359. package/src/panels/thinking-panel.ts +304 -0
  360. package/src/panels/token-budget-panel.ts +469 -0
  361. package/src/panels/tool-inspector-panel.ts +434 -0
  362. package/src/panels/types.ts +44 -0
  363. package/src/panels/watchers-panel.ts +241 -0
  364. package/src/panels/welcome-panel.ts +64 -0
  365. package/src/panels/worktree-panel.ts +180 -0
  366. package/src/panels/wrfc-panel.ts +480 -0
  367. package/src/permissions/briefs/build.ts +88 -0
  368. package/src/permissions/manager.ts +356 -0
  369. package/src/permissions/prompt.ts +184 -0
  370. package/src/plugins/api.ts +383 -0
  371. package/src/plugins/loader.ts +304 -0
  372. package/src/plugins/manager.ts +481 -0
  373. package/src/profiles/shape.ts +58 -0
  374. package/src/providers/amazon-bedrock-mantle.ts +50 -0
  375. package/src/providers/amazon-bedrock.ts +61 -0
  376. package/src/providers/anthropic-compat.ts +373 -0
  377. package/src/providers/anthropic-sdk-provider.ts +230 -0
  378. package/src/providers/anthropic-vertex.ts +59 -0
  379. package/src/providers/anthropic.ts +469 -0
  380. package/src/providers/auto-register.ts +417 -0
  381. package/src/providers/builtin-catalog.ts +326 -0
  382. package/src/providers/builtin-registry.ts +575 -0
  383. package/src/providers/cache-planner.ts +258 -0
  384. package/src/providers/capabilities.ts +601 -0
  385. package/src/providers/custom-loader.ts +425 -0
  386. package/src/providers/discovered-compat.ts +18 -0
  387. package/src/providers/discovered-factory.ts +61 -0
  388. package/src/providers/discovered-traits.ts +138 -0
  389. package/src/providers/gemini.ts +462 -0
  390. package/src/providers/github-copilot.ts +254 -0
  391. package/src/providers/index.ts +47 -0
  392. package/src/providers/interface.ts +185 -0
  393. package/src/providers/llama-cpp.ts +402 -0
  394. package/src/providers/lm-studio-helpers.ts +367 -0
  395. package/src/providers/lm-studio.ts +484 -0
  396. package/src/providers/model-catalog-cache.ts +221 -0
  397. package/src/providers/model-catalog-notifications.ts +97 -0
  398. package/src/providers/model-catalog-synthetic.ts +202 -0
  399. package/src/providers/model-catalog.ts +211 -0
  400. package/src/providers/model-limits.ts +280 -0
  401. package/src/providers/ollama.ts +469 -0
  402. package/src/providers/openai-codex.ts +472 -0
  403. package/src/providers/openai-compat.ts +615 -0
  404. package/src/providers/openai.ts +231 -0
  405. package/src/providers/optimizer.ts +381 -0
  406. package/src/providers/provider-api.ts +553 -0
  407. package/src/providers/registry-helpers.ts +34 -0
  408. package/src/providers/registry-models.ts +77 -0
  409. package/src/providers/registry-types.ts +67 -0
  410. package/src/providers/registry.ts +729 -0
  411. package/src/providers/runtime-metadata.ts +149 -0
  412. package/src/providers/runtime-snapshot.ts +130 -0
  413. package/src/providers/synthetic.ts +561 -0
  414. package/src/providers/tier-prompts.ts +84 -0
  415. package/src/providers/tool-formats.ts +414 -0
  416. package/src/renderer/agent-detail-modal.ts +285 -0
  417. package/src/renderer/autocomplete-overlay.ts +154 -0
  418. package/src/renderer/block-actions.ts +76 -0
  419. package/src/renderer/bookmark-modal.ts +101 -0
  420. package/src/renderer/bottom-bar.ts +58 -0
  421. package/src/renderer/buffer.ts +34 -0
  422. package/src/renderer/code-block.ts +373 -0
  423. package/src/renderer/compositor.ts +261 -0
  424. package/src/renderer/context-inspector.ts +219 -0
  425. package/src/renderer/conversation-layout.ts +67 -0
  426. package/src/renderer/conversation-overlays.ts +123 -0
  427. package/src/renderer/conversation-surface.ts +260 -0
  428. package/src/renderer/diff-view.ts +132 -0
  429. package/src/renderer/diff.ts +122 -0
  430. package/src/renderer/file-picker-overlay.ts +101 -0
  431. package/src/renderer/file-tree.ts +153 -0
  432. package/src/renderer/git-status.ts +89 -0
  433. package/src/renderer/help-overlay.ts +247 -0
  434. package/src/renderer/history-search-overlay.ts +73 -0
  435. package/src/renderer/layout-engine.ts +97 -0
  436. package/src/renderer/layout.ts +32 -0
  437. package/src/renderer/live-tail-modal.ts +156 -0
  438. package/src/renderer/markdown.ts +777 -0
  439. package/src/renderer/modal-factory.ts +467 -0
  440. package/src/renderer/modal-utils.ts +24 -0
  441. package/src/renderer/model-picker-overlay.ts +396 -0
  442. package/src/renderer/overlay-box.ts +165 -0
  443. package/src/renderer/overlay-viewport.ts +104 -0
  444. package/src/renderer/panel-composite.ts +80 -0
  445. package/src/renderer/panel-picker-overlay.ts +202 -0
  446. package/src/renderer/panel-tab-bar.ts +69 -0
  447. package/src/renderer/panel-workspace-bar.ts +38 -0
  448. package/src/renderer/process-indicator.ts +96 -0
  449. package/src/renderer/process-modal.ts +295 -0
  450. package/src/renderer/profile-picker-modal.ts +129 -0
  451. package/src/renderer/progress.ts +98 -0
  452. package/src/renderer/search-overlay.ts +54 -0
  453. package/src/renderer/selection-modal-overlay.ts +214 -0
  454. package/src/renderer/semantic-diff.ts +369 -0
  455. package/src/renderer/session-picker-modal.ts +127 -0
  456. package/src/renderer/settings-modal.ts +701 -0
  457. package/src/renderer/shell-surface.ts +88 -0
  458. package/src/renderer/surface-layout.ts +101 -0
  459. package/src/renderer/syntax-highlighter.ts +542 -0
  460. package/src/renderer/system-message.ts +83 -0
  461. package/src/renderer/tab-strip.ts +108 -0
  462. package/src/renderer/text-layout.ts +31 -0
  463. package/src/renderer/thinking.ts +17 -0
  464. package/src/renderer/tool-call.ts +233 -0
  465. package/src/renderer/ui-factory.ts +524 -0
  466. package/src/renderer/ui-primitives.ts +96 -0
  467. package/src/runtime/auth/inspection.ts +125 -0
  468. package/src/runtime/bootstrap-background.ts +147 -0
  469. package/src/runtime/bootstrap-command-context.ts +265 -0
  470. package/src/runtime/bootstrap-command-parts.ts +357 -0
  471. package/src/runtime/bootstrap-core.ts +375 -0
  472. package/src/runtime/bootstrap-helpers.ts +88 -0
  473. package/src/runtime/bootstrap-hook-bridge.ts +271 -0
  474. package/src/runtime/bootstrap-runtime-events.ts +254 -0
  475. package/src/runtime/bootstrap-services.ts +197 -0
  476. package/src/runtime/bootstrap-shell.ts +262 -0
  477. package/src/runtime/bootstrap.ts +488 -0
  478. package/src/runtime/compaction/index.ts +90 -0
  479. package/src/runtime/compaction/lifecycle.ts +167 -0
  480. package/src/runtime/compaction/manager.ts +474 -0
  481. package/src/runtime/compaction/quality-score.ts +279 -0
  482. package/src/runtime/compaction/resume-repair.ts +183 -0
  483. package/src/runtime/compaction/strategies/autocompact.ts +65 -0
  484. package/src/runtime/compaction/strategies/boundary-commit.ts +106 -0
  485. package/src/runtime/compaction/strategies/collapse.ts +90 -0
  486. package/src/runtime/compaction/strategies/index.ts +23 -0
  487. package/src/runtime/compaction/strategies/microcompact.ts +74 -0
  488. package/src/runtime/compaction/strategies/reactive.ts +89 -0
  489. package/src/runtime/compaction/types.ts +221 -0
  490. package/src/runtime/context.ts +158 -0
  491. package/src/runtime/diagnostics/actions.ts +776 -0
  492. package/src/runtime/diagnostics/index.ts +99 -0
  493. package/src/runtime/diagnostics/panels/agents.ts +252 -0
  494. package/src/runtime/diagnostics/panels/events.ts +188 -0
  495. package/src/runtime/diagnostics/panels/health.ts +242 -0
  496. package/src/runtime/diagnostics/panels/index.ts +24 -0
  497. package/src/runtime/diagnostics/panels/ops.ts +156 -0
  498. package/src/runtime/diagnostics/panels/policy.ts +176 -0
  499. package/src/runtime/diagnostics/panels/tasks.ts +251 -0
  500. package/src/runtime/diagnostics/panels/tool-calls.ts +267 -0
  501. package/src/runtime/diagnostics/provider.ts +262 -0
  502. package/src/runtime/ecosystem/catalog.ts +606 -0
  503. package/src/runtime/ecosystem/recommendations.ts +117 -0
  504. package/src/runtime/emitters/agents.ts +96 -0
  505. package/src/runtime/emitters/automation.ts +112 -0
  506. package/src/runtime/emitters/communication.ts +53 -0
  507. package/src/runtime/emitters/compaction.ts +161 -0
  508. package/src/runtime/emitters/control-plane.ts +65 -0
  509. package/src/runtime/emitters/deliveries.ts +65 -0
  510. package/src/runtime/emitters/forensics.ts +17 -0
  511. package/src/runtime/emitters/index.ts +59 -0
  512. package/src/runtime/emitters/knowledge.ts +129 -0
  513. package/src/runtime/emitters/mcp.ts +95 -0
  514. package/src/runtime/emitters/ops.ts +163 -0
  515. package/src/runtime/emitters/orchestration.ts +87 -0
  516. package/src/runtime/emitters/permissions.ts +98 -0
  517. package/src/runtime/emitters/planner.ts +23 -0
  518. package/src/runtime/emitters/plugins.ts +78 -0
  519. package/src/runtime/emitters/providers.ts +30 -0
  520. package/src/runtime/emitters/routes.ts +57 -0
  521. package/src/runtime/emitters/security.ts +53 -0
  522. package/src/runtime/emitters/session.ts +93 -0
  523. package/src/runtime/emitters/surfaces.ts +57 -0
  524. package/src/runtime/emitters/tasks.ts +69 -0
  525. package/src/runtime/emitters/tools.ts +140 -0
  526. package/src/runtime/emitters/transport.ts +78 -0
  527. package/src/runtime/emitters/turn.ts +155 -0
  528. package/src/runtime/emitters/ui.ts +57 -0
  529. package/src/runtime/emitters/watchers.ts +57 -0
  530. package/src/runtime/emitters/workflows.ts +79 -0
  531. package/src/runtime/eval/index.ts +48 -0
  532. package/src/runtime/eval/runner.ts +163 -0
  533. package/src/runtime/eval/suites.ts +264 -0
  534. package/src/runtime/events/domain-map.ts +148 -0
  535. package/src/runtime/events/index.ts +194 -0
  536. package/src/runtime/events/turn.ts +60 -0
  537. package/src/runtime/events/workflows.ts +17 -0
  538. package/src/runtime/forensics/collector.ts +693 -0
  539. package/src/runtime/forensics/index.ts +23 -0
  540. package/src/runtime/foundation-clients.ts +78 -0
  541. package/src/runtime/foundation-services.ts +96 -0
  542. package/src/runtime/guidance.ts +183 -0
  543. package/src/runtime/health/effect-handlers.ts +189 -0
  544. package/src/runtime/health/index.ts +70 -0
  545. package/src/runtime/health/wiring.ts +115 -0
  546. package/src/runtime/index.ts +174 -0
  547. package/src/runtime/integration/helpers.ts +640 -0
  548. package/src/runtime/lifecycle.ts +107 -0
  549. package/src/runtime/mcp/index.ts +68 -0
  550. package/src/runtime/mcp/manager.ts +513 -0
  551. package/src/runtime/network/inbound.ts +131 -0
  552. package/src/runtime/network/index.ts +30 -0
  553. package/src/runtime/network/outbound.ts +292 -0
  554. package/src/runtime/network/shared.ts +82 -0
  555. package/src/runtime/operator-client.ts +235 -0
  556. package/src/runtime/ops/control-plane.ts +363 -0
  557. package/src/runtime/ops/index.ts +122 -0
  558. package/src/runtime/ops/playbooks/index.ts +10 -0
  559. package/src/runtime/ops/playbooks/session-unrecoverable.ts +196 -0
  560. package/src/runtime/ops/playbooks/stuck-turn.ts +197 -0
  561. package/src/runtime/ops/runtime-context.ts +100 -0
  562. package/src/runtime/ops-api.ts +27 -0
  563. package/src/runtime/orchestration/spawn-policy.ts +83 -0
  564. package/src/runtime/peer-client.ts +404 -0
  565. package/src/runtime/perf/index.ts +57 -0
  566. package/src/runtime/perf/slo-collector.ts +375 -0
  567. package/src/runtime/permissions/index.ts +190 -0
  568. package/src/runtime/permissions/policy-runtime.ts +175 -0
  569. package/src/runtime/permissions/preflight.ts +101 -0
  570. package/src/runtime/permissions/rule-suggestions.ts +36 -0
  571. package/src/runtime/plugins/hot-reload.ts +221 -0
  572. package/src/runtime/plugins/index.ts +84 -0
  573. package/src/runtime/plugins/lifecycle.ts +95 -0
  574. package/src/runtime/plugins/manager.ts +474 -0
  575. package/src/runtime/plugins/manifest.ts +167 -0
  576. package/src/runtime/plugins/quarantine.ts +202 -0
  577. package/src/runtime/plugins/trust.ts +291 -0
  578. package/src/runtime/plugins/types.ts +205 -0
  579. package/src/runtime/provider-accounts/registry.ts +326 -0
  580. package/src/runtime/remote/distributed-runtime-contract-schemas.ts +386 -0
  581. package/src/runtime/remote/index.ts +488 -0
  582. package/src/runtime/remote/runner-registry.ts +438 -0
  583. package/src/runtime/remote/supervisor.ts +70 -0
  584. package/src/runtime/runtime-hook-api.ts +5 -0
  585. package/src/runtime/runtime-knowledge-api.ts +14 -0
  586. package/src/runtime/runtime-mcp-api.ts +5 -0
  587. package/src/runtime/runtime-ops-api.ts +86 -0
  588. package/src/runtime/runtime-provider-api.ts +18 -0
  589. package/src/runtime/sandbox/backend.ts +291 -0
  590. package/src/runtime/sandbox/manager.ts +364 -0
  591. package/src/runtime/sandbox/provisioning.ts +422 -0
  592. package/src/runtime/sandbox/session-registry.ts +289 -0
  593. package/src/runtime/services.ts +541 -0
  594. package/src/runtime/session-maintenance.ts +188 -0
  595. package/src/runtime/session-persistence.ts +288 -0
  596. package/src/runtime/session-return-context.ts +195 -0
  597. package/src/runtime/settings/control-plane-store.ts +258 -0
  598. package/src/runtime/settings/control-plane.ts +599 -0
  599. package/src/runtime/shell-command-extensions.ts +54 -0
  600. package/src/runtime/shell-command-ops.ts +207 -0
  601. package/src/runtime/shell-command-platform.ts +47 -0
  602. package/src/runtime/shell-command-services.ts +143 -0
  603. package/src/runtime/shell-command-workspace.ts +31 -0
  604. package/src/runtime/store/domains/conversation.ts +181 -0
  605. package/src/runtime/store/domains/domain-read-matrix.ts +17 -0
  606. package/src/runtime/store/domains/index.ts +222 -0
  607. package/src/runtime/store/domains/panels.ts +117 -0
  608. package/src/runtime/store/domains/permissions.ts +143 -0
  609. package/src/runtime/store/domains/ui-perf.ts +103 -0
  610. package/src/runtime/store/helpers/reducers/conversation.ts +228 -0
  611. package/src/runtime/store/helpers/reducers/lifecycle.ts +440 -0
  612. package/src/runtime/store/helpers/reducers/shared.ts +60 -0
  613. package/src/runtime/store/helpers/reducers/sync.ts +555 -0
  614. package/src/runtime/store/helpers/reducers.ts +30 -0
  615. package/src/runtime/store/index.ts +304 -0
  616. package/src/runtime/store/selectors/index.ts +354 -0
  617. package/src/runtime/store/state.ts +137 -0
  618. package/src/runtime/tasks/adapters/acp-adapter.ts +211 -0
  619. package/src/runtime/tasks/adapters/agent-adapter.ts +208 -0
  620. package/src/runtime/tasks/adapters/index.ts +16 -0
  621. package/src/runtime/tasks/adapters/process-adapter.ts +214 -0
  622. package/src/runtime/tasks/adapters/scheduler-adapter.ts +193 -0
  623. package/src/runtime/tasks/index.ts +68 -0
  624. package/src/runtime/tasks/manager.ts +415 -0
  625. package/src/runtime/telemetry/api-helpers.ts +517 -0
  626. package/src/runtime/telemetry/api.ts +768 -0
  627. package/src/runtime/telemetry/index.ts +178 -0
  628. package/src/runtime/telemetry/instrumentation/domain-bridge-agent-session.ts +440 -0
  629. package/src/runtime/telemetry/instrumentation/domain-bridge-plugin-mcp.ts +200 -0
  630. package/src/runtime/telemetry/instrumentation/domain-bridge-shared.ts +18 -0
  631. package/src/runtime/telemetry/instrumentation/domain-bridge-transport-task.ts +204 -0
  632. package/src/runtime/telemetry/instrumentation/domain-bridge.ts +125 -0
  633. package/src/runtime/telemetry/instrumentation/index.ts +67 -0
  634. package/src/runtime/tools/context.ts +114 -0
  635. package/src/runtime/tools/index.ts +46 -0
  636. package/src/runtime/tools/phased-executor.ts +448 -0
  637. package/src/runtime/tools/phases/budget.ts +130 -0
  638. package/src/runtime/tools/phases/execute.ts +69 -0
  639. package/src/runtime/tools/phases/index.ts +13 -0
  640. package/src/runtime/tools/phases/map-output.ts +98 -0
  641. package/src/runtime/tools/phases/permission.ts +133 -0
  642. package/src/runtime/tools/phases/posthook.ts +57 -0
  643. package/src/runtime/tools/phases/prehook.ts +68 -0
  644. package/src/runtime/tools/phases/validate.ts +53 -0
  645. package/src/runtime/transports/direct.ts +73 -0
  646. package/src/runtime/transports/http-helpers.ts +218 -0
  647. package/src/runtime/transports/http-types.ts +364 -0
  648. package/src/runtime/transports/http.ts +629 -0
  649. package/src/runtime/transports/realtime.ts +50 -0
  650. package/src/runtime/transports/remote-events.ts +16 -0
  651. package/src/runtime/transports/shared.ts +39 -0
  652. package/src/runtime/transports/ui-runtime-events.ts +35 -0
  653. package/src/runtime/ui/index.ts +39 -0
  654. package/src/runtime/ui/model-picker/data-provider.ts +182 -0
  655. package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
  656. package/src/runtime/ui/model-picker/index.ts +59 -0
  657. package/src/runtime/ui/model-picker/types.ts +149 -0
  658. package/src/runtime/ui/provider-health/data-provider.ts +244 -0
  659. package/src/runtime/ui/provider-health/fallback-visualizer.ts +69 -0
  660. package/src/runtime/ui/provider-health/index.ts +46 -0
  661. package/src/runtime/ui/provider-health/types.ts +146 -0
  662. package/src/runtime/ui-events.ts +46 -0
  663. package/src/runtime/ui-read-model-helpers.ts +32 -0
  664. package/src/runtime/ui-read-models-core.ts +95 -0
  665. package/src/runtime/ui-read-models-observability-maintenance.ts +81 -0
  666. package/src/runtime/ui-read-models-observability-options.ts +5 -0
  667. package/src/runtime/ui-read-models-observability-remote.ts +73 -0
  668. package/src/runtime/ui-read-models-observability-security.ts +172 -0
  669. package/src/runtime/ui-read-models-observability-system.ts +217 -0
  670. package/src/runtime/ui-read-models-observability.ts +59 -0
  671. package/src/runtime/ui-read-models-operations.ts +203 -0
  672. package/src/runtime/ui-read-models.ts +61 -0
  673. package/src/runtime/ui-service-queries.ts +114 -0
  674. package/src/runtime/ui-services.ts +163 -0
  675. package/src/runtime/worktree/registry.ts +252 -0
  676. package/src/scripts/process-messages.ts +42 -0
  677. package/src/sessions/manager.ts +388 -0
  678. package/src/shell/blocking-input.ts +89 -0
  679. package/src/shell/ui-openers.ts +163 -0
  680. package/src/state/file-watcher.ts +294 -0
  681. package/src/state/index.ts +56 -0
  682. package/src/state/knowledge-injection.ts +214 -0
  683. package/src/state/memory-embedding-http.ts +642 -0
  684. package/src/state/memory-embeddings.ts +312 -0
  685. package/src/state/memory-ingest.ts +132 -0
  686. package/src/state/memory-registry.ts +111 -0
  687. package/src/state/memory-store-helpers.ts +160 -0
  688. package/src/state/memory-store.ts +728 -0
  689. package/src/state/memory-vector-store.ts +418 -0
  690. package/src/templates/manager.ts +187 -0
  691. package/src/tools/agent/index.ts +610 -0
  692. package/src/tools/agent/manager.ts +476 -0
  693. package/src/tools/analyze/git-modes.ts +380 -0
  694. package/src/tools/analyze/index.ts +128 -0
  695. package/src/tools/channel/agent-tools.ts +16 -0
  696. package/src/tools/channel/index.ts +268 -0
  697. package/src/tools/control/index.ts +90 -0
  698. package/src/tools/edit/core.ts +619 -0
  699. package/src/tools/edit/index.ts +4 -0
  700. package/src/tools/edit/phased.ts +33 -0
  701. package/src/tools/fetch/index.ts +3 -0
  702. package/src/tools/fetch/phased.ts +34 -0
  703. package/src/tools/fetch/runtime.ts +499 -0
  704. package/src/tools/index.ts +186 -0
  705. package/src/tools/mcp/index.ts +190 -0
  706. package/src/tools/remote-trigger/index.ts +130 -0
  707. package/src/tools/repl/index.ts +318 -0
  708. package/src/tools/shared/auto-heal.ts +282 -0
  709. package/src/tools/state/index.ts +688 -0
  710. package/src/tools/web-search/index.ts +38 -0
  711. package/src/tools/write/index.ts +604 -0
  712. package/src/tools/write/phased.ts +41 -0
  713. package/src/types/generated/foundation-client-types.ts +22 -0
  714. package/src/types/sql-js.d.ts +15 -0
  715. package/src/utils/splash-lines.ts +46 -0
  716. package/src/version.ts +17 -0
  717. package/src/watchers/index.ts +11 -0
  718. package/src/watchers/registry.ts +517 -0
  719. package/src/web-search/index.ts +26 -0
  720. package/src/web-search/provider-registry.ts +64 -0
  721. package/src/web-search/providers/brave.ts +100 -0
  722. package/src/web-search/providers/duckduckgo.ts +270 -0
  723. package/src/web-search/providers/exa.ts +77 -0
  724. package/src/web-search/providers/firecrawl.ts +90 -0
  725. package/src/web-search/providers/perplexity.ts +86 -0
  726. package/src/web-search/providers/searxng.ts +88 -0
  727. package/src/web-search/providers/shared.ts +249 -0
  728. package/src/web-search/providers/tavily.ts +90 -0
  729. package/src/web-search/service.ts +142 -0
  730. package/src/widget/index.ts +2 -0
  731. package/src/widget/types.ts +9 -0
  732. package/src/widget/widget.ts +8 -0
@@ -0,0 +1,775 @@
1
+ import { InfiniteBuffer } from '@pellux/goodvibes-sdk/platform/core/history';
2
+ import { createEmptyLine, type Line, type Cell } from '@pellux/goodvibes-sdk/platform/types/grid';
3
+ import type { SplashOptions } from '../utils/splash-lines.ts';
4
+ import type { ToolCall, ToolResult } from '@pellux/goodvibes-sdk/platform/types/tools';
5
+ import type { ProviderMessage, ContentPart } from '../providers/interface.ts';
6
+ import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
7
+ import type { ConfigManager } from '../config/manager.ts';
8
+ import type { SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core/session-memory';
9
+ import { SessionLineageTracker } from '@pellux/goodvibes-sdk/platform/core/session-lineage';
10
+ import { buildTranscriptEventIndex } from './transcript-events/index.ts';
11
+ import type { TranscriptEventKind } from './transcript-events/index.ts';
12
+ import { compactConversation } from './conversation-compaction.ts';
13
+ import {
14
+ addConversationSplashScreen,
15
+ appendConversationMessages,
16
+ conversationTextToLines,
17
+ logConversationText,
18
+ renderConversationAssistantMessage,
19
+ renderConversationSystemMessage,
20
+ renderConversationToolMessage,
21
+ renderConversationUserMessage,
22
+ } from './conversation-rendering.ts';
23
+ import { renderMarkdown } from '../renderer/markdown.ts';
24
+ import {
25
+ cloneBranchMap,
26
+ cloneMessages,
27
+ deriveConversationTitle,
28
+ messagesToInternal,
29
+ restoreBranchMap,
30
+ } from './conversation-utils.ts';
31
+ import { applyDiffContent, parseDiffForApply } from './conversation-diff.ts';
32
+
33
+ /**
34
+ * ConversationManager - Owns conversation messages and the rendered history buffer.
35
+ * Supports tool-use messages (assistant with tool calls, tool results).
36
+ *
37
+ * History is rebuilt lazily: a dirty flag is set on every message mutation and
38
+ * the buffer is only actually reconstructed when getDisplayBlocks() is called
39
+ * or when the width changes. This avoids O(n) rebuilds per turn in long sessions.
40
+ */
41
+ export type TokenUsage = { inputTokens: number; outputTokens: number; cacheReadTokens?: number; cacheWriteTokens?: number };
42
+
43
+ type AssistantMessage = { role: 'assistant'; content: string; toolCalls?: ToolCall[]; reasoningContent?: string; reasoningSummary?: string; usage?: TokenUsage; model?: string; provider?: string };
44
+
45
+ export type ConversationMessageSnapshot =
46
+ | { role: 'user'; content: string | ContentPart[]; cancelled?: boolean }
47
+ | AssistantMessage
48
+ | { role: 'system'; content: string }
49
+ | { role: 'tool'; callId: string; content: string; toolName?: string };
50
+
51
+ type Message = ConversationMessageSnapshot;
52
+ export type ConversationTitleSource = 'system' | 'user';
53
+
54
+ /** Metadata for a rendered block (code, tool, or diff). */
55
+ export interface BlockMeta {
56
+ /** Index of this block (increments per renderable block). */
57
+ blockIndex: number;
58
+ /** Type of block content. */
59
+ type: 'tool' | 'code' | 'diff' | 'thinking';
60
+ /** First rendered line index in the history buffer. */
61
+ startLine: number;
62
+ /** Number of rendered lines (when not collapsed). */
63
+ lineCount: number;
64
+ /** Raw text content (code source, tool output, diff text). */
65
+ rawContent: string;
66
+ /** Stable key for collapse state persistence across rebuilds (e.g. msg_N). */
67
+ collapseKey: string;
68
+ /** File path for diff blocks. */
69
+ filePath?: string;
70
+ /** Parsed diff for apply: original/updated sections. */
71
+ diffOriginal?: string;
72
+ diffUpdated?: string;
73
+ }
74
+
75
+ export class ConversationManager {
76
+ public history = new InfiniteBuffer();
77
+ /** Auto-generated or manually set conversation title. */
78
+ private _title = '';
79
+ private _titleSource: ConversationTitleSource = 'system';
80
+ private messages: Message[] = [];
81
+ private getWidth: () => number;
82
+ /** Tracks the rendered width; a change invalidates the full history. */
83
+ private lastRenderedWidth = 0;
84
+ /** When true the buffer needs to be rebuilt before the next display. */
85
+ private dirty = true;
86
+ /** Index of the first message not yet appended to the buffer. */
87
+ private appendedUpTo = 0;
88
+ /** Optional config manager for display settings. */
89
+ private configManager: ConfigManager | null = null;
90
+ /** Session memory store wired by the runtime composition root. */
91
+ private sessionMemoryStore: Pick<SessionMemoryStore, 'list'> | null = null;
92
+ /** Session lineage tracker wired by the runtime composition root. */
93
+ private sessionLineageTracker: SessionLineageTracker = new SessionLineageTracker();
94
+ /** Collapse state: stable key (msg_N) -> collapsed (true = collapsed). */
95
+ private collapseState: Map<string, boolean> = new Map();
96
+ /** Block registry: track rendered blocks for copy/apply. */
97
+ protected blockRegistry: BlockMeta[] = [];
98
+ /** Message index -> first rendered line index in the history buffer. */
99
+ private messageLineRegistry: number[] = [];
100
+ /** Registry of rendered line indices for system messages matching /error/i. */
101
+ private errorLineRegistry: number[] = [];
102
+ /** Streaming block start line in history buffer (for incremental streaming update). */
103
+ private streamingStartLine = -1;
104
+ /** Undo stack: each entry is a turn (user msg + all subsequent non-user msgs until next user). */
105
+ private undoStack: Message[][] = [];
106
+ /** Branch storage: named snapshots of messages[]. */
107
+ private branches: Map<string, Message[]> = new Map();
108
+ /** Name of the currently active branch. */
109
+ private currentBranch: string = 'main';
110
+
111
+ constructor(
112
+ getWidth: () => number = () => process.stdout.columns || 80,
113
+ configManager?: ConfigManager,
114
+ ) {
115
+ this.getWidth = getWidth;
116
+ this.configManager = configManager ?? null;
117
+ }
118
+
119
+ /** Wire in a config manager after construction (e.g. from main.ts). */
120
+ public setConfigManager(cm: ConfigManager): void {
121
+ this.configManager = cm;
122
+ }
123
+
124
+ /** Wire in the session memory store used for compaction summaries. */
125
+ public setSessionMemoryStore(store: Pick<SessionMemoryStore, 'list'>): void {
126
+ this.sessionMemoryStore = store;
127
+ }
128
+
129
+ /** Wire in the session lineage tracker used for compaction output. */
130
+ public setSessionLineageTracker(tracker: SessionLineageTracker): void {
131
+ this.sessionLineageTracker = tracker;
132
+ }
133
+
134
+ /** Read the session memory store used for compaction summaries. */
135
+ public getSessionMemoryStore(): Pick<SessionMemoryStore, 'list'> | null {
136
+ return this.sessionMemoryStore;
137
+ }
138
+
139
+ /** Read the session lineage tracker used for compaction output. */
140
+ public getSessionLineageTracker(): SessionLineageTracker {
141
+ return this.sessionLineageTracker;
142
+ }
143
+
144
+ /** Update the width provider so shell layout can own transcript width. */
145
+ public setWidthProvider(getWidth: () => number): void {
146
+ this.getWidth = getWidth;
147
+ this.markDirty();
148
+ }
149
+
150
+ /** Returns messages formatted for LLM provider consumption. */
151
+ public getMessagesForLLM(): ProviderMessage[] {
152
+ const result: ProviderMessage[] = [];
153
+ for (const m of this.messages) {
154
+ if (m.role === 'system') continue; // System messages go via systemPrompt param
155
+ if (m.role === 'user') {
156
+ result.push({ role: 'user', content: m.content as string | ContentPart[] });
157
+ } else if (m.role === 'assistant') {
158
+ result.push({ role: 'assistant', content: m.content, toolCalls: m.toolCalls });
159
+ } else if (m.role === 'tool') {
160
+ result.push({ role: 'tool', callId: m.callId, content: m.content, ...(m.toolName ? { name: m.toolName } : {}) });
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+
166
+ private findToolName(callId: string): string | undefined {
167
+ for (let i = this.messages.length - 1; i >= 0; i--) {
168
+ const message = this.messages[i];
169
+ if (message.role !== 'assistant' || !message.toolCalls?.length) continue;
170
+ const match = message.toolCalls.find((call) => call.id === callId);
171
+ if (match?.name) return match.name;
172
+ }
173
+ return undefined;
174
+ }
175
+
176
+ public addUserMessage(content: string | ContentPart[]): void {
177
+ // Auto-generate title from first user message if not already set
178
+ if (this._title === '' && typeof content === 'string' && content.trim().length > 0) {
179
+ this.setSystemTitle(deriveConversationTitle(content));
180
+ }
181
+ this.messages.push({ role: 'user', content });
182
+ // Clear undo stack when new user input is added (can't redo past new input)
183
+ this.undoStack = [];
184
+ this.markDirty();
185
+ }
186
+
187
+ /** Add an assistant message, optionally with tool calls (when the LLM invoked tools). */
188
+ public addAssistantMessage(content: string, opts?: { toolCalls?: ToolCall[]; reasoningContent?: string; reasoningSummary?: string; usage?: TokenUsage; model?: string; provider?: string }): void {
189
+ this.messages.push({ role: 'assistant', content, toolCalls: opts?.toolCalls, reasoningContent: opts?.reasoningContent, reasoningSummary: opts?.reasoningSummary, usage: opts?.usage, model: opts?.model, provider: opts?.provider });
190
+ this.markDirty();
191
+ }
192
+
193
+ /** Add a batch of tool results after tool calls have been executed. */
194
+ public addToolResults(results: ToolResult[]): void {
195
+ for (const r of results) {
196
+ const content = r.success
197
+ ? (r.output ?? 'Tool completed successfully.')
198
+ : `Error: ${r.error ?? 'Unknown error'}`;
199
+ const toolName = this.findToolName(r.callId);
200
+ this.messages.push({
201
+ role: 'tool',
202
+ callId: r.callId,
203
+ content,
204
+ ...(toolName ? { toolName } : {}),
205
+ });
206
+ }
207
+ this.markDirty();
208
+ }
209
+
210
+ /**
211
+ * undo - Remove the last complete turn (the last user message and all subsequent
212
+ * non-user messages). Pushes the removed messages onto the undo stack.
213
+ * Returns true if a turn was removed, false if there was nothing to undo.
214
+ */
215
+ public undo(): boolean {
216
+ // Find the index of the last user message
217
+ let lastUserIdx = -1;
218
+ for (let i = this.messages.length - 1; i >= 0; i--) {
219
+ if (this.messages[i].role === 'user') {
220
+ lastUserIdx = i;
221
+ break;
222
+ }
223
+ }
224
+ if (lastUserIdx === -1) return false;
225
+
226
+ // Collect the turn: user message + everything that follows (assistant, tool)
227
+ const turn = this.messages.splice(lastUserIdx);
228
+ this.undoStack.push(turn);
229
+ this.markDirty();
230
+ return true;
231
+ }
232
+
233
+ /**
234
+ * redo - Restore the most recently undone turn.
235
+ * Returns true if a turn was restored, false if the undo stack is empty.
236
+ */
237
+ public redo(): boolean {
238
+ if (this.undoStack.length === 0) return false;
239
+ const turn = this.undoStack.pop()!;
240
+ this.messages.push(...turn);
241
+ this.markDirty();
242
+ return true;
243
+ }
244
+
245
+ /**
246
+ * getLastUserMessage - Returns the content of the last user message, or null
247
+ * if there are no user messages or the content is not a plain string.
248
+ */
249
+ public getLastUserMessage(): string | null {
250
+ for (let i = this.messages.length - 1; i >= 0; i--) {
251
+ if (this.messages[i].role === 'user') {
252
+ const content = this.messages[i].content;
253
+ return typeof content === 'string' ? content : null;
254
+ }
255
+ }
256
+ return null;
257
+ }
258
+
259
+ /** Returns the current number of messages (for rollback tracking). */
260
+ public getMessageCount(): number {
261
+ return this.messages.length;
262
+ }
263
+
264
+ /** Remove all messages after the given index (for cancellation rollback). */
265
+ public removeMessagesAfter(count: number): void {
266
+ if (count < this.messages.length) {
267
+ this.messages.length = count;
268
+ this.markDirty();
269
+ }
270
+ }
271
+
272
+ /** Mark the last user message as cancelled (red + strikethrough in display). */
273
+ public markLastUserMessageCancelled(): void {
274
+ for (let i = this.messages.length - 1; i >= 0; i--) {
275
+ if (this.messages[i].role === 'user') {
276
+ (this.messages[i] as { cancelled?: boolean }).cancelled = true;
277
+ this.markDirty();
278
+ return;
279
+ }
280
+ }
281
+ }
282
+
283
+ public addSystemMessage(content: string): void {
284
+ this.messages.push({ role: 'system', content });
285
+ this.markDirty();
286
+ }
287
+
288
+ /**
289
+ * startStreamingBlock - Add a placeholder assistant message for incremental display.
290
+ * Called when streaming begins.
291
+ */
292
+ public startStreamingBlock(): void {
293
+ this.messages.push({ role: 'assistant', content: '' });
294
+ this.markDirty();
295
+ // Record the line where the streaming block starts so updates can be incremental
296
+ this.flushHistory();
297
+ this.streamingStartLine = this.history.getLineCount();
298
+ }
299
+
300
+ /**
301
+ * updateStreamingBlock - Update the in-progress streaming block with accumulated content.
302
+ * Called per-delta during streaming. Does NOT trigger a full rebuild — instead it
303
+ * directly updates the history buffer from streamingStartLine onward.
304
+ */
305
+ public updateStreamingBlock(content: string): void {
306
+ for (let i = this.messages.length - 1; i >= 0; i--) {
307
+ if (this.messages[i].role === 'assistant') {
308
+ (this.messages[i] as { role: 'assistant'; content: string }).content = content;
309
+ // Incrementally update the history buffer instead of full rebuild
310
+ if (this.streamingStartLine >= 0) {
311
+ const width = this.getWidth();
312
+ this.history.truncateToLine(this.streamingStartLine);
313
+ const rendered = renderMarkdown(content, width);
314
+ this.history.addLines(rendered);
315
+ }
316
+ return;
317
+ }
318
+ }
319
+ }
320
+
321
+ /**
322
+ * finalizeStreamingBlock - Remove the streaming placeholder.
323
+ * The orchestrator calls addAssistantMessage immediately after with the final content.
324
+ */
325
+ public finalizeStreamingBlock(): void {
326
+ for (let i = this.messages.length - 1; i >= 0; i--) {
327
+ if (this.messages[i].role === 'assistant') {
328
+ this.messages.splice(i, 1);
329
+ break;
330
+ }
331
+ }
332
+ this.streamingStartLine = -1;
333
+ this.markDirty();
334
+ }
335
+
336
+ public getDisplayBlocks(): Line[] {
337
+ this.flushHistory();
338
+ return this.history.getAllLines();
339
+ }
340
+
341
+ /**
342
+ * rebuildHistory - Full rebuild. Called when width changes or on first render.
343
+ * For incremental appends use flushHistory().
344
+ */
345
+ public rebuildHistory(): void {
346
+ this.history.clear();
347
+ this.appendedUpTo = 0;
348
+ this.blockRegistry = [];
349
+ this.messageLineRegistry = [];
350
+ this.errorLineRegistry = [];
351
+ const width = this.getWidth();
352
+ this.lastRenderedWidth = width;
353
+ this.dirty = false;
354
+
355
+ // Tool messages ARE rendered (as collapsed blocks); this filter is only
356
+ // for determining whether to show the splash screen (tool-only messages
357
+ // don't count as visible conversation content for splash purposes).
358
+ const displayMessages = this.messages.filter(
359
+ (m) => m.role !== 'tool' && m.role !== 'system',
360
+ );
361
+
362
+ if (displayMessages.length === 0 && !this.suppressSplash) {
363
+ this.addSplashScreen(width);
364
+ return;
365
+ }
366
+
367
+ this.appendMessages(this.messages, width);
368
+ this.appendedUpTo = this.messages.length;
369
+ }
370
+
371
+ /**
372
+ * flushHistory - Incremental update. Appends only newly added messages.
373
+ * Falls back to a full rebuild when the terminal width has changed.
374
+ */
375
+ public flushHistory(): void {
376
+ const currentWidth = this.getWidth();
377
+ if (!this.dirty && currentWidth === this.lastRenderedWidth) return;
378
+ this.rebuildHistory();
379
+ }
380
+
381
+ private markDirty(): void {
382
+ this.dirty = true;
383
+ }
384
+
385
+ private renderingContext() {
386
+ return {
387
+ history: this.history,
388
+ blockRegistry: this.blockRegistry,
389
+ collapseState: this.collapseState,
390
+ errorLineRegistry: this.errorLineRegistry,
391
+ configManager: this.configManager,
392
+ splashOptions: this.splashOptions,
393
+ };
394
+ }
395
+
396
+ private renderUserMessage(message: Extract<Message, { role: 'user' }>, width: number): void {
397
+ renderConversationUserMessage(this.renderingContext(), message, width);
398
+ }
399
+
400
+ private renderAssistantMessage(
401
+ message: Extract<Message, { role: 'assistant' }>,
402
+ width: number,
403
+ lineNumberMode: 'all' | 'code' | 'off',
404
+ collapseThreshold: number,
405
+ msgIdx: number,
406
+ ): void {
407
+ renderConversationAssistantMessage(this.renderingContext(), message, width, lineNumberMode, collapseThreshold, msgIdx);
408
+ }
409
+
410
+ private renderSystemMessage(message: Extract<Message, { role: 'system' }>, width: number): void {
411
+ renderConversationSystemMessage(this.renderingContext(), message, width);
412
+ }
413
+
414
+ private renderToolMessage(message: Extract<Message, { role: 'tool' }>, width: number, msgIdx: number): void {
415
+ renderConversationToolMessage(this.renderingContext(), message, width, msgIdx);
416
+ }
417
+
418
+ /** Render a slice of messages into the history buffer. */
419
+ private appendMessages(messages: Message[], width: number): void {
420
+ appendConversationMessages(this.renderingContext(), messages, width, this.messageLineRegistry);
421
+ }
422
+
423
+ /** Find the nearest block to a given line index, optionally filtered by type. */
424
+ public findNearestBlock(lineIndex: number, typeFilter?: string): BlockMeta | null {
425
+ let nearest: BlockMeta | null = null;
426
+ let nearestDist = Infinity;
427
+ for (const block of this.blockRegistry) {
428
+ if (typeFilter !== undefined && block.type !== typeFilter) continue;
429
+ if (lineIndex >= block.startLine && lineIndex < block.startLine + block.lineCount) {
430
+ return block;
431
+ }
432
+ const dist = Math.abs(block.startLine - lineIndex);
433
+ if (dist < nearestDist) {
434
+ nearestDist = dist;
435
+ nearest = block;
436
+ }
437
+ }
438
+ return nearest;
439
+ }
440
+
441
+ /**
442
+ * isCollapsed - Returns whether the block at blockIndex is collapsed.
443
+ */
444
+ public isCollapsed(blockIndex: number): boolean {
445
+ const block = this.blockRegistry[blockIndex];
446
+ if (!block) return false;
447
+ return this.collapseState.get(block.collapseKey) ?? false;
448
+ }
449
+
450
+ /**
451
+ * getBlockContentAtLine - Find the nearest block to the given line index.
452
+ * Returns the raw content of the block, or null if not found.
453
+ */
454
+ public getBlockContentAtLine(lineIndex: number): string | null {
455
+ return this.findNearestBlock(lineIndex)?.rawContent ?? null;
456
+ }
457
+
458
+ /**
459
+ * getDiffAtLine - Find the diff block nearest the given line index.
460
+ * Returns file path and original/updated content for applying.
461
+ */
462
+ public getDiffAtLine(lineIndex: number): { filePath: string; original: string; updated: string } | null {
463
+ const nearest = this.findNearestBlock(lineIndex, 'diff');
464
+ if (!nearest || !nearest.filePath) return null;
465
+ return {
466
+ filePath: nearest.filePath,
467
+ original: nearest.diffOriginal ?? '',
468
+ updated: nearest.diffUpdated ?? '',
469
+ };
470
+ }
471
+
472
+ /**
473
+ * toggleCollapseAtLine - Toggle the collapse state of the nearest block to the given line.
474
+ * Triggers a rebuild. Returns the blockIndex toggled, or -1 if none found.
475
+ */
476
+ public toggleCollapseAtLine(lineIndex: number): number {
477
+ const nearest = this.findNearestBlock(lineIndex);
478
+ if (!nearest) return -1;
479
+ const current = this.collapseState.get(nearest.collapseKey) ?? false;
480
+ this.collapseState.set(nearest.collapseKey, !current);
481
+ this.markDirty();
482
+ return nearest.blockIndex;
483
+ }
484
+
485
+ /** Returns a read-only view of the block registry for external consumers. */
486
+ public getBlockRegistry(): readonly BlockMeta[] {
487
+ return this.blockRegistry;
488
+ }
489
+
490
+ /**
491
+ * getErrorLines - Returns line indices in the rendered history buffer for
492
+ * system messages that contain 'error' (case-insensitive).
493
+ * Triggers a history flush if dirty.
494
+ */
495
+ public getErrorLines(): number[] {
496
+ this.flushHistory();
497
+ return [...this.errorLineRegistry];
498
+ }
499
+
500
+ /**
501
+ * nextErrorLine - Find the next error line after currentLine (wraps around).
502
+ * Returns -1 if there are no error lines.
503
+ */
504
+ public nextErrorLine(currentLine: number): number {
505
+ const errors = this.getErrorLines();
506
+ if (errors.length === 0) return -1;
507
+ const after = errors.find(l => l > currentLine);
508
+ return after ?? errors[0];
509
+ }
510
+
511
+ /**
512
+ * prevErrorLine - Find the previous error line before currentLine (wraps around).
513
+ * Returns -1 if there are no error lines.
514
+ */
515
+ public prevErrorLine(currentLine: number): number {
516
+ const errors = this.getErrorLines();
517
+ if (errors.length === 0) return -1;
518
+ const before = [...errors].reverse().find(l => l < currentLine);
519
+ return before ?? errors[errors.length - 1];
520
+ }
521
+
522
+ public nextTranscriptEventLine(currentLine: number, kind: TranscriptEventKind | 'all' = 'all'): number {
523
+ this.flushHistory();
524
+ const index = this.getTranscriptEventIndex();
525
+ const events = kind === 'all' ? index.events : index.events.filter((event) => event.kind === kind);
526
+ if (events.length === 0) return -1;
527
+ const lines = events
528
+ .map((event) => this.messageLineRegistry[event.messageIndex] ?? -1)
529
+ .filter((line) => line >= 0)
530
+ .sort((a, b) => a - b);
531
+ if (lines.length === 0) return -1;
532
+ const after = lines.find((line) => line > currentLine);
533
+ return after ?? lines[0]!;
534
+ }
535
+
536
+ public prevTranscriptEventLine(currentLine: number, kind: TranscriptEventKind | 'all' = 'all'): number {
537
+ this.flushHistory();
538
+ const index = this.getTranscriptEventIndex();
539
+ const events = kind === 'all' ? index.events : index.events.filter((event) => event.kind === kind);
540
+ if (events.length === 0) return -1;
541
+ const lines = events
542
+ .map((event) => this.messageLineRegistry[event.messageIndex] ?? -1)
543
+ .filter((line) => line >= 0)
544
+ .sort((a, b) => a - b);
545
+ if (lines.length === 0) return -1;
546
+ const before = [...lines].reverse().find((line) => line < currentLine);
547
+ return before ?? lines[lines.length - 1]!;
548
+ }
549
+
550
+ public suppressSplash: boolean = false;
551
+ public splashOptions: SplashOptions = {};
552
+
553
+ public get title(): string {
554
+ return this._title;
555
+ }
556
+
557
+ public set title(value: string) {
558
+ this._title = String(value ?? '');
559
+ this._titleSource = this._title.trim().length > 0 ? 'user' : 'system';
560
+ }
561
+
562
+ public getTitleSource(): ConversationTitleSource {
563
+ return this._titleSource;
564
+ }
565
+
566
+ public setSystemTitle(value: string): void {
567
+ if (this._titleSource === 'user') return;
568
+ this._title = String(value ?? '');
569
+ this._titleSource = 'system';
570
+ }
571
+
572
+ public setSplashSuppressed(suppressed: boolean): void {
573
+ if (this.suppressSplash === suppressed) return;
574
+ this.suppressSplash = suppressed;
575
+ this.markDirty();
576
+ }
577
+
578
+ private addSplashScreen(width: number): void {
579
+ addConversationSplashScreen(this.renderingContext(), width);
580
+ }
581
+
582
+ public textToLines(text: string, width: number, style: Partial<Cell> = {}): Line[] {
583
+ return conversationTextToLines(text, width, style);
584
+ }
585
+
586
+ public log(text: string, style: Partial<Cell> = {}, indent = ' '): void {
587
+ logConversationText(this.renderingContext(), this.getWidth(), text, style, indent);
588
+ }
589
+
590
+ /**
591
+ * clearDisplay - Clear the visual history buffer without touching the LLM context messages.
592
+ * The next render will show a blank conversation area.
593
+ */
594
+ public clearDisplay(): void {
595
+ this.history.clear();
596
+ this.appendedUpTo = 0;
597
+ this.dirty = true;
598
+ // Re-render from existing messages to rebuild buffer
599
+ const width = this.getWidth();
600
+ this.lastRenderedWidth = width;
601
+ this.dirty = false;
602
+ this.appendMessages(this.messages, width);
603
+ this.appendedUpTo = this.messages.length;
604
+ }
605
+
606
+ /**
607
+ * resetAll - Clear both the display buffer and all conversation messages.
608
+ * This is a full reset; the LLM context is wiped.
609
+ */
610
+ public resetAll(): void {
611
+ this.messages = [];
612
+ this._title = '';
613
+ this._titleSource = 'system';
614
+ this.undoStack = [];
615
+ this.branches.clear();
616
+ this.currentBranch = 'main';
617
+ this.history.clear();
618
+ this.appendedUpTo = 0;
619
+ this.lastRenderedWidth = 0;
620
+ this.dirty = true;
621
+ this.collapseState.clear();
622
+ this.blockRegistry = [];
623
+ this.streamingStartLine = -1;
624
+ }
625
+
626
+ public getMessageSnapshot(): ConversationMessageSnapshot[] {
627
+ return cloneMessages(this.messages);
628
+ }
629
+
630
+ public getTranscriptEventIndex() {
631
+ return buildTranscriptEventIndex(this.getMessageSnapshot());
632
+ }
633
+
634
+ /**
635
+ * replaceMessagesForLLM - Replace the conversation's LLM-visible messages with a new set.
636
+ * Used by small-window compaction to swap in truncated messages without an LLM call.
637
+ * System messages are always preserved at the front.
638
+ *
639
+ * @param newMessages - Replacement ProviderMessage array (user/assistant/tool roles only)
640
+ */
641
+ public replaceMessagesForLLM(newMessages: ProviderMessage[]): void {
642
+ const originalSystemMessages = this.messages.filter(m => m.role === 'system');
643
+ const convertedMessages = messagesToInternal(newMessages);
644
+ this.messages = [...originalSystemMessages, ...convertedMessages];
645
+ this.history.clear();
646
+ this.appendedUpTo = 0;
647
+ this.lastRenderedWidth = 0;
648
+ this.dirty = true;
649
+ }
650
+
651
+ /**
652
+ * compact - Reduce conversation state to a structured handoff payload.
653
+ *
654
+ * @param registry - Provider registry
655
+ * @param modelId - Model to use for summarization
656
+ * @param trigger - 'manual' (from /compact command) or 'auto' (from threshold check)
657
+ * @param provider - Provider name for model disambiguation
658
+ * @param context - Structured compaction context
659
+ */
660
+ public async compact(
661
+ registry: import('../providers/registry.ts').ProviderRegistry,
662
+ modelId: string,
663
+ trigger: 'auto' | 'manual' = 'manual',
664
+ provider?: string,
665
+ context?: import('./context-compaction.ts').CompactionContext,
666
+ ): Promise<void> {
667
+ return compactConversation(this, registry, modelId, trigger, provider, context);
668
+ }
669
+
670
+ /**
671
+ * forkBranch - Save a deep-copy of the current messages under a named branch.
672
+ * If no name is provided a timestamp-based name is used.
673
+ * Returns the name used.
674
+ */
675
+ public forkBranch(name?: string, force = false): string {
676
+ const branchName = name?.trim() || `branch-${Date.now()}`;
677
+ if (!force && this.branches.has(branchName)) {
678
+ logger.warn(`forkBranch: branch '${branchName}' already exists; use force=true to overwrite`);
679
+ }
680
+ this.branches.set(branchName, cloneMessages(this.messages));
681
+ return branchName;
682
+ }
683
+
684
+ /**
685
+ * listBranches - Return the names and message counts of all saved branches.
686
+ */
687
+ public listBranches(): Array<{ name: string; messageCount: number; isCurrent: boolean }> {
688
+ const result: Array<{ name: string; messageCount: number; isCurrent: boolean }> = [];
689
+ // Always include current branch even if it hasn't been stored in the map yet
690
+ const currentInMap = this.branches.has(this.currentBranch);
691
+ if (!currentInMap) {
692
+ result.push({ name: this.currentBranch, messageCount: this.messages.length, isCurrent: true });
693
+ }
694
+ for (const [name, msgs] of this.branches) {
695
+ result.push({ name, messageCount: msgs.length, isCurrent: name === this.currentBranch });
696
+ }
697
+ return result;
698
+ }
699
+
700
+ /**
701
+ * switchBranch - Replace the active messages with the stored branch snapshot.
702
+ * Returns true on success, false if the branch does not exist.
703
+ */
704
+ public switchBranch(name: string): boolean {
705
+ const stored = this.branches.get(name);
706
+ if (!stored) return false;
707
+ // Save current branch state before switching to prevent data loss
708
+ this.branches.set(this.currentBranch, cloneMessages(this.messages));
709
+ this.messages = cloneMessages(stored);
710
+ this.currentBranch = name;
711
+ this.undoStack = [];
712
+ this.markDirty();
713
+ return true;
714
+ }
715
+
716
+ /**
717
+ * mergeBranch - Append all messages from the named branch that come after
718
+ * the fork point (messages not already present in the current conversation).
719
+ * Simple strategy: append all branch messages after current messages.
720
+ * Returns true on success, false if the branch does not exist.
721
+ */
722
+ public mergeBranch(name: string): boolean {
723
+ const stored = this.branches.get(name);
724
+ if (!stored) return false;
725
+ // Use length-based fork point detection: the branch was cloned from a known
726
+ // snapshot so we use the shorter of the two lengths as the common prefix,
727
+ // then append any messages the branch has beyond that point.
728
+ const commonLen = Math.min(this.messages.length, stored.length);
729
+ const toAppend = stored.slice(commonLen);
730
+ if (toAppend.length === 0) return true;
731
+ this.messages.push(...cloneMessages(toAppend));
732
+ this.undoStack = [];
733
+ this.markDirty();
734
+ return true;
735
+ }
736
+
737
+ /** Returns the name of the currently active branch. */
738
+ public getCurrentBranch(): string {
739
+ return this.currentBranch;
740
+ }
741
+
742
+ /**
743
+ * toJSON - Serialize conversation for persistence.
744
+ */
745
+ public toJSON(): object {
746
+ // Serialize branches map as a plain object for persistence
747
+ const branchesObj = cloneBranchMap(this.branches);
748
+ return {
749
+ messages: cloneMessages(this.messages),
750
+ timestamp: Date.now(),
751
+ title: this._title,
752
+ titleSource: this._titleSource,
753
+ branches: branchesObj,
754
+ currentBranch: this.currentBranch,
755
+ };
756
+ }
757
+
758
+ /**
759
+ * fromJSON - Restore conversation from persisted data.
760
+ */
761
+ public fromJSON(data: { messages: Message[]; branches?: Record<string, Message[]>; currentBranch?: string; title?: string; titleSource?: ConversationTitleSource }): void {
762
+ this.messages = data.messages ?? [];
763
+ this._title = typeof data.title === 'string' ? data.title : '';
764
+ this._titleSource = data.titleSource === 'user' || data.titleSource === 'system'
765
+ ? data.titleSource
766
+ : (this._title ? 'user' : 'system');
767
+ this.branches = restoreBranchMap(data.branches);
768
+ this.currentBranch = data.currentBranch ?? 'main';
769
+ this.history.clear();
770
+ this.appendedUpTo = 0;
771
+ this.lastRenderedWidth = 0;
772
+ this.dirty = true;
773
+ }
774
+ }
775
+ export { parseDiffForApply, applyDiffContent } from './conversation-diff.ts';