@opendash-ai/cli 0.1.0-beta.1 → 0.1.0-beta.3

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 (1213) hide show
  1. package/{src/skill/compose/LICENSE-superpowers → LICENSE} +2 -6
  2. package/README.md +53 -8
  3. package/bin/opendash +3 -4
  4. package/package.json +9 -191
  5. package/postinstall.mjs +124 -0
  6. package/Dockerfile +0 -18
  7. package/analysis.py +0 -171
  8. package/bunfig.toml +0 -7
  9. package/drizzle.config.ts +0 -10
  10. package/git +0 -0
  11. package/migration/20260127222353_familiar_lady_ursula/migration.sql +0 -90
  12. package/migration/20260127222353_familiar_lady_ursula/snapshot.json +0 -796
  13. package/migration/20260211171708_add_project_commands/migration.sql +0 -1
  14. package/migration/20260211171708_add_project_commands/snapshot.json +0 -806
  15. package/migration/20260213144116_wakeful_the_professor/migration.sql +0 -11
  16. package/migration/20260213144116_wakeful_the_professor/snapshot.json +0 -897
  17. package/migration/20260225215848_workspace/migration.sql +0 -7
  18. package/migration/20260225215848_workspace/snapshot.json +0 -959
  19. package/migration/20260227213759_add_session_workspace_id/migration.sql +0 -2
  20. package/migration/20260227213759_add_session_workspace_id/snapshot.json +0 -983
  21. package/migration/20260228203230_blue_harpoon/migration.sql +0 -17
  22. package/migration/20260228203230_blue_harpoon/snapshot.json +0 -1102
  23. package/migration/20260303231226_add_workspace_fields/migration.sql +0 -5
  24. package/migration/20260303231226_add_workspace_fields/snapshot.json +0 -1013
  25. package/migration/20260309230000_move_org_to_state/migration.sql +0 -3
  26. package/migration/20260309230000_move_org_to_state/snapshot.json +0 -1156
  27. package/migration/20260312043431_session_message_cursor/migration.sql +0 -4
  28. package/migration/20260312043431_session_message_cursor/snapshot.json +0 -1168
  29. package/migration/20260323234822_events/migration.sql +0 -13
  30. package/migration/20260323234822_events/snapshot.json +0 -1271
  31. package/migration/20260410174513_workspace-name/migration.sql +0 -16
  32. package/migration/20260410174513_workspace-name/snapshot.json +0 -1271
  33. package/migration/20260413175956_chief_energizer/migration.sql +0 -13
  34. package/migration/20260413175956_chief_energizer/snapshot.json +0 -1399
  35. package/migration/20260422160000_context_inheritance/migration.sql +0 -3
  36. package/migration/20260422170000_task_registry/migration.sql +0 -18
  37. package/migration/20260423145421_remove_session_entry/migration.sql +0 -4
  38. package/migration/20260515000000_actor_rename/migration.sql +0 -7
  39. package/migration/20260515010000_memory_fts/migration.sql +0 -33
  40. package/migration/20260515020000_user_task/migration.sql +0 -29
  41. package/migration/20260519000000_last_checkpoint_message_id/migration.sql +0 -1
  42. package/migration/20260521000000_message_agent_id/migration.sql +0 -2
  43. package/migration/20260521000100_actor_registry_v6/migration.sql +0 -25
  44. package/migration/20260521010000_memory_fts_v6/migration.sql +0 -33
  45. package/migration/20260521020000_memory_fts_triggers/migration.sql +0 -17
  46. package/migration/20260526000000_agent_id_main/migration.sql +0 -14
  47. package/migration/20260527000000_actor_lifecycle/migration.sql +0 -8
  48. package/migration/20260527000100_inbox/migration.sql +0 -12
  49. package/migration/20260529000000_task_todo_redesign/migration.sql +0 -16
  50. package/migration/20260603000000_task_in_progress_owner/migration.sql +0 -1
  51. package/migration/20260603000000_workflow_run/migration.sql +0 -17
  52. package/migration/20260604000000_workflow_script_sha/migration.sql +0 -1
  53. package/migration/20260608000000_claude_import/migration.sql +0 -7
  54. package/migration/20260608010000_claude_import_message_ids/migration.sql +0 -1
  55. package/migration/20260609000000_history_fts/migration.sql +0 -29
  56. package/migration/20260609230000_workflow_agent_timeout/migration.sql +0 -1
  57. package/migration/20260612000000_external_import/migration.sql +0 -16
  58. package/parsers-config.ts +0 -290
  59. package/script/build.ts +0 -337
  60. package/script/build_noinstall.ts +0 -337
  61. package/script/check-migrations.ts +0 -16
  62. package/script/dev.ts +0 -38
  63. package/script/fds-upload.ts +0 -170
  64. package/script/fix-node-pty.ts +0 -28
  65. package/script/generate.ts +0 -23
  66. package/script/postinstall.mjs +0 -102
  67. package/script/publish.ts +0 -75
  68. package/script/run-workspace-server +0 -106
  69. package/script/schema.ts +0 -63
  70. package/script/time.ts +0 -6
  71. package/script/trace-imports.ts +0 -153
  72. package/script/upgrade-opentui.ts +0 -64
  73. package/src/account/account.sql.ts +0 -39
  74. package/src/account/account.ts +0 -456
  75. package/src/account/repo.ts +0 -166
  76. package/src/account/schema.ts +0 -99
  77. package/src/account/url.ts +0 -8
  78. package/src/acp/README.md +0 -174
  79. package/src/acp/agent.ts +0 -1787
  80. package/src/acp/session.ts +0 -116
  81. package/src/acp/types.ts +0 -24
  82. package/src/actor/actor.sql.ts +0 -38
  83. package/src/actor/events.ts +0 -67
  84. package/src/actor/index.ts +0 -2
  85. package/src/actor/registry.ts +0 -412
  86. package/src/actor/return-header.ts +0 -24
  87. package/src/actor/schema.ts +0 -47
  88. package/src/actor/spawn-ref.ts +0 -16
  89. package/src/actor/spawn.ts +0 -756
  90. package/src/actor/turn.ts +0 -49
  91. package/src/actor/waiter.ts +0 -166
  92. package/src/agent/agent.ts +0 -574
  93. package/src/agent/config.ts +0 -5
  94. package/src/agent/generate.txt +0 -75
  95. package/src/agent/prompt/checkpoint-writer.txt +0 -167
  96. package/src/agent/prompt/compaction.txt +0 -9
  97. package/src/agent/prompt/distill.txt +0 -199
  98. package/src/agent/prompt/dream.txt +0 -155
  99. package/src/agent/prompt/explore.txt +0 -18
  100. package/src/agent/prompt/summary.txt +0 -11
  101. package/src/agent/prompt/title.txt +0 -44
  102. package/src/audio.d.ts +0 -9
  103. package/src/auth/index.ts +0 -97
  104. package/src/bus/bus-event.ts +0 -33
  105. package/src/bus/global.ts +0 -12
  106. package/src/bus/index.ts +0 -193
  107. package/src/cli/bootstrap.ts +0 -33
  108. package/src/cli/cmd/account.ts +0 -258
  109. package/src/cli/cmd/acp.ts +0 -70
  110. package/src/cli/cmd/agent.ts +0 -248
  111. package/src/cli/cmd/cmd.ts +0 -7
  112. package/src/cli/cmd/db.ts +0 -120
  113. package/src/cli/cmd/debug/agent.ts +0 -192
  114. package/src/cli/cmd/debug/config.ts +0 -17
  115. package/src/cli/cmd/debug/file.ts +0 -100
  116. package/src/cli/cmd/debug/index.ts +0 -48
  117. package/src/cli/cmd/debug/lsp.ts +0 -61
  118. package/src/cli/cmd/debug/ripgrep.ts +0 -105
  119. package/src/cli/cmd/debug/scrap.ts +0 -16
  120. package/src/cli/cmd/debug/skill.ts +0 -23
  121. package/src/cli/cmd/debug/snapshot.ts +0 -53
  122. package/src/cli/cmd/export.ts +0 -306
  123. package/src/cli/cmd/generate.ts +0 -50
  124. package/src/cli/cmd/github.ts +0 -1647
  125. package/src/cli/cmd/import.ts +0 -208
  126. package/src/cli/cmd/mcp.ts +0 -812
  127. package/src/cli/cmd/models.ts +0 -88
  128. package/src/cli/cmd/plug.ts +0 -233
  129. package/src/cli/cmd/pr.ts +0 -138
  130. package/src/cli/cmd/providers.ts +0 -713
  131. package/src/cli/cmd/run-completion.ts +0 -77
  132. package/src/cli/cmd/run.ts +0 -694
  133. package/src/cli/cmd/serve.ts +0 -30
  134. package/src/cli/cmd/session.ts +0 -181
  135. package/src/cli/cmd/stats.ts +0 -413
  136. package/src/cli/cmd/tui/app.tsx +0 -1140
  137. package/src/cli/cmd/tui/asset/TEN_VAD_LICENSE +0 -12
  138. package/src/cli/cmd/tui/asset/charge.wav +0 -0
  139. package/src/cli/cmd/tui/asset/pulse-a.wav +0 -0
  140. package/src/cli/cmd/tui/asset/pulse-b.wav +0 -0
  141. package/src/cli/cmd/tui/asset/pulse-c.wav +0 -0
  142. package/src/cli/cmd/tui/asset/ten_vad.wasm +0 -0
  143. package/src/cli/cmd/tui/asset/ten_vad_loader.js +0 -30
  144. package/src/cli/cmd/tui/attach.ts +0 -84
  145. package/src/cli/cmd/tui/component/background-image.tsx +0 -150
  146. package/src/cli/cmd/tui/component/bg-pulse.tsx +0 -130
  147. package/src/cli/cmd/tui/component/border.tsx +0 -21
  148. package/src/cli/cmd/tui/component/dialog-agent.tsx +0 -31
  149. package/src/cli/cmd/tui/component/dialog-agreement.tsx +0 -111
  150. package/src/cli/cmd/tui/component/dialog-command.tsx +0 -219
  151. package/src/cli/cmd/tui/component/dialog-console-org.tsx +0 -103
  152. package/src/cli/cmd/tui/component/dialog-go-upsell.tsx +0 -157
  153. package/src/cli/cmd/tui/component/dialog-image-list.tsx +0 -111
  154. package/src/cli/cmd/tui/component/dialog-logo-design.tsx +0 -37
  155. package/src/cli/cmd/tui/component/dialog-mcp.tsx +0 -86
  156. package/src/cli/cmd/tui/component/dialog-mimo-login.tsx +0 -165
  157. package/src/cli/cmd/tui/component/dialog-model.tsx +0 -335
  158. package/src/cli/cmd/tui/component/dialog-provider.tsx +0 -449
  159. package/src/cli/cmd/tui/component/dialog-session-delete-failed.tsx +0 -101
  160. package/src/cli/cmd/tui/component/dialog-session-list.tsx +0 -269
  161. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +0 -31
  162. package/src/cli/cmd/tui/component/dialog-skill.tsx +0 -42
  163. package/src/cli/cmd/tui/component/dialog-stash.tsx +0 -87
  164. package/src/cli/cmd/tui/component/dialog-status.tsx +0 -170
  165. package/src/cli/cmd/tui/component/dialog-tag.tsx +0 -44
  166. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +0 -50
  167. package/src/cli/cmd/tui/component/dialog-token-plan.tsx +0 -77
  168. package/src/cli/cmd/tui/component/dialog-variant.tsx +0 -39
  169. package/src/cli/cmd/tui/component/dialog-workflows.tsx +0 -51
  170. package/src/cli/cmd/tui/component/dialog-workspace-create.tsx +0 -289
  171. package/src/cli/cmd/tui/component/dialog-workspace-unavailable.tsx +0 -81
  172. package/src/cli/cmd/tui/component/dialog-worktree.tsx +0 -90
  173. package/src/cli/cmd/tui/component/error-component.tsx +0 -92
  174. package/src/cli/cmd/tui/component/logo.tsx +0 -961
  175. package/src/cli/cmd/tui/component/plugin-route-missing.tsx +0 -14
  176. package/src/cli/cmd/tui/component/prompt/autocomplete-detect.ts +0 -34
  177. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +0 -668
  178. package/src/cli/cmd/tui/component/prompt/cwd.ts +0 -0
  179. package/src/cli/cmd/tui/component/prompt/frecency.tsx +0 -90
  180. package/src/cli/cmd/tui/component/prompt/history.tsx +0 -108
  181. package/src/cli/cmd/tui/component/prompt/index.tsx +0 -1917
  182. package/src/cli/cmd/tui/component/prompt/offset.ts +0 -45
  183. package/src/cli/cmd/tui/component/prompt/part.ts +0 -36
  184. package/src/cli/cmd/tui/component/prompt/shimmer.ts +0 -62
  185. package/src/cli/cmd/tui/component/prompt/stash.tsx +0 -101
  186. package/src/cli/cmd/tui/component/spinner.tsx +0 -24
  187. package/src/cli/cmd/tui/component/starry-background.tsx +0 -305
  188. package/src/cli/cmd/tui/component/startup-loading.tsx +0 -67
  189. package/src/cli/cmd/tui/component/task-item.tsx +0 -63
  190. package/src/cli/cmd/tui/component/textarea-keybindings.ts +0 -73
  191. package/src/cli/cmd/tui/component/todo-item.tsx +0 -32
  192. package/src/cli/cmd/tui/component/workflow-tree.tsx +0 -177
  193. package/src/cli/cmd/tui/config/cwd.ts +0 -5
  194. package/src/cli/cmd/tui/config/tui-migrate.ts +0 -151
  195. package/src/cli/cmd/tui/config/tui-schema.ts +0 -38
  196. package/src/cli/cmd/tui/config/tui.ts +0 -219
  197. package/src/cli/cmd/tui/context/args.tsx +0 -16
  198. package/src/cli/cmd/tui/context/directory.ts +0 -15
  199. package/src/cli/cmd/tui/context/event.ts +0 -45
  200. package/src/cli/cmd/tui/context/exit.tsx +0 -65
  201. package/src/cli/cmd/tui/context/helper.tsx +0 -25
  202. package/src/cli/cmd/tui/context/keybind.tsx +0 -105
  203. package/src/cli/cmd/tui/context/kv.tsx +0 -86
  204. package/src/cli/cmd/tui/context/language.tsx +0 -91
  205. package/src/cli/cmd/tui/context/local.tsx +0 -469
  206. package/src/cli/cmd/tui/context/plugin-keybinds.ts +0 -41
  207. package/src/cli/cmd/tui/context/project.tsx +0 -109
  208. package/src/cli/cmd/tui/context/prompt.tsx +0 -18
  209. package/src/cli/cmd/tui/context/route.tsx +0 -68
  210. package/src/cli/cmd/tui/context/sdk.tsx +0 -150
  211. package/src/cli/cmd/tui/context/sync.tsx +0 -884
  212. package/src/cli/cmd/tui/context/theme/aura.json +0 -69
  213. package/src/cli/cmd/tui/context/theme/ayu.json +0 -80
  214. package/src/cli/cmd/tui/context/theme/carbonfox.json +0 -248
  215. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +0 -230
  216. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +0 -230
  217. package/src/cli/cmd/tui/context/theme/catppuccin.json +0 -112
  218. package/src/cli/cmd/tui/context/theme/cobalt2.json +0 -225
  219. package/src/cli/cmd/tui/context/theme/cursor.json +0 -249
  220. package/src/cli/cmd/tui/context/theme/dracula.json +0 -219
  221. package/src/cli/cmd/tui/context/theme/everforest.json +0 -241
  222. package/src/cli/cmd/tui/context/theme/flexoki.json +0 -237
  223. package/src/cli/cmd/tui/context/theme/github.json +0 -233
  224. package/src/cli/cmd/tui/context/theme/gruvbox.json +0 -242
  225. package/src/cli/cmd/tui/context/theme/kanagawa.json +0 -77
  226. package/src/cli/cmd/tui/context/theme/lucent-orng.json +0 -234
  227. package/src/cli/cmd/tui/context/theme/material.json +0 -235
  228. package/src/cli/cmd/tui/context/theme/matrix.json +0 -77
  229. package/src/cli/cmd/tui/context/theme/mercury.json +0 -252
  230. package/src/cli/cmd/tui/context/theme/monokai.json +0 -221
  231. package/src/cli/cmd/tui/context/theme/nightowl.json +0 -221
  232. package/src/cli/cmd/tui/context/theme/nord.json +0 -223
  233. package/src/cli/cmd/tui/context/theme/one-dark.json +0 -84
  234. package/src/cli/cmd/tui/context/theme/opendash.json +0 -243
  235. package/src/cli/cmd/tui/context/theme/orng.json +0 -249
  236. package/src/cli/cmd/tui/context/theme/osaka-jade.json +0 -93
  237. package/src/cli/cmd/tui/context/theme/palenight.json +0 -222
  238. package/src/cli/cmd/tui/context/theme/rosepine.json +0 -234
  239. package/src/cli/cmd/tui/context/theme/solarized.json +0 -223
  240. package/src/cli/cmd/tui/context/theme/synthwave84.json +0 -226
  241. package/src/cli/cmd/tui/context/theme/tokyonight.json +0 -243
  242. package/src/cli/cmd/tui/context/theme/vercel.json +0 -245
  243. package/src/cli/cmd/tui/context/theme/vesper.json +0 -218
  244. package/src/cli/cmd/tui/context/theme/zenburn.json +0 -223
  245. package/src/cli/cmd/tui/context/theme.tsx +0 -1299
  246. package/src/cli/cmd/tui/context/thinking.ts +0 -48
  247. package/src/cli/cmd/tui/context/tui-config.tsx +0 -9
  248. package/src/cli/cmd/tui/event.ts +0 -56
  249. package/src/cli/cmd/tui/feature-plugins/home/footer.tsx +0 -93
  250. package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +0 -194
  251. package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +0 -54
  252. package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +0 -114
  253. package/src/cli/cmd/tui/feature-plugins/sidebar/cwd.tsx +0 -45
  254. package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +0 -62
  255. package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +0 -93
  256. package/src/cli/cmd/tui/feature-plugins/sidebar/goal.tsx +0 -84
  257. package/src/cli/cmd/tui/feature-plugins/sidebar/instructions.tsx +0 -54
  258. package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +0 -66
  259. package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +0 -98
  260. package/src/cli/cmd/tui/feature-plugins/sidebar/task.tsx +0 -95
  261. package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +0 -51
  262. package/src/cli/cmd/tui/feature-plugins/sidebar/tps.ts +0 -31
  263. package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +0 -274
  264. package/src/cli/cmd/tui/i18n/en.ts +0 -470
  265. package/src/cli/cmd/tui/i18n/es.ts +0 -508
  266. package/src/cli/cmd/tui/i18n/fr.ts +0 -515
  267. package/src/cli/cmd/tui/i18n/ja.ts +0 -463
  268. package/src/cli/cmd/tui/i18n/locales.ts +0 -82
  269. package/src/cli/cmd/tui/i18n/ru.ts +0 -527
  270. package/src/cli/cmd/tui/i18n/slash-command.ts +0 -11
  271. package/src/cli/cmd/tui/i18n/zh.ts +0 -459
  272. package/src/cli/cmd/tui/i18n/zht.ts +0 -430
  273. package/src/cli/cmd/tui/layer.ts +0 -6
  274. package/src/cli/cmd/tui/plugin/api.tsx +0 -402
  275. package/src/cli/cmd/tui/plugin/index.ts +0 -3
  276. package/src/cli/cmd/tui/plugin/internal.ts +0 -35
  277. package/src/cli/cmd/tui/plugin/runtime.ts +0 -1057
  278. package/src/cli/cmd/tui/plugin/slots.tsx +0 -60
  279. package/src/cli/cmd/tui/routes/home.tsx +0 -172
  280. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +0 -76
  281. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +0 -116
  282. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +0 -47
  283. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +0 -47
  284. package/src/cli/cmd/tui/routes/session/footer.tsx +0 -91
  285. package/src/cli/cmd/tui/routes/session/index.tsx +0 -3087
  286. package/src/cli/cmd/tui/routes/session/permission.tsx +0 -697
  287. package/src/cli/cmd/tui/routes/session/question.tsx +0 -488
  288. package/src/cli/cmd/tui/routes/session/sidebar.tsx +0 -109
  289. package/src/cli/cmd/tui/routes/session/subagent-footer.tsx +0 -143
  290. package/src/cli/cmd/tui/thread.ts +0 -323
  291. package/src/cli/cmd/tui/ui/dialog-alert.tsx +0 -61
  292. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +0 -95
  293. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +0 -223
  294. package/src/cli/cmd/tui/ui/dialog-help.tsx +0 -42
  295. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +0 -123
  296. package/src/cli/cmd/tui/ui/dialog-select.tsx +0 -467
  297. package/src/cli/cmd/tui/ui/dialog.tsx +0 -207
  298. package/src/cli/cmd/tui/ui/link.tsx +0 -28
  299. package/src/cli/cmd/tui/ui/spinner.ts +0 -386
  300. package/src/cli/cmd/tui/ui/toast.tsx +0 -102
  301. package/src/cli/cmd/tui/util/clipboard.ts +0 -203
  302. package/src/cli/cmd/tui/util/editor.ts +0 -36
  303. package/src/cli/cmd/tui/util/image-protocol.ts +0 -35
  304. package/src/cli/cmd/tui/util/index.ts +0 -6
  305. package/src/cli/cmd/tui/util/model.ts +0 -23
  306. package/src/cli/cmd/tui/util/pinyin.ts +0 -20
  307. package/src/cli/cmd/tui/util/provider-origin.ts +0 -7
  308. package/src/cli/cmd/tui/util/revert-diff.ts +0 -18
  309. package/src/cli/cmd/tui/util/scroll.ts +0 -23
  310. package/src/cli/cmd/tui/util/selection.ts +0 -23
  311. package/src/cli/cmd/tui/util/signal.ts +0 -71
  312. package/src/cli/cmd/tui/util/sound.ts +0 -154
  313. package/src/cli/cmd/tui/util/system-locale.ts +0 -209
  314. package/src/cli/cmd/tui/util/terminal.ts +0 -110
  315. package/src/cli/cmd/tui/util/transcript.ts +0 -112
  316. package/src/cli/cmd/tui/util/vad.ts +0 -229
  317. package/src/cli/cmd/tui/util/voice.ts +0 -595
  318. package/src/cli/cmd/tui/win32.ts +0 -130
  319. package/src/cli/cmd/tui/worker.ts +0 -104
  320. package/src/cli/cmd/uninstall.ts +0 -351
  321. package/src/cli/cmd/upgrade.ts +0 -79
  322. package/src/cli/cmd/web.ts +0 -96
  323. package/src/cli/effect/prompt.ts +0 -25
  324. package/src/cli/error.ts +0 -82
  325. package/src/cli/heap.ts +0 -59
  326. package/src/cli/i18n.ts +0 -15
  327. package/src/cli/logo.ts +0 -52
  328. package/src/cli/network.ts +0 -68
  329. package/src/cli/ui.ts +0 -133
  330. package/src/cli/upgrade.ts +0 -41
  331. package/src/command/index.ts +0 -276
  332. package/src/command/template/initialize.txt +0 -66
  333. package/src/command/template/review.txt +0 -101
  334. package/src/config/agent.ts +0 -197
  335. package/src/config/command.ts +0 -69
  336. package/src/config/compose.ts +0 -26
  337. package/src/config/config.ts +0 -1052
  338. package/src/config/console-state.ts +0 -16
  339. package/src/config/entry-name.ts +0 -16
  340. package/src/config/error.ts +0 -21
  341. package/src/config/formatter.ts +0 -17
  342. package/src/config/history.ts +0 -21
  343. package/src/config/index.ts +0 -17
  344. package/src/config/keybinds.ts +0 -127
  345. package/src/config/layout.ts +0 -10
  346. package/src/config/lsp.ts +0 -45
  347. package/src/config/managed.ts +0 -70
  348. package/src/config/markdown.ts +0 -97
  349. package/src/config/mcp.ts +0 -172
  350. package/src/config/model-id.ts +0 -14
  351. package/src/config/parse.ts +0 -44
  352. package/src/config/paths.ts +0 -73
  353. package/src/config/permission.ts +0 -76
  354. package/src/config/plugin.ts +0 -88
  355. package/src/config/provider.ts +0 -118
  356. package/src/config/server.ts +0 -20
  357. package/src/config/skills.ts +0 -16
  358. package/src/config/variable.ts +0 -90
  359. package/src/control-plane/adaptors/index.ts +0 -52
  360. package/src/control-plane/adaptors/worktree.ts +0 -47
  361. package/src/control-plane/dev/debug-workspace-plugin.ts +0 -73
  362. package/src/control-plane/schema.ts +0 -19
  363. package/src/control-plane/sse.ts +0 -66
  364. package/src/control-plane/types.ts +0 -34
  365. package/src/control-plane/util.ts +0 -37
  366. package/src/control-plane/workspace-context.ts +0 -26
  367. package/src/control-plane/workspace.sql.ts +0 -17
  368. package/src/control-plane/workspace.ts +0 -615
  369. package/src/effect/app-runtime.ts +0 -146
  370. package/src/effect/bootstrap-runtime.ts +0 -33
  371. package/src/effect/bridge.ts +0 -48
  372. package/src/effect/cross-spawn-spawner.ts +0 -514
  373. package/src/effect/index.ts +0 -5
  374. package/src/effect/instance-ref.ts +0 -11
  375. package/src/effect/instance-registry.ts +0 -12
  376. package/src/effect/instance-state.ts +0 -81
  377. package/src/effect/logger.ts +0 -73
  378. package/src/effect/memo-map.ts +0 -3
  379. package/src/effect/observability.ts +0 -107
  380. package/src/effect/run-service.ts +0 -52
  381. package/src/effect/runner.ts +0 -210
  382. package/src/effect/runtime.ts +0 -19
  383. package/src/env/index.ts +0 -37
  384. package/src/file/ignore.ts +0 -81
  385. package/src/file/index.ts +0 -664
  386. package/src/file/protected.ts +0 -59
  387. package/src/file/ripgrep.ts +0 -485
  388. package/src/file/watcher.ts +0 -163
  389. package/src/flag/flag.ts +0 -212
  390. package/src/format/formatter.ts +0 -403
  391. package/src/format/index.ts +0 -203
  392. package/src/git/index.ts +0 -260
  393. package/src/global/index.ts +0 -54
  394. package/src/history/backfill.ts +0 -162
  395. package/src/history/extract.ts +0 -67
  396. package/src/history/fts-query.ts +0 -15
  397. package/src/history/fts.sql.ts +0 -20
  398. package/src/history/index.ts +0 -10
  399. package/src/history/resolve.ts +0 -65
  400. package/src/history/service.ts +0 -258
  401. package/src/history/writer.ts +0 -112
  402. package/src/id/id.ts +0 -87
  403. package/src/ide/index.ts +0 -73
  404. package/src/inbox/inbox-ref.ts +0 -38
  405. package/src/inbox/inbox.sql.ts +0 -26
  406. package/src/inbox/inbox.ts +0 -223
  407. package/src/inbox/index.ts +0 -3
  408. package/src/inbox/render.ts +0 -40
  409. package/src/index.ts +0 -261
  410. package/src/installation/index.ts +0 -362
  411. package/src/installation/version.ts +0 -32
  412. package/src/intelligence/AUDIT.md +0 -292
  413. package/src/intelligence/ENTERPRISE-CAPABILITIES.md +0 -317
  414. package/src/intelligence/ENTERPRISE-REVIEW.md +0 -284
  415. package/src/intelligence/IMPLEMENTATION.md +0 -214
  416. package/src/intelligence/PHASE1.md +0 -178
  417. package/src/intelligence/PHASE2.5.md +0 -162
  418. package/src/intelligence/PHASE2.md +0 -150
  419. package/src/intelligence/PHASE3-REFINED.md +0 -257
  420. package/src/intelligence/PHASE3.md +0 -188
  421. package/src/intelligence/README.md +0 -260
  422. package/src/intelligence/analytics/SKILL.md +0 -369
  423. package/src/intelligence/analytics/adapters/index.ts +0 -77
  424. package/src/intelligence/analytics/benchmarks/observable-runner.ts +0 -575
  425. package/src/intelligence/analytics/benchmarks/runner.ts +0 -758
  426. package/src/intelligence/analytics/engine/index.ts +0 -152
  427. package/src/intelligence/analytics/hook.ts +0 -154
  428. package/src/intelligence/analytics/index.ts +0 -194
  429. package/src/intelligence/analytics/loader/index.ts +0 -502
  430. package/src/intelligence/analytics/memory/index.ts +0 -455
  431. package/src/intelligence/analytics/orchestrator/index.ts +0 -329
  432. package/src/intelligence/analytics/planner/index.ts +0 -188
  433. package/src/intelligence/analytics/prompt/index.ts +0 -449
  434. package/src/intelligence/analytics/reasoning/enterprise-capabilities.ts +0 -534
  435. package/src/intelligence/analytics/reasoning/enterprise-prompt.ts +0 -321
  436. package/src/intelligence/analytics/reasoning/index.ts +0 -267
  437. package/src/intelligence/analytics/reasoning/test.ts +0 -166
  438. package/src/intelligence/analytics/reasoning/visible-reasoning.ts +0 -609
  439. package/src/intelligence/analytics/registry/index.ts +0 -176
  440. package/src/intelligence/analytics/router/index.ts +0 -352
  441. package/src/intelligence/analytics/test.ts +0 -127
  442. package/src/intelligence/analytics/workflow/index.ts +0 -375
  443. package/src/intelligence/index.ts +0 -50
  444. package/src/lsp/client.ts +0 -249
  445. package/src/lsp/diagnostic.ts +0 -29
  446. package/src/lsp/index.ts +0 -3
  447. package/src/lsp/language.ts +0 -120
  448. package/src/lsp/launch.ts +0 -21
  449. package/src/lsp/lsp.ts +0 -519
  450. package/src/lsp/server.ts +0 -1956
  451. package/src/mcp/auth.ts +0 -144
  452. package/src/mcp/index.ts +0 -939
  453. package/src/mcp/oauth-callback.ts +0 -236
  454. package/src/mcp/oauth-provider.ts +0 -214
  455. package/src/memory/fts-query.ts +0 -37
  456. package/src/memory/fts.sql.ts +0 -19
  457. package/src/memory/index.ts +0 -1
  458. package/src/memory/paths.ts +0 -116
  459. package/src/memory/reconcile.ts +0 -144
  460. package/src/memory/service.ts +0 -144
  461. package/src/metrics/client.ts +0 -40
  462. package/src/metrics/event.ts +0 -43
  463. package/src/metrics/index.ts +0 -5
  464. package/src/metrics/installation.ts +0 -18
  465. package/src/metrics/subscriber.ts +0 -58
  466. package/src/metrics/util.ts +0 -9
  467. package/src/node.ts +0 -6
  468. package/src/npm/config.ts +0 -0
  469. package/src/npm/index.ts +0 -293
  470. package/src/npmcli-config.d.ts +0 -43
  471. package/src/patch/index.ts +0 -680
  472. package/src/permission/arity.ts +0 -163
  473. package/src/permission/evaluate.ts +0 -15
  474. package/src/permission/index.ts +0 -382
  475. package/src/permission/schema.ts +0 -17
  476. package/src/plugin/checkpoint-splitover.ts +0 -60
  477. package/src/plugin/cloudflare.ts +0 -76
  478. package/src/plugin/codex.ts +0 -611
  479. package/src/plugin/github-copilot/copilot.ts +0 -368
  480. package/src/plugin/github-copilot/models.ts +0 -153
  481. package/src/plugin/index.ts +0 -637
  482. package/src/plugin/install.ts +0 -439
  483. package/src/plugin/loader.ts +0 -216
  484. package/src/plugin/matcher.ts +0 -33
  485. package/src/plugin/meta.ts +0 -188
  486. package/src/plugin/mimo.ts +0 -296
  487. package/src/plugin/shared.ts +0 -323
  488. package/src/plugin/subagent-progress-checker.ts +0 -147
  489. package/src/project/bootstrap.ts +0 -59
  490. package/src/project/index.ts +0 -2
  491. package/src/project/instance.ts +0 -215
  492. package/src/project/project-id.ts +0 -48
  493. package/src/project/project.sql.ts +0 -16
  494. package/src/project/project.ts +0 -522
  495. package/src/project/schema.ts +0 -15
  496. package/src/project/vcs.ts +0 -227
  497. package/src/project/workspace-trust.ts +0 -67
  498. package/src/provider/auth.ts +0 -234
  499. package/src/provider/error.ts +0 -216
  500. package/src/provider/index.ts +0 -5
  501. package/src/provider/models.ts +0 -180
  502. package/src/provider/provider.ts +0 -1788
  503. package/src/provider/schema.ts +0 -36
  504. package/src/provider/sdk/copilot/README.md +0 -5
  505. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +0 -170
  506. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +0 -15
  507. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +0 -19
  508. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +0 -64
  509. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +0 -815
  510. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +0 -28
  511. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +0 -44
  512. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +0 -83
  513. package/src/provider/sdk/copilot/copilot-provider.ts +0 -100
  514. package/src/provider/sdk/copilot/index.ts +0 -2
  515. package/src/provider/sdk/copilot/openai-compatible-error.ts +0 -27
  516. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +0 -335
  517. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +0 -22
  518. package/src/provider/sdk/copilot/responses/openai-config.ts +0 -18
  519. package/src/provider/sdk/copilot/responses/openai-error.ts +0 -22
  520. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +0 -214
  521. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +0 -1770
  522. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +0 -173
  523. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +0 -1
  524. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +0 -87
  525. package/src/provider/sdk/copilot/responses/tool/file-search.ts +0 -127
  526. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +0 -114
  527. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +0 -64
  528. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +0 -103
  529. package/src/provider/sdk/copilot/responses/tool/web-search.ts +0 -102
  530. package/src/provider/transform.ts +0 -1376
  531. package/src/pty/index.ts +0 -364
  532. package/src/pty/pty.bun.ts +0 -26
  533. package/src/pty/pty.node.ts +0 -27
  534. package/src/pty/pty.ts +0 -25
  535. package/src/pty/schema.ts +0 -17
  536. package/src/question/index.ts +0 -252
  537. package/src/question/schema.ts +0 -17
  538. package/src/server/adapter.bun.ts +0 -40
  539. package/src/server/adapter.node.ts +0 -66
  540. package/src/server/adapter.ts +0 -21
  541. package/src/server/auth.ts +0 -16
  542. package/src/server/error.ts +0 -53
  543. package/src/server/event.ts +0 -7
  544. package/src/server/fence.ts +0 -81
  545. package/src/server/mdns.ts +0 -60
  546. package/src/server/middleware.ts +0 -94
  547. package/src/server/projectors.ts +0 -28
  548. package/src/server/proxy.ts +0 -171
  549. package/src/server/pty-ticket.ts +0 -42
  550. package/src/server/rate-limit.ts +0 -38
  551. package/src/server/routes/control/index.ts +0 -160
  552. package/src/server/routes/control/workspace.ts +0 -203
  553. package/src/server/routes/global.ts +0 -367
  554. package/src/server/routes/instance/bash-interactive.ts +0 -82
  555. package/src/server/routes/instance/config.ts +0 -89
  556. package/src/server/routes/instance/event.ts +0 -108
  557. package/src/server/routes/instance/experimental.ts +0 -408
  558. package/src/server/routes/instance/file.ts +0 -190
  559. package/src/server/routes/instance/httpapi/config.ts +0 -51
  560. package/src/server/routes/instance/httpapi/permission.ts +0 -72
  561. package/src/server/routes/instance/httpapi/project.ts +0 -62
  562. package/src/server/routes/instance/httpapi/provider.ts +0 -142
  563. package/src/server/routes/instance/httpapi/question.ts +0 -121
  564. package/src/server/routes/instance/httpapi/server.ts +0 -153
  565. package/src/server/routes/instance/index.ts +0 -301
  566. package/src/server/routes/instance/mcp.ts +0 -260
  567. package/src/server/routes/instance/middleware.ts +0 -44
  568. package/src/server/routes/instance/permission.ts +0 -73
  569. package/src/server/routes/instance/project.ts +0 -122
  570. package/src/server/routes/instance/provider.ts +0 -158
  571. package/src/server/routes/instance/pty.ts +0 -302
  572. package/src/server/routes/instance/question.ts +0 -162
  573. package/src/server/routes/instance/session.ts +0 -1328
  574. package/src/server/routes/instance/sync.ts +0 -143
  575. package/src/server/routes/instance/trace.ts +0 -59
  576. package/src/server/routes/instance/tui.ts +0 -384
  577. package/src/server/routes/instance/workflows.ts +0 -142
  578. package/src/server/routes/ui.ts +0 -37
  579. package/src/server/server.ts +0 -146
  580. package/src/server/workspace.ts +0 -122
  581. package/src/session/auto-dream.ts +0 -123
  582. package/src/session/boundary.ts +0 -77
  583. package/src/session/budgeted-read.ts +0 -118
  584. package/src/session/checkpoint-align.ts +0 -29
  585. package/src/session/checkpoint-context.ts +0 -36
  586. package/src/session/checkpoint-paths.ts +0 -86
  587. package/src/session/checkpoint-progress-reconcile.ts +0 -111
  588. package/src/session/checkpoint-retry.ts +0 -192
  589. package/src/session/checkpoint-templates.ts +0 -114
  590. package/src/session/checkpoint-validator.ts +0 -259
  591. package/src/session/checkpoint.ts +0 -1560
  592. package/src/session/classify.ts +0 -117
  593. package/src/session/claude-import.ts +0 -381
  594. package/src/session/codex-import.ts +0 -416
  595. package/src/session/compaction.ts +0 -545
  596. package/src/session/external-import.sql.ts +0 -18
  597. package/src/session/external-import.ts +0 -136
  598. package/src/session/goal.ts +0 -232
  599. package/src/session/index.ts +0 -1
  600. package/src/session/instruction.ts +0 -276
  601. package/src/session/last-message-info.ts +0 -32
  602. package/src/session/llm-request-prefix.ts +0 -82
  603. package/src/session/llm.ts +0 -734
  604. package/src/session/max-mode.ts +0 -410
  605. package/src/session/message-v2.ts +0 -1138
  606. package/src/session/message.ts +0 -191
  607. package/src/session/opendash-import.ts +0 -281
  608. package/src/session/overflow.ts +0 -53
  609. package/src/session/prefix-capture-ref.ts +0 -48
  610. package/src/session/processor.ts +0 -983
  611. package/src/session/projectors.ts +0 -137
  612. package/src/session/prompt/anthropic.txt +0 -177
  613. package/src/session/prompt/beast.txt +0 -186
  614. package/src/session/prompt/build-switch.txt +0 -5
  615. package/src/session/prompt/codex.txt +0 -108
  616. package/src/session/prompt/compose.txt +0 -119
  617. package/src/session/prompt/copilot-gpt-5.txt +0 -173
  618. package/src/session/prompt/deepseek.txt +0 -156
  619. package/src/session/prompt/default.old.txt +0 -151
  620. package/src/session/prompt/default.txt +0 -209
  621. package/src/session/prompt/gemini.txt +0 -186
  622. package/src/session/prompt/glm.txt +0 -73
  623. package/src/session/prompt/gpt.txt +0 -134
  624. package/src/session/prompt/kimi.txt +0 -117
  625. package/src/session/prompt/max-steps.txt +0 -16
  626. package/src/session/prompt/minimax.txt +0 -165
  627. package/src/session/prompt/text-loop-recovery.ts +0 -40
  628. package/src/session/prompt/text-ngram-detection.ts +0 -116
  629. package/src/session/prompt/trinity.txt +0 -128
  630. package/src/session/prompt.ts +0 -3878
  631. package/src/session/prune.ts +0 -481
  632. package/src/session/retry.ts +0 -178
  633. package/src/session/revert.ts +0 -161
  634. package/src/session/run-state.ts +0 -135
  635. package/src/session/schema.ts +0 -36
  636. package/src/session/session.sql.ts +0 -110
  637. package/src/session/session.ts +0 -908
  638. package/src/session/status.ts +0 -89
  639. package/src/session/summary.ts +0 -163
  640. package/src/session/system.ts +0 -97
  641. package/src/session/todo.ts +0 -77
  642. package/src/session/trajectory.ts +0 -98
  643. package/src/share/index.ts +0 -2
  644. package/src/share/session.ts +0 -57
  645. package/src/share/share-next.ts +0 -381
  646. package/src/share/share.sql.ts +0 -13
  647. package/src/shell/shell.ts +0 -124
  648. package/src/skill/builtin/.bundle/self-extend/SKILL.md +0 -131
  649. package/src/skill/builtin/.bundle/self-extend/reference/hook-api.md +0 -242
  650. package/src/skill/builtin/.bundle/self-extend/reference/skill-api.md +0 -114
  651. package/src/skill/builtin/.bundle/self-extend/reference/tool-api.md +0 -115
  652. package/src/skill/builtin/.bundle/self-extend/reference/tui-api.md +0 -258
  653. package/src/skill/builtin/bundle.macro.ts +0 -30
  654. package/src/skill/builtin/extract.ts +0 -41
  655. package/src/skill/compose/.bundle/ask/SKILL.md +0 -58
  656. package/src/skill/compose/.bundle/brainstorm/SKILL.md +0 -200
  657. package/src/skill/compose/.bundle/brainstorm/scripts/frame-template.html +0 -214
  658. package/src/skill/compose/.bundle/brainstorm/scripts/helper.js +0 -88
  659. package/src/skill/compose/.bundle/brainstorm/scripts/server.cjs +0 -354
  660. package/src/skill/compose/.bundle/brainstorm/scripts/start-server.sh +0 -148
  661. package/src/skill/compose/.bundle/brainstorm/scripts/stop-server.sh +0 -56
  662. package/src/skill/compose/.bundle/brainstorm/spec-document-reviewer-prompt.md +0 -50
  663. package/src/skill/compose/.bundle/brainstorm/visual-companion.md +0 -258
  664. package/src/skill/compose/.bundle/debug/CREATION-LOG.md +0 -119
  665. package/src/skill/compose/.bundle/debug/SKILL.md +0 -297
  666. package/src/skill/compose/.bundle/debug/condition-based-waiting-example.ts +0 -158
  667. package/src/skill/compose/.bundle/debug/condition-based-waiting.md +0 -106
  668. package/src/skill/compose/.bundle/debug/defense-in-depth.md +0 -122
  669. package/src/skill/compose/.bundle/debug/find-polluter.sh +0 -63
  670. package/src/skill/compose/.bundle/debug/root-cause-tracing.md +0 -144
  671. package/src/skill/compose/.bundle/debug/test-academic.md +0 -14
  672. package/src/skill/compose/.bundle/debug/test-pressure-1.md +0 -58
  673. package/src/skill/compose/.bundle/debug/test-pressure-2.md +0 -68
  674. package/src/skill/compose/.bundle/debug/test-pressure-3.md +0 -69
  675. package/src/skill/compose/.bundle/execute/SKILL.md +0 -71
  676. package/src/skill/compose/.bundle/feedback/SKILL.md +0 -214
  677. package/src/skill/compose/.bundle/merge/SKILL.md +0 -252
  678. package/src/skill/compose/.bundle/new-skill/SKILL.md +0 -211
  679. package/src/skill/compose/.bundle/parallel/SKILL.md +0 -168
  680. package/src/skill/compose/.bundle/plan/SKILL.md +0 -183
  681. package/src/skill/compose/.bundle/plan/plan-document-reviewer-prompt.md +0 -50
  682. package/src/skill/compose/.bundle/report/SKILL.md +0 -180
  683. package/src/skill/compose/.bundle/review/SKILL.md +0 -104
  684. package/src/skill/compose/.bundle/review/code-reviewer.md +0 -178
  685. package/src/skill/compose/.bundle/subagent/SKILL.md +0 -325
  686. package/src/skill/compose/.bundle/subagent/code-quality-reviewer-prompt.md +0 -26
  687. package/src/skill/compose/.bundle/subagent/implementer-prompt.md +0 -128
  688. package/src/skill/compose/.bundle/subagent/spec-reviewer-prompt.md +0 -118
  689. package/src/skill/compose/.bundle/tdd/SKILL.md +0 -360
  690. package/src/skill/compose/.bundle/tdd/testing-anti-patterns.md +0 -299
  691. package/src/skill/compose/.bundle/verify/SKILL.md +0 -140
  692. package/src/skill/compose/.bundle/worktree/SKILL.md +0 -234
  693. package/src/skill/compose/LICENSE-karpathy +0 -28
  694. package/src/skill/compose/bundle.macro.ts +0 -30
  695. package/src/skill/compose/extract.ts +0 -85
  696. package/src/skill/discovery.ts +0 -116
  697. package/src/skill/index.ts +0 -328
  698. package/src/snapshot/index.ts +0 -777
  699. package/src/sql.d.ts +0 -4
  700. package/src/storage/db.bun.ts +0 -8
  701. package/src/storage/db.node.ts +0 -8
  702. package/src/storage/db.ts +0 -172
  703. package/src/storage/index.ts +0 -26
  704. package/src/storage/json-migration.ts +0 -426
  705. package/src/storage/read-sqlite.bun.ts +0 -11
  706. package/src/storage/read-sqlite.node.ts +0 -13
  707. package/src/storage/read-sqlite.ts +0 -10
  708. package/src/storage/schema.sql.ts +0 -10
  709. package/src/storage/schema.ts +0 -7
  710. package/src/storage/storage.ts +0 -331
  711. package/src/sync/README.md +0 -179
  712. package/src/sync/event.sql.ts +0 -16
  713. package/src/sync/index.ts +0 -278
  714. package/src/sync/schema.ts +0 -14
  715. package/src/task/events.ts +0 -28
  716. package/src/task/gate-state.ts +0 -54
  717. package/src/task/gate.ts +0 -116
  718. package/src/task/index.ts +0 -1
  719. package/src/task/registry.ts +0 -394
  720. package/src/task/schema.ts +0 -43
  721. package/src/task/task.sql.ts +0 -50
  722. package/src/team/events.ts +0 -22
  723. package/src/team/index.ts +0 -113
  724. package/src/team/schema.ts +0 -31
  725. package/src/temporary.ts +0 -33
  726. package/src/tool/actor.shell.txt +0 -72
  727. package/src/tool/actor.ts +0 -804
  728. package/src/tool/actor.txt +0 -103
  729. package/src/tool/apply_patch.ts +0 -308
  730. package/src/tool/apply_patch.txt +0 -33
  731. package/src/tool/bash-interactive.ts +0 -183
  732. package/src/tool/bash.ts +0 -722
  733. package/src/tool/bash.txt +0 -123
  734. package/src/tool/bash_token_efficient_pipeline.ts +0 -189
  735. package/src/tool/change-directory.ts +0 -91
  736. package/src/tool/codesearch.ts +0 -63
  737. package/src/tool/codesearch.txt +0 -12
  738. package/src/tool/edit.ts +0 -752
  739. package/src/tool/edit.txt +0 -10
  740. package/src/tool/external-directory.ts +0 -132
  741. package/src/tool/glob.ts +0 -100
  742. package/src/tool/glob.txt +0 -6
  743. package/src/tool/grep.ts +0 -145
  744. package/src/tool/grep.txt +0 -8
  745. package/src/tool/history.ts +0 -146
  746. package/src/tool/history.txt +0 -17
  747. package/src/tool/index.ts +0 -4
  748. package/src/tool/invalid.ts +0 -20
  749. package/src/tool/invocation-style.ts +0 -17
  750. package/src/tool/lsp.ts +0 -91
  751. package/src/tool/lsp.txt +0 -19
  752. package/src/tool/mcp-exa.ts +0 -78
  753. package/src/tool/memory-path-guard.ts +0 -162
  754. package/src/tool/memory.ts +0 -81
  755. package/src/tool/memory.txt +0 -69
  756. package/src/tool/multiedit.ts +0 -54
  757. package/src/tool/multiedit.txt +0 -41
  758. package/src/tool/notebook-edit.ts +0 -225
  759. package/src/tool/notebook-edit.txt +0 -10
  760. package/src/tool/plan-enter.txt +0 -16
  761. package/src/tool/plan-exit.txt +0 -14
  762. package/src/tool/plan.ts +0 -179
  763. package/src/tool/question.ts +0 -67
  764. package/src/tool/question.txt +0 -10
  765. package/src/tool/read-state.ts +0 -44
  766. package/src/tool/read.ts +0 -327
  767. package/src/tool/read.txt +0 -14
  768. package/src/tool/recoverable.ts +0 -35
  769. package/src/tool/registry.ts +0 -429
  770. package/src/tool/schema.ts +0 -17
  771. package/src/tool/session-cwd.ts +0 -35
  772. package/src/tool/shell-tokenize.ts +0 -374
  773. package/src/tool/shell-wrap.ts +0 -235
  774. package/src/tool/skill.ts +0 -76
  775. package/src/tool/skill.txt +0 -5
  776. package/src/tool/task.shell.txt +0 -57
  777. package/src/tool/task.ts +0 -456
  778. package/src/tool/task.txt +0 -56
  779. package/src/tool/tool.ts +0 -166
  780. package/src/tool/truncate.ts +0 -201
  781. package/src/tool/truncation-dir.ts +0 -4
  782. package/src/tool/webfetch.ts +0 -208
  783. package/src/tool/webfetch.txt +0 -13
  784. package/src/tool/websearch/index.ts +0 -104
  785. package/src/tool/websearch/mimo.ts +0 -118
  786. package/src/tool/websearch/websearch.txt +0 -14
  787. package/src/tool/workflow.ts +0 -357
  788. package/src/tool/workflow.txt +0 -25
  789. package/src/tool/write.ts +0 -88
  790. package/src/tool/write.txt +0 -10
  791. package/src/util/abort.ts +0 -35
  792. package/src/util/archive.ts +0 -15
  793. package/src/util/color.ts +0 -17
  794. package/src/util/data-url.ts +0 -9
  795. package/src/util/defer.ts +0 -10
  796. package/src/util/effect-http-client.ts +0 -11
  797. package/src/util/effect-zod.ts +0 -367
  798. package/src/util/env-info.ts +0 -62
  799. package/src/util/error.ts +0 -78
  800. package/src/util/filesystem.ts +0 -243
  801. package/src/util/fn.ts +0 -21
  802. package/src/util/format.ts +0 -20
  803. package/src/util/iife.ts +0 -3
  804. package/src/util/index.ts +0 -14
  805. package/src/util/keybind.ts +0 -101
  806. package/src/util/lazy.ts +0 -18
  807. package/src/util/local-context.ts +0 -23
  808. package/src/util/locale.ts +0 -79
  809. package/src/util/lock.ts +0 -96
  810. package/src/util/log.ts +0 -234
  811. package/src/util/media.ts +0 -26
  812. package/src/util/network.ts +0 -9
  813. package/src/util/opendash-process.ts +0 -24
  814. package/src/util/process.ts +0 -174
  815. package/src/util/provider-priority.ts +0 -48
  816. package/src/util/queue.ts +0 -60
  817. package/src/util/record.ts +0 -3
  818. package/src/util/rpc.ts +0 -64
  819. package/src/util/schema.ts +0 -53
  820. package/src/util/scrap.ts +0 -10
  821. package/src/util/signal.ts +0 -12
  822. package/src/util/ssrf.ts +0 -116
  823. package/src/util/timeout.ts +0 -14
  824. package/src/util/token.ts +0 -5
  825. package/src/util/tool-compat.ts +0 -144
  826. package/src/util/update-schema.ts +0 -13
  827. package/src/util/which.ts +0 -14
  828. package/src/util/wildcard.ts +0 -57
  829. package/src/workflow/builtin/compose.js +0 -749
  830. package/src/workflow/builtin/deep-research.js +0 -398
  831. package/src/workflow/builtin.ts +0 -59
  832. package/src/workflow/events.ts +0 -72
  833. package/src/workflow/meta.ts +0 -335
  834. package/src/workflow/persistence.ts +0 -312
  835. package/src/workflow/resolve.ts +0 -45
  836. package/src/workflow/runtime-ref.ts +0 -18
  837. package/src/workflow/runtime.ts +0 -1447
  838. package/src/workflow/sandbox.ts +0 -286
  839. package/src/workflow/workflow.sql.ts +0 -31
  840. package/src/workflow/workspace.ts +0 -69
  841. package/src/worktree/index.ts +0 -629
  842. package/sst-env.d.ts +0 -10
  843. package/test/AGENTS.md +0 -133
  844. package/test/account/repo.test.ts +0 -352
  845. package/test/account/service.test.ts +0 -456
  846. package/test/acp/agent-interface.test.ts +0 -51
  847. package/test/acp/event-subscription.test.ts +0 -725
  848. package/test/actor/cancel-cascade.test.ts +0 -432
  849. package/test/actor/no-completion-listener.test.ts +0 -41
  850. package/test/actor/poststop-progress-write-permission.repro.test.ts +0 -414
  851. package/test/actor/registry-render.test.ts +0 -113
  852. package/test/actor/registry-status.test.ts +0 -111
  853. package/test/actor/registry.test.ts +0 -619
  854. package/test/actor/return-header.test.ts +0 -40
  855. package/test/actor/spawn-lifecycle.test.ts +0 -346
  856. package/test/actor/spawn-no-deadlock.test.ts +0 -340
  857. package/test/actor/spawn-notification.test.ts +0 -393
  858. package/test/actor/spawn-task-autostart.test.ts +0 -530
  859. package/test/actor/spawn.test.ts +0 -1106
  860. package/test/actor/status-event-payload.test.ts +0 -132
  861. package/test/actor/terminology.test.ts +0 -39
  862. package/test/actor/turn.test.ts +0 -125
  863. package/test/actor/waiter.test.ts +0 -246
  864. package/test/agent/agent.test.ts +0 -935
  865. package/test/agent/allowlist.test.ts +0 -45
  866. package/test/auth/auth.test.ts +0 -86
  867. package/test/bus/bus-effect.test.ts +0 -162
  868. package/test/bus/bus-integration.test.ts +0 -87
  869. package/test/bus/bus.test.ts +0 -219
  870. package/test/cli/account.test.ts +0 -26
  871. package/test/cli/cmd/tui/autocomplete-detect.test.ts +0 -55
  872. package/test/cli/cmd/tui/extmark-cjk.test.ts +0 -96
  873. package/test/cli/cmd/tui/offset.test.ts +0 -101
  874. package/test/cli/cmd/tui/prompt-part.test.ts +0 -97
  875. package/test/cli/error.test.ts +0 -18
  876. package/test/cli/github-action.test.ts +0 -198
  877. package/test/cli/github-remote.test.ts +0 -80
  878. package/test/cli/import.test.ts +0 -54
  879. package/test/cli/plugin-auth-picker.test.ts +0 -120
  880. package/test/cli/run-completion.test.ts +0 -131
  881. package/test/cli/tui/keybind-plugin.test.ts +0 -90
  882. package/test/cli/tui/plugin-add.test.ts +0 -111
  883. package/test/cli/tui/plugin-install.test.ts +0 -87
  884. package/test/cli/tui/plugin-lifecycle.test.ts +0 -224
  885. package/test/cli/tui/plugin-loader-entrypoint.test.ts +0 -484
  886. package/test/cli/tui/plugin-loader-pure.test.ts +0 -71
  887. package/test/cli/tui/plugin-loader.test.ts +0 -816
  888. package/test/cli/tui/plugin-toggle.test.ts +0 -157
  889. package/test/cli/tui/revert-diff.test.ts +0 -35
  890. package/test/cli/tui/route-agent-id.test.ts +0 -26
  891. package/test/cli/tui/sidebar-tps.test.ts +0 -63
  892. package/test/cli/tui/slot-replace.test.tsx +0 -47
  893. package/test/cli/tui/sync-bucket.test.ts +0 -29
  894. package/test/cli/tui/theme-store.test.ts +0 -51
  895. package/test/cli/tui/thread.test.ts +0 -125
  896. package/test/cli/tui/transcript.test.ts +0 -426
  897. package/test/cli/tui/use-event.test.tsx +0 -175
  898. package/test/cli/tui/voice.test.ts +0 -443
  899. package/test/command/deep-research-command.test.ts +0 -16
  900. package/test/config/agent-color.test.ts +0 -77
  901. package/test/config/checkpoint-fork.test.ts +0 -21
  902. package/test/config/config.test.ts +0 -2577
  903. package/test/config/fixtures/empty-frontmatter.md +0 -4
  904. package/test/config/fixtures/frontmatter.md +0 -28
  905. package/test/config/fixtures/markdown-header.md +0 -11
  906. package/test/config/fixtures/no-frontmatter.md +0 -1
  907. package/test/config/fixtures/weird-model-id.md +0 -13
  908. package/test/config/lsp.test.ts +0 -87
  909. package/test/config/markdown.test.ts +0 -228
  910. package/test/config/plugin.test.ts +0 -0
  911. package/test/config/tui.test.ts +0 -627
  912. package/test/control-plane/adaptors.test.ts +0 -71
  913. package/test/control-plane/sse.test.ts +0 -56
  914. package/test/effect/app-runtime-logger.test.ts +0 -92
  915. package/test/effect/cross-spawn-spawner.test.ts +0 -411
  916. package/test/effect/instance-state.test.ts +0 -482
  917. package/test/effect/observability.test.ts +0 -46
  918. package/test/effect/run-service.test.ts +0 -46
  919. package/test/effect/runner-warn-log.test.ts +0 -111
  920. package/test/effect/runner.test.ts +0 -494
  921. package/test/fake/provider.ts +0 -90
  922. package/test/file/fsmonitor.test.ts +0 -68
  923. package/test/file/ignore.test.ts +0 -10
  924. package/test/file/index.test.ts +0 -963
  925. package/test/file/path-traversal.test.ts +0 -243
  926. package/test/file/ripgrep.test.ts +0 -218
  927. package/test/file/watcher.test.ts +0 -249
  928. package/test/filesystem/filesystem.test.ts +0 -319
  929. package/test/fixture/db.ts +0 -11
  930. package/test/fixture/fixture.test.ts +0 -58
  931. package/test/fixture/fixture.ts +0 -223
  932. package/test/fixture/flock-worker.ts +0 -72
  933. package/test/fixture/lsp/fake-lsp-server.js +0 -75
  934. package/test/fixture/plug-worker.ts +0 -93
  935. package/test/fixture/plugin-meta-worker.ts +0 -19
  936. package/test/fixture/skills/agents-sdk/SKILL.md +0 -152
  937. package/test/fixture/skills/agents-sdk/references/callable.md +0 -92
  938. package/test/fixture/skills/cloudflare/SKILL.md +0 -211
  939. package/test/fixture/skills/index.json +0 -6
  940. package/test/fixture/tui-plugin.ts +0 -328
  941. package/test/fixture/tui-runtime.ts +0 -31
  942. package/test/format/format.test.ts +0 -244
  943. package/test/git/git.test.ts +0 -128
  944. package/test/global/fixture/global-paths-worker.ts +0 -17
  945. package/test/global/mimocode-home.test.ts +0 -143
  946. package/test/history/backfill.test.ts +0 -160
  947. package/test/history/extract.test.ts +0 -106
  948. package/test/history/fts-query.test.ts +0 -30
  949. package/test/history/resolve.test.ts +0 -130
  950. package/test/history/service.test.ts +0 -210
  951. package/test/history/writer.test.ts +0 -163
  952. package/test/ide/ide.test.ts +0 -82
  953. package/test/inbox/drain-in-loop.test.ts +0 -230
  954. package/test/inbox/fork-agent-compat.test.ts +0 -387
  955. package/test/inbox/gc-on-init.test.ts +0 -167
  956. package/test/inbox/send-no-block.test.ts +0 -120
  957. package/test/inbox/sender-cancel-independence.test.ts +0 -160
  958. package/test/inbox/wake-matrix.test.ts +0 -141
  959. package/test/installation/installation.test.ts +0 -255
  960. package/test/keybind.test.ts +0 -421
  961. package/test/lib/effect.ts +0 -53
  962. package/test/lib/filesystem.ts +0 -10
  963. package/test/lib/llm-server.ts +0 -770
  964. package/test/lib/mock-llm.ts +0 -159
  965. package/test/lib/scripted-llm-server.ts +0 -245
  966. package/test/lsp/client.test.ts +0 -98
  967. package/test/lsp/index.test.ts +0 -109
  968. package/test/lsp/launch.test.ts +0 -22
  969. package/test/lsp/lifecycle.test.ts +0 -184
  970. package/test/mcp/headers.test.ts +0 -178
  971. package/test/mcp/lifecycle.test.ts +0 -786
  972. package/test/mcp/oauth-auto-connect.test.ts +0 -281
  973. package/test/mcp/oauth-browser.test.ts +0 -268
  974. package/test/mcp/oauth-callback.test.ts +0 -34
  975. package/test/memory/abort-leak-webfetch.ts +0 -49
  976. package/test/memory/abort-leak.test.ts +0 -127
  977. package/test/memory/cc-frontmatter.test.ts +0 -85
  978. package/test/memory/cc-paths.test.ts +0 -60
  979. package/test/memory/cc-reconcile.test.ts +0 -239
  980. package/test/memory/cc-search.test.ts +0 -151
  981. package/test/memory/fts-query.test.ts +0 -48
  982. package/test/memory/fts-rowid-stability.test.ts +0 -271
  983. package/test/memory/paths.test.ts +0 -210
  984. package/test/memory/reconcile.test.ts +0 -115
  985. package/test/memory/service.test.ts +0 -169
  986. package/test/npm.test.ts +0 -18
  987. package/test/patch/patch.test.ts +0 -348
  988. package/test/permission/abort.test.ts +0 -116
  989. package/test/permission/arity.test.ts +0 -33
  990. package/test/permission/disabled.test.ts +0 -68
  991. package/test/permission/next.test.ts +0 -1116
  992. package/test/permission/non-interactive.test.ts +0 -55
  993. package/test/permission-task.test.ts +0 -326
  994. package/test/plugin/actor-hooks.test.ts +0 -1471
  995. package/test/plugin/auth-override.test.ts +0 -79
  996. package/test/plugin/checkpoint-splitover.test.ts +0 -434
  997. package/test/plugin/cloudflare.test.ts +0 -68
  998. package/test/plugin/codex.test.ts +0 -123
  999. package/test/plugin/github-copilot-models.test.ts +0 -163
  1000. package/test/plugin/install-concurrency.test.ts +0 -140
  1001. package/test/plugin/install.test.ts +0 -570
  1002. package/test/plugin/loader-shared.test.ts +0 -1169
  1003. package/test/plugin/matcher.test.ts +0 -97
  1004. package/test/plugin/meta.test.ts +0 -137
  1005. package/test/plugin/mimo.test.ts +0 -259
  1006. package/test/plugin/session-loop-hooks.test.ts +0 -159
  1007. package/test/plugin/shared.test.ts +0 -88
  1008. package/test/plugin/subagent-progress-checker.test.ts +0 -227
  1009. package/test/plugin/trigger.test.ts +0 -116
  1010. package/test/plugin/workspace-adaptor.test.ts +0 -109
  1011. package/test/preload.ts +0 -102
  1012. package/test/project/migrate-global.test.ts +0 -152
  1013. package/test/project/project-id.test.ts +0 -64
  1014. package/test/project/project.test.ts +0 -504
  1015. package/test/project/vcs.test.ts +0 -286
  1016. package/test/project/worktree-remove.test.ts +0 -126
  1017. package/test/project/worktree.test.ts +0 -222
  1018. package/test/provider/amazon-bedrock.test.ts +0 -462
  1019. package/test/provider/copilot/convert-to-copilot-messages.test.ts +0 -523
  1020. package/test/provider/copilot/copilot-chat-model.test.ts +0 -592
  1021. package/test/provider/error.test.ts +0 -160
  1022. package/test/provider/gitlab-duo.test.ts +0 -413
  1023. package/test/provider/model-groups.test.ts +0 -389
  1024. package/test/provider/provider-chunk-timeout.test.ts +0 -23
  1025. package/test/provider/provider.test.ts +0 -2610
  1026. package/test/provider/transform.test.ts +0 -3523
  1027. package/test/pty/pty-output-isolation.test.ts +0 -146
  1028. package/test/pty/pty-session.test.ts +0 -102
  1029. package/test/pty/pty-shell.test.ts +0 -69
  1030. package/test/question/question.test.ts +0 -464
  1031. package/test/server/global-session-list.test.ts +0 -105
  1032. package/test/server/project-init-git.test.ts +0 -137
  1033. package/test/server/rate-limit.test.ts +0 -66
  1034. package/test/server/session-actions.test.ts +0 -49
  1035. package/test/server/session-list.test.ts +0 -110
  1036. package/test/server/session-messages.test.ts +0 -220
  1037. package/test/server/session-prompt-busy.test.ts +0 -146
  1038. package/test/server/session-prompt-heartbeat.test.ts +0 -131
  1039. package/test/server/session-select.test.ts +0 -100
  1040. package/test/server/session-task-route.test.ts +0 -165
  1041. package/test/server/summarize-route-main-slice.test.ts +0 -99
  1042. package/test/server/trace-attributes.test.ts +0 -76
  1043. package/test/server/workflows-route.test.ts +0 -363
  1044. package/test/session/bootstrap-skip-system.test.ts +0 -121
  1045. package/test/session/boundary.test.ts +0 -33
  1046. package/test/session/budgeted-read.test.ts +0 -74
  1047. package/test/session/checkpoint-align.test.ts +0 -58
  1048. package/test/session/checkpoint-boundary.test.ts +0 -186
  1049. package/test/session/checkpoint-child-session.test.ts +0 -509
  1050. package/test/session/checkpoint-context.test.ts +0 -141
  1051. package/test/session/checkpoint-drain.test.ts +0 -189
  1052. package/test/session/checkpoint-extract-titles.test.ts +0 -58
  1053. package/test/session/checkpoint-fork-mode.test.ts +0 -577
  1054. package/test/session/checkpoint-main-slice.test.ts +0 -261
  1055. package/test/session/checkpoint-paths.test.ts +0 -87
  1056. package/test/session/checkpoint-permission.test.ts +0 -136
  1057. package/test/session/checkpoint-progress-reconcile.test.ts +0 -219
  1058. package/test/session/checkpoint-rebuild-unify.test.ts +0 -158
  1059. package/test/session/checkpoint-rebuild-v3.test.ts +0 -259
  1060. package/test/session/checkpoint-render-verify.test.ts +0 -512
  1061. package/test/session/checkpoint-retry.test.ts +0 -150
  1062. package/test/session/checkpoint-splitover-integration.test.ts +0 -533
  1063. package/test/session/checkpoint-templates.test.ts +0 -51
  1064. package/test/session/checkpoint-thresholds.test.ts +0 -120
  1065. package/test/session/checkpoint-validator.test.ts +0 -189
  1066. package/test/session/classify-integration.test.ts +0 -476
  1067. package/test/session/classify.test.ts +0 -390
  1068. package/test/session/codex-import.test.ts +0 -331
  1069. package/test/session/compaction-agent-scope.test.ts +0 -209
  1070. package/test/session/context-inheritance.test.ts +0 -46
  1071. package/test/session/external-import.test.ts +0 -17
  1072. package/test/session/fork-prefix-invariant.test.ts +0 -116
  1073. package/test/session/goal.test.ts +0 -106
  1074. package/test/session/instruction.test.ts +0 -388
  1075. package/test/session/invalid-output-continuation.test.ts +0 -150
  1076. package/test/session/last-message-info.test.ts +0 -47
  1077. package/test/session/length-tool-safety.test.ts +0 -125
  1078. package/test/session/llm-request-prefix.test.ts +0 -197
  1079. package/test/session/llm-retry.test.ts +0 -59
  1080. package/test/session/llm-system-prompt.test.ts +0 -479
  1081. package/test/session/llm.test.ts +0 -1268
  1082. package/test/session/main-lifecycle.test.ts +0 -51
  1083. package/test/session/main-runloop-history-invariant.test.ts +0 -182
  1084. package/test/session/max-mode-econnreset.test.ts +0 -232
  1085. package/test/session/max-mode.test.ts +0 -54
  1086. package/test/session/message-v2-filter.test.ts +0 -197
  1087. package/test/session/message-v2.test.ts +0 -1119
  1088. package/test/session/messages-default-main.test.ts +0 -105
  1089. package/test/session/messages-pagination.test.ts +0 -888
  1090. package/test/session/overflow.test.ts +0 -576
  1091. package/test/session/processor-effect.test.ts +0 -853
  1092. package/test/session/prompt-effect.test.ts +0 -1534
  1093. package/test/session/prompt-rebuild-loop.test.ts +0 -108
  1094. package/test/session/prompt-rebuild-reset.test.ts +0 -67
  1095. package/test/session/prompt-sweep.test.ts +0 -145
  1096. package/test/session/prompt-task-gate.test.ts +0 -127
  1097. package/test/session/prompt.test.ts +0 -827
  1098. package/test/session/prune-main-slice.test.ts +0 -272
  1099. package/test/session/prune-skip-system.test.ts +0 -346
  1100. package/test/session/prune.test.ts +0 -419
  1101. package/test/session/rebuild-microcompact.test.ts +0 -318
  1102. package/test/session/recall-reminder.test.ts +0 -37
  1103. package/test/session/recent-user-msg.test.ts +0 -219
  1104. package/test/session/retry.test.ts +0 -410
  1105. package/test/session/revert-compact.test.ts +0 -639
  1106. package/test/session/run-state-tuple-key.test.ts +0 -152
  1107. package/test/session/session-create-registers-main.test.ts +0 -70
  1108. package/test/session/session.test.ts +0 -181
  1109. package/test/session/snapshot-tool-race.test.ts +0 -301
  1110. package/test/session/structured-output-integration.test.ts +0 -264
  1111. package/test/session/structured-output-retry.test.ts +0 -127
  1112. package/test/session/structured-output.test.ts +0 -397
  1113. package/test/session/summary-main-slice.test.ts +0 -170
  1114. package/test/session/system.test.ts +0 -72
  1115. package/test/session/text-loop-detection.test.ts +0 -185
  1116. package/test/session/text-loop-integration.test.ts +0 -448
  1117. package/test/session/text-ngram-detection.test.ts +0 -169
  1118. package/test/session/trajectory.test.ts +0 -236
  1119. package/test/share/share-next.test.ts +0 -332
  1120. package/test/shell/shell.test.ts +0 -73
  1121. package/test/skill/compose-review.test.ts +0 -174
  1122. package/test/skill/discovery.test.ts +0 -116
  1123. package/test/skill/skill.test.ts +0 -466
  1124. package/test/snapshot/snapshot.test.ts +0 -1531
  1125. package/test/storage/db.test.ts +0 -16
  1126. package/test/storage/json-migration.test.ts +0 -831
  1127. package/test/storage/storage.test.ts +0 -293
  1128. package/test/sync/index.test.ts +0 -237
  1129. package/test/task/gate-state.test.ts +0 -66
  1130. package/test/task/gate.test.ts +0 -167
  1131. package/test/task/registry.test.ts +0 -171
  1132. package/test/task/state-machine.test.ts +0 -292
  1133. package/test/team/migrate-to-inbox.test.ts +0 -124
  1134. package/test/team/team.test.ts +0 -75
  1135. package/test/tool/__snapshots__/tool.test.ts.snap +0 -9
  1136. package/test/tool/actor-cancel.test.ts +0 -211
  1137. package/test/tool/actor-recover.test.ts +0 -50
  1138. package/test/tool/actor-send.test.ts +0 -200
  1139. package/test/tool/actor-status.test.ts +0 -296
  1140. package/test/tool/actor-wait.test.ts +0 -193
  1141. package/test/tool/actor.shell.test.ts +0 -266
  1142. package/test/tool/actor.test.ts +0 -753
  1143. package/test/tool/apply_patch.test.ts +0 -626
  1144. package/test/tool/bash.test.ts +0 -1232
  1145. package/test/tool/bash_token_efficient_pipeline.test.ts +0 -329
  1146. package/test/tool/describe-workflow.test.ts +0 -12
  1147. package/test/tool/edit.test.ts +0 -730
  1148. package/test/tool/external-directory.test.ts +0 -207
  1149. package/test/tool/fixtures/large-image.png +0 -0
  1150. package/test/tool/fixtures/models-api.json +0 -65179
  1151. package/test/tool/glob.test.ts +0 -81
  1152. package/test/tool/grep.test.ts +0 -114
  1153. package/test/tool/history.test.ts +0 -144
  1154. package/test/tool/invocation-style.test.ts +0 -30
  1155. package/test/tool/memory-edit-ask-skip.test.ts +0 -62
  1156. package/test/tool/memory-path-guard.test.ts +0 -594
  1157. package/test/tool/memory.test.ts +0 -71
  1158. package/test/tool/question.test.ts +0 -167
  1159. package/test/tool/read.test.ts +0 -483
  1160. package/test/tool/recoverable.test.ts +0 -36
  1161. package/test/tool/registry-invocation-style.test.ts +0 -121
  1162. package/test/tool/registry.test.ts +0 -164
  1163. package/test/tool/shell-tokenize.test.ts +0 -309
  1164. package/test/tool/shell-wrap-missing-script.test.ts +0 -128
  1165. package/test/tool/shell-wrap.test.ts +0 -345
  1166. package/test/tool/skill.test.ts +0 -99
  1167. package/test/tool/task-recover.test.ts +0 -36
  1168. package/test/tool/task.shell.test.ts +0 -234
  1169. package/test/tool/task.test.ts +0 -296
  1170. package/test/tool/tool-def-shell-shape.test.ts +0 -23
  1171. package/test/tool/tool-define.test.ts +0 -59
  1172. package/test/tool/tool-validation-error.test.ts +0 -25
  1173. package/test/tool/truncation.test.ts +0 -253
  1174. package/test/tool/webfetch.test.ts +0 -103
  1175. package/test/tool/whitelist.test.ts +0 -377
  1176. package/test/tool/write.test.ts +0 -244
  1177. package/test/util/data-url.test.ts +0 -14
  1178. package/test/util/effect-zod.test.ts +0 -869
  1179. package/test/util/env-info.test.ts +0 -26
  1180. package/test/util/error.test.ts +0 -38
  1181. package/test/util/filesystem.test.ts +0 -656
  1182. package/test/util/format.test.ts +0 -59
  1183. package/test/util/glob.test.ts +0 -164
  1184. package/test/util/iife.test.ts +0 -36
  1185. package/test/util/lazy.test.ts +0 -50
  1186. package/test/util/lock.test.ts +0 -72
  1187. package/test/util/log.test.ts +0 -69
  1188. package/test/util/module.test.ts +0 -59
  1189. package/test/util/process.test.ts +0 -128
  1190. package/test/util/queue.test.ts +0 -64
  1191. package/test/util/ssrf.test.ts +0 -115
  1192. package/test/util/timeout.test.ts +0 -21
  1193. package/test/util/tool-compat.test.ts +0 -189
  1194. package/test/util/which.test.ts +0 -100
  1195. package/test/util/wildcard.test.ts +0 -90
  1196. package/test/workflow/builtin.test.ts +0 -36
  1197. package/test/workflow/compose.test.ts +0 -668
  1198. package/test/workflow/deep-research-cluster.test.ts +0 -47
  1199. package/test/workflow/lib.ts +0 -243
  1200. package/test/workflow/meta.test.ts +0 -142
  1201. package/test/workflow/model-routing.test.ts +0 -68
  1202. package/test/workflow/persistence.test.ts +0 -229
  1203. package/test/workflow/resolve.test.ts +0 -37
  1204. package/test/workflow/runtime-nested.test.ts +0 -419
  1205. package/test/workflow/runtime-worktree.test.ts +0 -261
  1206. package/test/workflow/runtime.test.ts +0 -1142
  1207. package/test/workflow/sandbox.test.ts +0 -259
  1208. package/test/workflow/tool.test.ts +0 -487
  1209. package/test/workflow/verify-wow.test.ts +0 -144
  1210. package/test/workflow/workspace.test.ts +0 -88
  1211. package/test/workspace/workspace-restore.test.ts +0 -281
  1212. package/test/worktree/index.test.ts +0 -30
  1213. package/tsconfig.json +0 -24
@@ -1,3087 +0,0 @@
1
- import {
2
- batch,
3
- createContext,
4
- createEffect,
5
- createMemo,
6
- createSignal,
7
- For,
8
- Match,
9
- on,
10
- onCleanup,
11
- Show,
12
- Switch,
13
- useContext,
14
- } from "solid-js"
15
- import { Dynamic } from "solid-js/web"
16
- import path from "path"
17
- import { useCurrentAgentID, useRoute, useRouteData } from "@tui/context/route"
18
- import { useProject } from "@tui/context/project"
19
- import { useSync } from "@tui/context/sync"
20
- import { useEvent } from "@tui/context/event"
21
- import { SplitBorder } from "@tui/component/border"
22
- import { Spinner } from "@tui/component/spinner"
23
- import { selectedForeground, useTheme } from "@tui/context/theme"
24
- import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA, MouseEvent } from "@opentui/core"
25
- import { Prompt, type PromptRef } from "@tui/component/prompt"
26
- import type {
27
- AssistantMessage,
28
- Part,
29
- Provider,
30
- ToolPart,
31
- UserMessage,
32
- TextPart,
33
- ReasoningPart,
34
- } from "@opendash-ai/sdk/v2"
35
- import { useLocal } from "@tui/context/local"
36
- import { Locale } from "@/util"
37
- import type { Tool } from "@/tool"
38
- import type { ReadTool } from "@/tool/read"
39
- import type { WriteTool } from "@/tool/write"
40
- import { BashTool } from "@/tool/bash"
41
- import type { GlobTool } from "@/tool/glob"
42
- import type { GrepTool } from "@/tool/grep"
43
- import type { EditTool } from "@/tool/edit"
44
- import type { ApplyPatchTool } from "@/tool/apply_patch"
45
- import type { WebFetchTool } from "@/tool/webfetch"
46
- import type { CodeSearchTool } from "@/tool/codesearch"
47
- import type { WebSearchTool } from "@/tool/websearch"
48
- import type { ActorTool } from "@/tool/actor"
49
- import type { TaskTool } from "@/tool/task"
50
- import type { QuestionTool } from "@/tool/question"
51
- import type { SkillTool } from "@/tool/skill"
52
- import type { WorkflowTool } from "@/tool/workflow"
53
- import { useKeyboard, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
54
- import { useSDK } from "@tui/context/sdk"
55
- import { useCommandDialog } from "@tui/component/dialog-command"
56
- import { useLanguage } from "@tui/context/language"
57
- import type { DialogContext } from "@tui/ui/dialog"
58
- import { useKeybind } from "@tui/context/keybind"
59
- import { useDialog } from "../../ui/dialog"
60
- import { DialogMessage } from "./dialog-message"
61
- import type { PromptInfo } from "../../component/prompt/history"
62
- import { DialogConfirm } from "@tui/ui/dialog-confirm"
63
- import { DialogTimeline } from "./dialog-timeline"
64
- import { DialogForkFromTimeline } from "./dialog-fork-from-timeline"
65
- import { DialogSessionRename } from "../../component/dialog-session-rename"
66
- import { Sidebar } from "./sidebar"
67
- import { WorkflowTree } from "@tui/component/workflow-tree"
68
- import { SubagentFooter } from "./subagent-footer.tsx"
69
- import { DialogSubagent } from "./dialog-subagent.tsx"
70
- import { Flag } from "@/flag/flag"
71
- import { LANGUAGE_EXTENSIONS } from "@/lsp/language"
72
- import parsers from "../../../../../../parsers-config.ts"
73
- import * as Clipboard from "../../util/clipboard"
74
- import { Toast, useToast } from "../../ui/toast"
75
- import { useKV } from "../../context/kv.tsx"
76
- import * as Editor from "../../util/editor"
77
- import stripAnsi from "strip-ansi"
78
- import { usePromptRef } from "../../context/prompt"
79
- import { useExit } from "../../context/exit"
80
- import { Filesystem } from "@/util"
81
- import { Global } from "@/global"
82
- import { PermissionPrompt } from "./permission"
83
- import { QuestionPrompt } from "./question"
84
- import { DialogExportOptions } from "../../ui/dialog-export-options"
85
- import * as Model from "../../util/model"
86
- import { formatTranscript } from "../../util/transcript"
87
- import { UI } from "@/cli/ui.ts"
88
- import { useTuiConfig } from "../../context/tui-config"
89
- import { getScrollAcceleration } from "../../util/scroll"
90
- import { nextThinkingMode, reasoningSummary, useThinkingMode, type ThinkingMode } from "../../context/thinking"
91
- import { TuiPluginRuntime } from "../../plugin"
92
- import { DialogGoUpsell } from "../../component/dialog-go-upsell"
93
- import { DialogTokenPlan } from "../../component/dialog-token-plan"
94
- import { SessionRetry } from "@/session/retry"
95
- import { getRevertDiffFiles } from "../../util/revert-diff"
96
- import { getAgentBrandColor } from "../../component/prompt/shimmer"
97
-
98
- addDefaultParsers(parsers.parsers)
99
-
100
- const GO_UPSELL_LAST_SEEN_AT = "go_upsell_last_seen_at"
101
- const GO_UPSELL_DONT_SHOW = "go_upsell_dont_show"
102
- const GO_UPSELL_WINDOW = 86_400_000 // 24 hrs
103
-
104
- const QUEUE_TOKEN_PLAN_LAST_SEEN_AT = "queue_token_plan_last_seen_at"
105
- const QUEUE_TOKEN_PLAN_WINDOW = 86_400_000 // 24 hrs
106
-
107
- const context = createContext<{
108
- width: number
109
- sessionID: string
110
- conceal: () => boolean
111
- thinkingMode: () => ThinkingMode
112
- showThinking: () => boolean
113
- showTimestamps: () => boolean
114
- showDetails: () => boolean
115
- showGenericToolOutput: () => boolean
116
- diffWrapMode: () => "word" | "none"
117
- providers: () => ReadonlyMap<string, Provider>
118
- sync: ReturnType<typeof useSync>
119
- tui: ReturnType<typeof useTuiConfig>
120
- }>()
121
-
122
- function use() {
123
- const ctx = useContext(context)
124
- if (!ctx) throw new Error("useContext must be used within a Session component")
125
- return ctx
126
- }
127
-
128
- export function Session() {
129
- const route = useRouteData("session")
130
- const fullRoute = useRoute()
131
- const navigate = fullRoute.navigate
132
- const sync = useSync()
133
- const event = useEvent()
134
- const project = useProject()
135
- const tuiConfig = useTuiConfig()
136
- const kv = useKV()
137
- const { theme } = useTheme()
138
- const promptRef = usePromptRef()
139
- const session = createMemo(() => sync.session.get(route.sessionID))
140
- const currentAgentID = useCurrentAgentID()
141
- const actors = createMemo(() => sync.data.actor[route.sessionID] ?? [])
142
- const messages = createMemo(() => sync.data.message[route.sessionID]?.[currentAgentID()] ?? [])
143
- const permissions = createMemo(() => sync.data.permission[route.sessionID] ?? [])
144
- const questions = createMemo(() => sync.data.question[route.sessionID] ?? [])
145
- const visible = createMemo(
146
- () =>
147
- !session()?.parentID &&
148
- currentAgentID() === "main" &&
149
- permissions().length === 0 &&
150
- questions().length === 0,
151
- )
152
- const disabled = createMemo(() => permissions().length > 0 || questions().length > 0)
153
-
154
- const pending = createMemo(() => {
155
- return messages().findLast((x) => x.role === "assistant" && !x.time.completed)?.id
156
- })
157
-
158
- const lastAssistant = createMemo(() => {
159
- return messages().findLast((x) => x.role === "assistant")
160
- })
161
-
162
- const dimensions = useTerminalDimensions()
163
- const [sidebar, setSidebar] = kv.signal<"auto" | "hide">("sidebar", "auto")
164
- const [sidebarOpen, setSidebarOpen] = createSignal(false)
165
- const [conceal, setConceal] = createSignal(true)
166
- const thinking = useThinkingMode()
167
- const thinkingMode = thinking.mode
168
- const showThinking = createMemo(() => true)
169
- const [timestamps, setTimestamps] = kv.signal<"hide" | "show">("timestamps", "hide")
170
- const [showDetails, setShowDetails] = kv.signal("tool_details_visibility", true)
171
- const [showAssistantMetadata, _setShowAssistantMetadata] = kv.signal("assistant_metadata_visibility", true)
172
- const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", false)
173
- const [scrolling, setScrolling] = createSignal(false)
174
- let scrollHideTimer: ReturnType<typeof setTimeout> | undefined
175
- const scrollbarVisible = createMemo(() => showScrollbar() || scrolling())
176
- const onWheel = (evt: MouseEvent) => {
177
- if (evt.type !== "scroll") return
178
- setScrolling(true)
179
- if (scrollHideTimer) clearTimeout(scrollHideTimer)
180
- scrollHideTimer = setTimeout(() => setScrolling(false), 1000)
181
- }
182
- onCleanup(() => {
183
- if (scrollHideTimer) clearTimeout(scrollHideTimer)
184
- })
185
- const [diffWrapMode] = kv.signal<"word" | "none">("diff_wrap_mode", "word")
186
- const [_animationsEnabled, _setAnimationsEnabled] = kv.signal("animations_enabled", true)
187
- const [showGenericToolOutput, setShowGenericToolOutput] = kv.signal("generic_tool_output_visibility", false)
188
-
189
- // The workflow run shown as a FULL-SCREEN page (replacing the message stream),
190
- // mirroring how agentID renders a subagent's conversation. Driven by the route so
191
- // it's a real navigable view, not a side panel.
192
- const workflowRunID = createMemo(() => route.workflowRunID)
193
- const fromWorkflowRunID = createMemo(() => route.fromWorkflowRunID)
194
-
195
- const wide = createMemo(() => dimensions().width > 120)
196
- const sidebarVisible = createMemo(() => {
197
- if (session()?.parentID) return false
198
- if (currentAgentID() !== "main") return false
199
- if (sidebarOpen()) return true
200
- if (sidebar() === "auto" && wide()) return true
201
- return false
202
- })
203
- const showTimestamps = createMemo(() => timestamps() === "show")
204
- const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4)
205
- const providers = createMemo(() => Model.index(sync.data.provider))
206
-
207
- const scrollAcceleration = createMemo(() => getScrollAcceleration(tuiConfig))
208
- const toast = useToast()
209
- const sdk = useSDK()
210
-
211
- createEffect(async () => {
212
- const previousWorkspace = project.workspace.current()
213
- const result = await sdk.client.session.get({ sessionID: route.sessionID }, { throwOnError: true })
214
- if (!result.data) {
215
- toast.show({
216
- message: `Session not found: ${route.sessionID}`,
217
- variant: "error",
218
- })
219
- navigate({ type: "home" })
220
- return
221
- }
222
-
223
- if (result.data.workspaceID !== previousWorkspace) {
224
- project.workspace.set(result.data.workspaceID)
225
-
226
- // Sync all the data for this workspace. Note that this
227
- // workspace may not exist anymore which is why this is not
228
- // fatal. If it doesn't we still want to show the session
229
- // (which will be non-interactive)
230
- try {
231
- await sync.bootstrap({ fatal: false })
232
- } catch (e) {}
233
- }
234
- await sync.session.sync(route.sessionID)
235
- if (scroll) scroll.scrollBy(100_000)
236
- })
237
-
238
- let lastSwitch: string | undefined = undefined
239
- event.on("message.part.updated", (evt) => {
240
- const part = evt.properties.part
241
- if (part.type !== "tool") return
242
- if (part.sessionID !== route.sessionID) return
243
- if (part.state.status !== "completed") return
244
- if (part.id === lastSwitch) return
245
-
246
- if (part.tool === "plan_exit" && part.state.metadata?.switched) {
247
- local.agent.set("build")
248
- lastSwitch = part.id
249
- } else if (part.tool === "plan_enter") {
250
- local.agent.set("plan")
251
- lastSwitch = part.id
252
- }
253
- })
254
-
255
- let seeded = false
256
- let scroll: ScrollBoxRenderable
257
- let prompt: PromptRef | undefined
258
- const bind = (r: PromptRef | undefined) => {
259
- prompt = r
260
- promptRef.set(r)
261
- if (seeded || !route.prompt || !r) return
262
- seeded = true
263
- r.set(route.prompt)
264
- }
265
- const keybind = useKeybind()
266
- const dialog = useDialog()
267
- const renderer = useRenderer()
268
-
269
- event.on("session.status", (evt) => {
270
- if (evt.properties.sessionID !== route.sessionID) return
271
- if (evt.properties.status.type !== "retry") return
272
- if (evt.properties.status.message !== SessionRetry.GO_UPSELL_MESSAGE) return
273
- if (dialog.stack.length > 0) return
274
-
275
- const seen = kv.get(GO_UPSELL_LAST_SEEN_AT)
276
- if (typeof seen === "number" && Date.now() - seen < GO_UPSELL_WINDOW) return
277
-
278
- if (kv.get(GO_UPSELL_DONT_SHOW)) return
279
-
280
- void DialogGoUpsell.show(dialog).then((dontShowAgain) => {
281
- if (dontShowAgain) kv.set(GO_UPSELL_DONT_SHOW, true)
282
- kv.set(GO_UPSELL_LAST_SEEN_AT, Date.now())
283
- })
284
- })
285
-
286
- // Allow exit when in child session (prompt is hidden)
287
- const exit = useExit()
288
-
289
- createEffect(() => {
290
- const title = Locale.truncate(session()?.title ?? "", 50)
291
- const pad = (text: string) => text.padEnd(10, " ")
292
- const weak = (text: string) => UI.Style.TEXT_DIM + pad(text) + UI.Style.TEXT_NORMAL
293
- const logo = UI.logo(" ").split(/\r?\n/)
294
- return exit.message.set(
295
- [
296
- ...logo,
297
- ``,
298
- ` ${weak("Session")}${UI.Style.TEXT_NORMAL_BOLD}${title}${UI.Style.TEXT_NORMAL}`,
299
- ` ${weak("Continue")}${UI.Style.TEXT_NORMAL_BOLD}opendash -s ${session()?.id}${UI.Style.TEXT_NORMAL}`,
300
- ``,
301
- ].join("\n"),
302
- )
303
- })
304
-
305
- useKeyboard((evt) => {
306
- if (!session()?.parentID && currentAgentID() === "main") return
307
- if (keybind.match("app_exit", evt)) {
308
- const status = sync.data.session_status?.[route.sessionID]
309
- if (status && status.type !== "idle") {
310
- void sdk.client.session.abort({ sessionID: route.sessionID }).catch(() => {})
311
- return
312
- }
313
- void exit()
314
- }
315
- })
316
-
317
- // Helper: Find next visible message boundary in direction
318
- const findNextVisibleMessage = (direction: "next" | "prev"): string | null => {
319
- const children = scroll.getChildren()
320
- const messagesList = messages()
321
- const scrollTop = scroll.y
322
-
323
- // Get visible messages sorted by position, filtering for valid non-synthetic, non-ignored content
324
- const visibleMessages = children
325
- .filter((c) => {
326
- if (!c.id) return false
327
- const message = messagesList.find((m) => m.id === c.id)
328
- if (!message) return false
329
-
330
- // Check if message has valid non-synthetic, non-ignored text parts
331
- const parts = sync.data.part[message.id]
332
- if (!parts || !Array.isArray(parts)) return false
333
-
334
- return parts.some((part) => part && part.type === "text" && !part.synthetic && !part.ignored)
335
- })
336
- .sort((a, b) => a.y - b.y)
337
-
338
- if (visibleMessages.length === 0) return null
339
-
340
- if (direction === "next") {
341
- // Find first message below current position
342
- return visibleMessages.find((c) => c.y > scrollTop + 10)?.id ?? null
343
- }
344
- // Find last message above current position
345
- return [...visibleMessages].reverse().find((c) => c.y < scrollTop - 10)?.id ?? null
346
- }
347
-
348
- // Helper: Scroll to message in direction or fallback to page scroll
349
- const scrollToMessage = (direction: "next" | "prev", dialog: ReturnType<typeof useDialog>) => {
350
- const targetID = findNextVisibleMessage(direction)
351
-
352
- if (!targetID) {
353
- scroll.scrollBy(direction === "next" ? scroll.height : -scroll.height)
354
- dialog.clear()
355
- return
356
- }
357
-
358
- const child = scroll.getChildren().find((c) => c.id === targetID)
359
- if (child) scroll.scrollBy(child.y - scroll.y - 1)
360
- dialog.clear()
361
- }
362
-
363
- function toBottom() {
364
- setTimeout(() => {
365
- if (!scroll || scroll.isDestroyed) return
366
- scroll.scrollTo(scroll.scrollHeight)
367
- }, 50)
368
- }
369
-
370
- const local = useLocal()
371
-
372
- // Free "mimo-auto" channel: on a rate-limit / queue ("too many requests"),
373
- // nudge the user toward a Token Plan — at most once per 24h.
374
- event.on("session.status", (evt) => {
375
- if (evt.properties.sessionID !== route.sessionID) return
376
- if (evt.properties.status.type !== "retry") return
377
- if (!SessionRetry.isRateLimitMessage(evt.properties.status.message)) return
378
- const model = local.model.current()
379
- if (!model || model.providerID !== "mimo" || model.modelID !== "mimo-auto") return
380
- if (dialog.stack.length > 0) return
381
-
382
- const seen = kv.get(QUEUE_TOKEN_PLAN_LAST_SEEN_AT)
383
- if (typeof seen === "number" && Date.now() - seen < QUEUE_TOKEN_PLAN_WINDOW) return
384
-
385
- // Record the 24h cooldown only after the user dismisses, so a show() that
386
- // fails (or never reaches the user) doesn't silently burn the whole day.
387
- void DialogTokenPlan.show(dialog).then(() => {
388
- kv.set(QUEUE_TOKEN_PLAN_LAST_SEEN_AT, Date.now())
389
- })
390
- })
391
-
392
- function moveFirstChild() {
393
- const list = actors().filter((a) => a.mode === "subagent")
394
- if (list.length === 0) {
395
- dialog.replace(() => <DialogSubagent sessionID={route.sessionID} />)
396
- return
397
- }
398
- if (fullRoute.data.type !== "session") return
399
- navigate({ ...fullRoute.data, agentID: list[0].actor_id, fromWorkflowRunID: undefined })
400
- }
401
-
402
- function moveChild(direction: 1 | -1) {
403
- const list = actors().filter((a) => a.mode === "subagent")
404
- if (list.length === 0) return
405
- if (fullRoute.data.type !== "session") return
406
- const cur = currentAgentID()
407
- const idx = list.findIndex((a) => a.actor_id === cur)
408
- const next =
409
- idx === -1
410
- ? direction === 1
411
- ? 0
412
- : list.length - 1
413
- : (idx + direction + list.length) % list.length
414
- navigate({ ...fullRoute.data, agentID: list[next].actor_id, fromWorkflowRunID: undefined })
415
- }
416
-
417
- const command = useCommandDialog()
418
- const t = useLanguage().t
419
- command.register(() => [
420
- {
421
- title: t(session()?.share?.url ? "tui.command.session.share.copy_link" : "tui.command.session.share.title"),
422
- value: "session.share",
423
- suggested: route.type === "session",
424
- keybind: "session_share",
425
- category: "session",
426
- enabled: sync.data.config.share !== "disabled",
427
- slash: {
428
- name: "share",
429
- },
430
- onSelect: async (dialog) => {
431
- const copy = (url: string) =>
432
- Clipboard.copy(url)
433
- .then(() => toast.show({ message: "Share URL copied to clipboard!", variant: "success" }))
434
- .catch(() => toast.show({ message: "Failed to copy URL to clipboard", variant: "error" }))
435
- const url = session()?.share?.url
436
- if (url) {
437
- await copy(url)
438
- dialog.clear()
439
- return
440
- }
441
- if (!kv.get("share_consent", false)) {
442
- const ok = await DialogConfirm.show(dialog, "Share Session", "Are you sure you want to share it?")
443
- if (ok !== true) return
444
- kv.set("share_consent", true)
445
- }
446
- await sdk.client.session
447
- .share({
448
- sessionID: route.sessionID,
449
- })
450
- .then((res) => copy(res.data!.share!.url))
451
- .catch((error) => {
452
- toast.show({
453
- message: error instanceof Error ? error.message : "Failed to share session",
454
- variant: "error",
455
- })
456
- })
457
- dialog.clear()
458
- },
459
- },
460
- {
461
- title: t("tui.command.session.rename.title"),
462
- value: "session.rename",
463
- keybind: "session_rename",
464
- category: "session",
465
- slash: {
466
- name: "rename",
467
- },
468
- onSelect: (dialog) => {
469
- dialog.replace(() => <DialogSessionRename session={route.sessionID} />)
470
- },
471
- },
472
- {
473
- title: t("tui.command.session.timeline.title"),
474
- value: "session.timeline",
475
- keybind: "session_timeline",
476
- category: "session",
477
- slash: {
478
- name: "timeline",
479
- },
480
- onSelect: (dialog) => {
481
- dialog.replace(() => (
482
- <DialogTimeline
483
- onMove={(messageID) => {
484
- const child = scroll.getChildren().find((child) => {
485
- return child.id === messageID
486
- })
487
- if (child) scroll.scrollBy(child.y - scroll.y - 1)
488
- }}
489
- sessionID={route.sessionID}
490
- setPrompt={(promptInfo) => prompt?.set(promptInfo)}
491
- />
492
- ))
493
- },
494
- },
495
- {
496
- title: t("tui.command.session.fork.title"),
497
- value: "session.fork",
498
- keybind: "session_fork",
499
- category: "session",
500
- slash: {
501
- name: "fork",
502
- },
503
- onSelect: (dialog) => {
504
- dialog.replace(() => (
505
- <DialogForkFromTimeline
506
- onMove={(messageID) => {
507
- if (!messageID) return
508
- const child = scroll.getChildren().find((child) => {
509
- return child.id === messageID
510
- })
511
- if (child) scroll.scrollBy(child.y - scroll.y - 1)
512
- }}
513
- sessionID={route.sessionID}
514
- />
515
- ))
516
- },
517
- },
518
- {
519
- title: t("tui.command.session.compact.title"),
520
- value: "session.compact",
521
- keybind: "session_compact",
522
- category: "session",
523
- slash: {
524
- name: "compact",
525
- aliases: ["summarize"],
526
- },
527
- onSelect: (dialog) => {
528
- const selectedModel = local.model.current()
529
- if (!selectedModel) {
530
- toast.show({
531
- variant: "warning",
532
- message: "Connect a provider to summarize this session",
533
- duration: 3000,
534
- })
535
- return
536
- }
537
- void sdk.client.session.summarize({
538
- sessionID: route.sessionID,
539
- modelID: selectedModel.modelID,
540
- providerID: selectedModel.providerID,
541
- })
542
- dialog.clear()
543
- },
544
- },
545
- {
546
- title: t("tui.command.session.unshare.title"),
547
- value: "session.unshare",
548
- keybind: "session_unshare",
549
- category: "session",
550
- enabled: !!session()?.share?.url,
551
- slash: {
552
- name: "unshare",
553
- },
554
- onSelect: async (dialog) => {
555
- await sdk.client.session
556
- .unshare({
557
- sessionID: route.sessionID,
558
- })
559
- .then(() => toast.show({ message: "Session unshared successfully", variant: "success" }))
560
- .catch((error) => {
561
- toast.show({
562
- message: error instanceof Error ? error.message : "Failed to unshare session",
563
- variant: "error",
564
- })
565
- })
566
- dialog.clear()
567
- },
568
- },
569
- {
570
- title: t("tui.command.session.undo.title"),
571
- value: "session.undo",
572
- keybind: "messages_undo",
573
- category: "session",
574
- slash: {
575
- name: "undo",
576
- },
577
- onSelect: async (dialog) => {
578
- const status = sync.data.session_status?.[route.sessionID]
579
- if (status?.type !== "idle") await sdk.client.session.abort({ sessionID: route.sessionID }).catch(() => {})
580
- const revert = session()?.revert?.messageID
581
- const message = messages().findLast((x) => (!revert || x.id < revert) && x.role === "user")
582
- if (!message) return
583
- void sdk.client.session
584
- .revert({
585
- sessionID: route.sessionID,
586
- messageID: message.id,
587
- })
588
- .then(() => {
589
- toBottom()
590
- })
591
- const parts = sync.data.part[message.id]
592
- prompt?.set(
593
- parts.reduce(
594
- (agg, part) => {
595
- if (part.type === "text") {
596
- if (!part.synthetic) agg.input += part.text
597
- }
598
- if (part.type === "file") agg.parts.push(part)
599
- return agg
600
- },
601
- { input: "", parts: [] as PromptInfo["parts"] },
602
- ),
603
- )
604
- dialog.clear()
605
- },
606
- },
607
- {
608
- title: t("tui.command.session.redo.title"),
609
- value: "session.redo",
610
- keybind: "messages_redo",
611
- category: "session",
612
- enabled: !!session()?.revert?.messageID,
613
- slash: {
614
- name: "redo",
615
- },
616
- onSelect: (dialog) => {
617
- dialog.clear()
618
- const messageID = session()?.revert?.messageID
619
- if (!messageID) return
620
- const message = messages().find((x) => x.role === "user" && x.id > messageID)
621
- if (!message) {
622
- void sdk.client.session.unrevert({
623
- sessionID: route.sessionID,
624
- })
625
- prompt?.set({ input: "", parts: [] })
626
- return
627
- }
628
- void sdk.client.session.revert({
629
- sessionID: route.sessionID,
630
- messageID: message.id,
631
- })
632
- },
633
- },
634
- {
635
- title: t(sidebarVisible() ? "tui.command.session.sidebar.hide" : "tui.command.session.sidebar.show"),
636
- value: "session.sidebar.toggle",
637
- keybind: "sidebar_toggle",
638
- slash: {
639
- name: "sidebar",
640
- },
641
- category: "session",
642
- onSelect: (dialog) => {
643
- batch(() => {
644
- const isVisible = sidebarVisible()
645
- setSidebar(() => (isVisible ? "hide" : "auto"))
646
- setSidebarOpen(!isVisible)
647
- })
648
- dialog.clear()
649
- },
650
- },
651
- {
652
- title: t(conceal() ? "tui.command.session.conceal.disable" : "tui.command.session.conceal.enable"),
653
- value: "session.toggle.conceal",
654
- keybind: "messages_toggle_conceal",
655
- category: "session",
656
- onSelect: (dialog) => {
657
- setConceal((prev) => !prev)
658
- dialog.clear()
659
- },
660
- },
661
- {
662
- title: t(showTimestamps() ? "tui.command.session.timestamps.hide" : "tui.command.session.timestamps.show"),
663
- value: "session.toggle.timestamps",
664
- category: "session",
665
- slash: {
666
- name: "timestamps",
667
- aliases: ["toggle-timestamps"],
668
- },
669
- onSelect: (dialog) => {
670
- setTimestamps((prev) => (prev === "show" ? "hide" : "show"))
671
- dialog.clear()
672
- },
673
- },
674
- {
675
- title: t(
676
- nextThinkingMode(thinkingMode()) === "hide"
677
- ? "tui.command.session.thinking.collapse"
678
- : "tui.command.session.thinking.expand",
679
- ),
680
- value: "session.toggle.thinking",
681
- keybind: "display_thinking",
682
- category: "session",
683
- slash: {
684
- name: "thinking",
685
- aliases: ["toggle-thinking"],
686
- },
687
- onSelect: (dialog) => {
688
- thinking.set(nextThinkingMode(thinkingMode()))
689
- dialog.clear()
690
- },
691
- },
692
- {
693
- title: t(showDetails() ? "tui.command.session.tool_details.hide" : "tui.command.session.tool_details.show"),
694
- value: "session.toggle.actions",
695
- keybind: "tool_details",
696
- category: "session",
697
- onSelect: (dialog) => {
698
- setShowDetails((prev) => !prev)
699
- dialog.clear()
700
- },
701
- },
702
- {
703
- title: t("tui.command.session.scrollbar.toggle"),
704
- value: "session.toggle.scrollbar",
705
- keybind: "scrollbar_toggle",
706
- category: "session",
707
- onSelect: (dialog) => {
708
- setShowScrollbar((prev) => !prev)
709
- dialog.clear()
710
- },
711
- },
712
- {
713
- title: t(
714
- showGenericToolOutput()
715
- ? "tui.command.session.generic_tool_output.hide"
716
- : "tui.command.session.generic_tool_output.show",
717
- ),
718
- value: "session.toggle.generic_tool_output",
719
- category: "session",
720
- onSelect: (dialog) => {
721
- setShowGenericToolOutput((prev) => !prev)
722
- dialog.clear()
723
- },
724
- },
725
- {
726
- title: t("tui.command.session.page_up.title"),
727
- value: "session.page.up",
728
- keybind: "messages_page_up",
729
- category: "session",
730
- hidden: true,
731
- onSelect: (dialog) => {
732
- scroll.scrollBy(-scroll.height / 2)
733
- dialog.clear()
734
- },
735
- },
736
- {
737
- title: t("tui.command.session.page_down.title"),
738
- value: "session.page.down",
739
- keybind: "messages_page_down",
740
- category: "session",
741
- hidden: true,
742
- onSelect: (dialog) => {
743
- scroll.scrollBy(scroll.height / 2)
744
- dialog.clear()
745
- },
746
- },
747
- {
748
- title: t("tui.command.session.line_up.title"),
749
- value: "session.line.up",
750
- keybind: "messages_line_up",
751
- category: "session",
752
- disabled: true,
753
- onSelect: (dialog) => {
754
- scroll.scrollBy(-1)
755
- dialog.clear()
756
- },
757
- },
758
- {
759
- title: t("tui.command.session.line_down.title"),
760
- value: "session.line.down",
761
- keybind: "messages_line_down",
762
- category: "session",
763
- disabled: true,
764
- onSelect: (dialog) => {
765
- scroll.scrollBy(1)
766
- dialog.clear()
767
- },
768
- },
769
- {
770
- title: t("tui.command.session.half_page_up.title"),
771
- value: "session.half.page.up",
772
- keybind: "messages_half_page_up",
773
- category: "session",
774
- hidden: true,
775
- onSelect: (dialog) => {
776
- scroll.scrollBy(-scroll.height / 4)
777
- dialog.clear()
778
- },
779
- },
780
- {
781
- title: t("tui.command.session.half_page_down.title"),
782
- value: "session.half.page.down",
783
- keybind: "messages_half_page_down",
784
- category: "session",
785
- hidden: true,
786
- onSelect: (dialog) => {
787
- scroll.scrollBy(scroll.height / 4)
788
- dialog.clear()
789
- },
790
- },
791
- {
792
- title: t("tui.command.session.first.title"),
793
- value: "session.first",
794
- keybind: "messages_first",
795
- category: "session",
796
- hidden: true,
797
- onSelect: (dialog) => {
798
- scroll.scrollTo(0)
799
- dialog.clear()
800
- },
801
- },
802
- {
803
- title: t("tui.command.session.last.title"),
804
- value: "session.last",
805
- keybind: "messages_last",
806
- category: "session",
807
- hidden: true,
808
- onSelect: (dialog) => {
809
- scroll.scrollTo(scroll.scrollHeight)
810
- dialog.clear()
811
- },
812
- },
813
- {
814
- title: t("tui.command.session.last_user.title"),
815
- value: "session.messages_last_user",
816
- keybind: "messages_last_user",
817
- category: "session",
818
- hidden: true,
819
- onSelect: () => {
820
- const msgs = messages()
821
- if (!msgs || !msgs.length) return
822
-
823
- // Find the most recent user message with non-ignored, non-synthetic text parts
824
- for (let i = msgs.length - 1; i >= 0; i--) {
825
- const message = msgs[i]
826
- if (!message || message.role !== "user") continue
827
-
828
- const parts = sync.data.part[message.id]
829
- if (!parts || !Array.isArray(parts)) continue
830
-
831
- const hasValidTextPart = parts.some(
832
- (part) => part && part.type === "text" && !part.synthetic && !part.ignored,
833
- )
834
-
835
- if (hasValidTextPart) {
836
- const child = scroll.getChildren().find((child) => {
837
- return child.id === message.id
838
- })
839
- if (child) scroll.scrollBy(child.y - scroll.y - 1)
840
- break
841
- }
842
- }
843
- },
844
- },
845
- {
846
- title: t("tui.command.session.message_next.title"),
847
- value: "session.message.next",
848
- keybind: "messages_next",
849
- category: "session",
850
- hidden: true,
851
- onSelect: (dialog) => scrollToMessage("next", dialog),
852
- },
853
- {
854
- title: t("tui.command.session.message_previous.title"),
855
- value: "session.message.previous",
856
- keybind: "messages_previous",
857
- category: "session",
858
- hidden: true,
859
- onSelect: (dialog) => scrollToMessage("prev", dialog),
860
- },
861
- {
862
- title: t("tui.command.messages.copy.title"),
863
- value: "messages.copy",
864
- keybind: "messages_copy",
865
- category: "session",
866
- onSelect: (dialog) => {
867
- const revertID = session()?.revert?.messageID
868
- const lastAssistantMessage = messages().findLast(
869
- (msg) => msg.role === "assistant" && (!revertID || msg.id < revertID),
870
- )
871
- if (!lastAssistantMessage) {
872
- toast.show({ message: "No assistant messages found", variant: "error" })
873
- dialog.clear()
874
- return
875
- }
876
-
877
- const parts = sync.data.part[lastAssistantMessage.id] ?? []
878
- const textParts = parts.filter((part) => part.type === "text")
879
- if (textParts.length === 0) {
880
- toast.show({ message: "No text parts found in last assistant message", variant: "error" })
881
- dialog.clear()
882
- return
883
- }
884
-
885
- const text = textParts
886
- .map((part) => part.text)
887
- .join("\n")
888
- .trim()
889
- if (!text) {
890
- toast.show({
891
- message: "No text content found in last assistant message",
892
- variant: "error",
893
- })
894
- dialog.clear()
895
- return
896
- }
897
-
898
- Clipboard.copy(text)
899
- .then(() => toast.show({ message: "Message copied to clipboard!", variant: "success" }))
900
- .catch(() => toast.show({ message: "Failed to copy to clipboard", variant: "error" }))
901
- dialog.clear()
902
- },
903
- },
904
- {
905
- title: t("tui.command.session.copy.title"),
906
- value: "session.copy",
907
- category: "session",
908
- slash: {
909
- name: "copy",
910
- },
911
- onSelect: async (dialog) => {
912
- try {
913
- const sessionData = session()
914
- if (!sessionData) return
915
- const sessionMessages = messages()
916
- const transcript = formatTranscript(
917
- sessionData,
918
- sessionMessages.map((msg) => ({ info: msg, parts: sync.data.part[msg.id] ?? [] })),
919
- {
920
- thinking: showThinking(),
921
- toolDetails: showDetails(),
922
- assistantMetadata: showAssistantMetadata(),
923
- providers: sync.data.provider,
924
- },
925
- )
926
- await Clipboard.copy(transcript)
927
- toast.show({ message: "Session transcript copied to clipboard!", variant: "success" })
928
- } catch {
929
- toast.show({ message: "Failed to copy session transcript", variant: "error" })
930
- }
931
- dialog.clear()
932
- },
933
- },
934
- {
935
- title: t("tui.command.session.export.title"),
936
- value: "session.export",
937
- keybind: "session_export",
938
- category: "session",
939
- slash: {
940
- name: "export",
941
- },
942
- onSelect: async (dialog) => {
943
- try {
944
- const sessionData = session()
945
- if (!sessionData) return
946
- const sessionMessages = messages()
947
-
948
- const defaultFilename = `session-${sessionData.id.slice(0, 8)}.md`
949
-
950
- const options = await DialogExportOptions.show(
951
- dialog,
952
- defaultFilename,
953
- showThinking(),
954
- showDetails(),
955
- showAssistantMetadata(),
956
- false,
957
- )
958
-
959
- if (options === null) return
960
-
961
- const transcript = formatTranscript(
962
- sessionData,
963
- sessionMessages.map((msg) => ({ info: msg, parts: sync.data.part[msg.id] ?? [] })),
964
- {
965
- thinking: options.thinking,
966
- toolDetails: options.toolDetails,
967
- assistantMetadata: options.assistantMetadata,
968
- providers: sync.data.provider,
969
- },
970
- )
971
-
972
- if (options.openWithoutSaving) {
973
- // Just open in editor without saving
974
- await Editor.open({ value: transcript, renderer })
975
- } else {
976
- const exportDir = process.cwd()
977
- const filename = options.filename.trim()
978
- const filepath = path.join(exportDir, filename)
979
-
980
- await Filesystem.write(filepath, transcript)
981
-
982
- // Open with EDITOR if available
983
- const result = await Editor.open({ value: transcript, renderer })
984
- if (result !== undefined) {
985
- await Filesystem.write(filepath, result)
986
- }
987
-
988
- toast.show({ message: `Session exported to ${filename}`, variant: "success" })
989
- }
990
- } catch {
991
- toast.show({ message: "Failed to export session", variant: "error" })
992
- }
993
- dialog.clear()
994
- },
995
- },
996
- {
997
- title: t("tui.command.session.child_first.title"),
998
- value: "session.child.first",
999
- keybind: "session_child_first",
1000
- category: "session",
1001
- hidden: true,
1002
- onSelect: (dialog) => {
1003
- moveFirstChild()
1004
- dialog.clear()
1005
- },
1006
- },
1007
- {
1008
- title: t("tui.command.session.parent.title"),
1009
- value: "session.parent",
1010
- keybind: "session_parent",
1011
- category: "session",
1012
- hidden: true,
1013
- enabled: currentAgentID() !== "main" || !!workflowRunID() || !!session()?.parentID,
1014
- onSelect: (dialog) => {
1015
- // Workflow page → back to the conversation (parallels agentID → main).
1016
- if (fullRoute.data.type === "session" && workflowRunID()) {
1017
- navigate({ ...fullRoute.data, workflowRunID: undefined })
1018
- dialog.clear()
1019
- return
1020
- }
1021
- // Agent opened FROM a workflow page → back returns to that workflow.
1022
- if (fullRoute.data.type === "session" && currentAgentID() !== "main" && fromWorkflowRunID()) {
1023
- navigate({ ...fullRoute.data, agentID: undefined, fromWorkflowRunID: undefined, workflowRunID: fromWorkflowRunID() })
1024
- dialog.clear()
1025
- return
1026
- }
1027
- if (fullRoute.data.type === "session" && currentAgentID() !== "main") {
1028
- navigate({ ...fullRoute.data, agentID: undefined })
1029
- dialog.clear()
1030
- return
1031
- }
1032
- const parentID = session()?.parentID
1033
- if (parentID) {
1034
- navigate({
1035
- type: "session",
1036
- sessionID: parentID,
1037
- })
1038
- }
1039
- dialog.clear()
1040
- },
1041
- },
1042
- {
1043
- title: t("tui.command.session.child_next.title"),
1044
- value: "session.child.next",
1045
- keybind: "session_child_cycle",
1046
- category: "session",
1047
- hidden: true,
1048
- onSelect: (dialog) => {
1049
- moveChild(1)
1050
- dialog.clear()
1051
- },
1052
- },
1053
- {
1054
- title: t("tui.command.session.child_previous.title"),
1055
- value: "session.child.previous",
1056
- keybind: "session_child_cycle_reverse",
1057
- category: "session",
1058
- hidden: true,
1059
- onSelect: (dialog) => {
1060
- moveChild(-1)
1061
- dialog.clear()
1062
- },
1063
- },
1064
- ])
1065
-
1066
- const revertInfo = createMemo(() => session()?.revert)
1067
- const revertMessageID = createMemo(() => revertInfo()?.messageID)
1068
-
1069
- const revertDiffFiles = createMemo(() => getRevertDiffFiles(revertInfo()?.diff ?? ""))
1070
-
1071
- const revertRevertedMessages = createMemo(() => {
1072
- const messageID = revertMessageID()
1073
- if (!messageID) return []
1074
- return messages().filter((x) => x.id >= messageID && x.role === "user")
1075
- })
1076
-
1077
- const revert = createMemo(() => {
1078
- const info = revertInfo()
1079
- if (!info) return
1080
- if (!info.messageID) return
1081
- return {
1082
- messageID: info.messageID,
1083
- reverted: revertRevertedMessages(),
1084
- diff: info.diff,
1085
- diffFiles: revertDiffFiles(),
1086
- }
1087
- })
1088
-
1089
- // snap to bottom when session changes
1090
- createEffect(on(() => route.sessionID, toBottom))
1091
-
1092
- return (
1093
- <context.Provider
1094
- value={{
1095
- get width() {
1096
- return contentWidth()
1097
- },
1098
- sessionID: route.sessionID,
1099
- conceal,
1100
- thinkingMode,
1101
- showThinking,
1102
- showTimestamps,
1103
- showDetails,
1104
- showGenericToolOutput,
1105
- diffWrapMode,
1106
- providers,
1107
- sync,
1108
- tui: tuiConfig,
1109
- }}
1110
- >
1111
- <box flexDirection="row">
1112
- <box flexGrow={1} paddingBottom={1} paddingLeft={2} paddingRight={2} gap={1} onMouse={onWheel}>
1113
- <Show
1114
- when={!workflowRunID()}
1115
- fallback={
1116
- <WorkflowPage
1117
- runID={workflowRunID()!}
1118
- onBack={() => navigate({ ...route, workflowRunID: undefined })}
1119
- onOpenAgent={(actorID) =>
1120
- navigate({ ...route, workflowRunID: undefined, agentID: actorID, fromWorkflowRunID: workflowRunID() })
1121
- }
1122
- onOpenChild={(childRunID) => navigate({ ...route, workflowRunID: childRunID })}
1123
- />
1124
- }
1125
- >
1126
- <Show when={session()}>
1127
- <scrollbox
1128
- ref={(r) => (scroll = r)}
1129
- viewportOptions={{
1130
- paddingRight: 1,
1131
- }}
1132
- verticalScrollbarOptions={{
1133
- paddingLeft: 1,
1134
- visible: true,
1135
- trackOptions: {
1136
- backgroundColor: scrollbarVisible() ? theme.backgroundElement : theme.background,
1137
- foregroundColor: scrollbarVisible() ? theme.border : theme.background,
1138
- },
1139
- }}
1140
- stickyScroll={true}
1141
- stickyStart="bottom"
1142
- flexGrow={1}
1143
- scrollAcceleration={scrollAcceleration()}
1144
- >
1145
- <box height={1} />
1146
- <For each={messages()}>
1147
- {(message, index) => (
1148
- <Switch>
1149
- <Match when={message.id === revert()?.messageID}>
1150
- {(function () {
1151
- const command = useCommandDialog()
1152
- const [hover, setHover] = createSignal(false)
1153
- const dialog = useDialog()
1154
-
1155
- const handleUnrevert = async () => {
1156
- const confirmed = await DialogConfirm.show(
1157
- dialog,
1158
- "Confirm Redo",
1159
- "Are you sure you want to restore the reverted messages?",
1160
- )
1161
- if (confirmed) {
1162
- command.trigger("session.redo")
1163
- }
1164
- }
1165
-
1166
- return (
1167
- <box
1168
- onMouseOver={() => setHover(true)}
1169
- onMouseOut={() => setHover(false)}
1170
- onMouseUp={handleUnrevert}
1171
- marginTop={1}
1172
- flexShrink={0}
1173
- border={["left"]}
1174
- customBorderChars={SplitBorder.customBorderChars}
1175
- borderColor={theme.backgroundPanel}
1176
- >
1177
- <box
1178
- paddingTop={1}
1179
- paddingBottom={1}
1180
- paddingLeft={2}
1181
- backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
1182
- >
1183
- <text fg={theme.textMuted}>{revert()!.reverted.length} message reverted</text>
1184
- <text fg={theme.textMuted}>
1185
- <span style={{ fg: theme.text }}>{keybind.print("messages_redo")}</span> or /redo to
1186
- restore
1187
- </text>
1188
- <Show when={revert()!.diffFiles?.length}>
1189
- <box marginTop={1}>
1190
- <For each={revert()!.diffFiles}>
1191
- {(file) => (
1192
- <text fg={theme.text}>
1193
- {file.filename}
1194
- <Show when={file.additions > 0}>
1195
- <span style={{ fg: theme.diffAdded }}> +{file.additions}</span>
1196
- </Show>
1197
- <Show when={file.deletions > 0}>
1198
- <span style={{ fg: theme.diffRemoved }}> -{file.deletions}</span>
1199
- </Show>
1200
- </text>
1201
- )}
1202
- </For>
1203
- </box>
1204
- </Show>
1205
- </box>
1206
- </box>
1207
- )
1208
- })()}
1209
- </Match>
1210
- <Match when={revert()?.messageID && message.id >= revert()!.messageID}>
1211
- <></>
1212
- </Match>
1213
- <Match when={message.role === "user"}>
1214
- <UserMessage
1215
- index={index()}
1216
- onMouseUp={() => {
1217
- if (renderer.getSelection()?.getSelectedText()) return
1218
- dialog.replace(() => (
1219
- <DialogMessage
1220
- messageID={message.id}
1221
- sessionID={route.sessionID}
1222
- setPrompt={(promptInfo) => prompt?.set(promptInfo)}
1223
- />
1224
- ))
1225
- }}
1226
- message={message as UserMessage}
1227
- parts={sync.data.part[message.id] ?? []}
1228
- pending={pending()}
1229
- />
1230
- </Match>
1231
- <Match when={message.role === "assistant"}>
1232
- <AssistantMessage
1233
- last={lastAssistant()?.id === message.id}
1234
- message={message as AssistantMessage}
1235
- parts={sync.data.part[message.id] ?? []}
1236
- />
1237
- </Match>
1238
- </Switch>
1239
- )}
1240
- </For>
1241
- </scrollbox>
1242
- <box flexShrink={0}>
1243
- <Show when={permissions().length > 0}>
1244
- <PermissionPrompt request={permissions()[0]} />
1245
- </Show>
1246
- <Show when={permissions().length === 0 && questions().length > 0}>
1247
- <QuestionPrompt request={questions()[0]} />
1248
- </Show>
1249
- <Show when={session()?.parentID || currentAgentID() !== "main"}>
1250
- <SubagentFooter />
1251
- </Show>
1252
- <Show when={visible()}>
1253
- <TuiPluginRuntime.Slot
1254
- name="session_prompt"
1255
- mode="replace"
1256
- session_id={route.sessionID}
1257
- visible={visible()}
1258
- disabled={disabled()}
1259
- on_submit={toBottom}
1260
- ref={bind}
1261
- >
1262
- <Prompt
1263
- visible={visible()}
1264
- ref={bind}
1265
- disabled={disabled()}
1266
- onSubmit={() => {
1267
- toBottom()
1268
- }}
1269
- sessionID={route.sessionID}
1270
- right={<TuiPluginRuntime.Slot name="session_prompt_right" session_id={route.sessionID} />}
1271
- />
1272
- </TuiPluginRuntime.Slot>
1273
- </Show>
1274
- </box>
1275
- </Show>
1276
- </Show>
1277
- <Toast />
1278
- </box>
1279
- <Show when={sidebarVisible()}>
1280
- <Switch>
1281
- <Match when={wide()}>
1282
- <Sidebar sessionID={route.sessionID} onToggle={() => {
1283
- batch(() => {
1284
- setSidebar("hide")
1285
- setSidebarOpen(false)
1286
- })
1287
- }} />
1288
- </Match>
1289
- <Match when={!wide()}>
1290
- <box
1291
- position="absolute"
1292
- top={0}
1293
- left={0}
1294
- right={0}
1295
- bottom={0}
1296
- alignItems="flex-end"
1297
- backgroundColor={RGBA.fromInts(0, 0, 0, 70)}
1298
- >
1299
- <Sidebar sessionID={route.sessionID} onToggle={() => {
1300
- batch(() => {
1301
- setSidebar("hide")
1302
- setSidebarOpen(false)
1303
- })
1304
- }} />
1305
- </box>
1306
- </Match>
1307
- </Switch>
1308
- </Show>
1309
- </box>
1310
- </context.Provider>
1311
- )
1312
- }
1313
-
1314
- const MIME_BADGE: Record<string, string> = {
1315
- "text/plain": "txt",
1316
- "image/png": "img",
1317
- "image/jpeg": "img",
1318
- "image/gif": "img",
1319
- "image/webp": "img",
1320
- "application/pdf": "pdf",
1321
- "application/x-directory": "dir",
1322
- }
1323
-
1324
- function UserMessage(props: {
1325
- message: UserMessage
1326
- parts: Part[]
1327
- onMouseUp: () => void
1328
- index: number
1329
- pending?: string
1330
- }) {
1331
- const ctx = use()
1332
- const local = useLocal()
1333
- const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0])
1334
- const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : [])))
1335
- const { theme } = useTheme()
1336
- const [hover, setHover] = createSignal(false)
1337
- const queued = createMemo(() => props.pending && props.message.id > props.pending)
1338
- const color = createMemo(() => getAgentBrandColor(props.message.agent))
1339
- const queuedFg = createMemo(() => selectedForeground(theme, color()))
1340
- const metadataVisible = createMemo(() => queued() || ctx.showTimestamps())
1341
-
1342
- return (
1343
- <>
1344
- <Show when={text()}>
1345
- <box
1346
- id={props.message.id}
1347
- border={["top", "right", "bottom", "left"]}
1348
- borderColor={theme.primary}
1349
- customBorderChars={{
1350
- topLeft: "╭",
1351
- topRight: "╮",
1352
- bottomLeft: "╰",
1353
- bottomRight: "╯",
1354
- horizontal: "─",
1355
- vertical: "│",
1356
- topT: "┬",
1357
- bottomT: "┴",
1358
- cross: "┼",
1359
- leftT: "├",
1360
- rightT: "┤",
1361
- }}
1362
- marginTop={props.index === 0 ? 0 : 1}
1363
- >
1364
- <box
1365
- onMouseOver={() => {
1366
- setHover(true)
1367
- }}
1368
- onMouseOut={() => {
1369
- setHover(false)
1370
- }}
1371
- onMouseUp={props.onMouseUp}
1372
- paddingTop={1}
1373
- paddingBottom={1}
1374
- paddingLeft={2}
1375
- backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
1376
- flexShrink={0}
1377
- >
1378
- <text fg={theme.text}>{text()?.text}</text>
1379
- <Show when={files().length}>
1380
- <box flexDirection="row" paddingBottom={metadataVisible() ? 1 : 0} paddingTop={1} gap={1} flexWrap="wrap">
1381
- <For each={files()}>
1382
- {(file) => {
1383
- const bg = createMemo(() => {
1384
- if (file.mime.startsWith("image/")) return theme.accent
1385
- if (file.mime === "application/pdf") return theme.primary
1386
- return theme.secondary
1387
- })
1388
- return (
1389
- <text fg={theme.text}>
1390
- <span style={{ bg: bg(), fg: theme.background }}> {MIME_BADGE[file.mime] ?? file.mime} </span>
1391
- <span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}> {file.filename} </span>
1392
- </text>
1393
- )
1394
- }}
1395
- </For>
1396
- </box>
1397
- </Show>
1398
- <Show
1399
- when={queued()}
1400
- fallback={
1401
- <Show when={ctx.showTimestamps()}>
1402
- <text fg={theme.textMuted}>
1403
- <span style={{ fg: theme.textMuted }}>
1404
- {Locale.todayTimeOrDateTime(props.message.time.created)}
1405
- </span>
1406
- </text>
1407
- </Show>
1408
- }
1409
- >
1410
- <text fg={theme.textMuted}>
1411
- <span style={{ bg: color(), fg: queuedFg(), bold: true }}> QUEUED </span>
1412
- </text>
1413
- </Show>
1414
- </box>
1415
- </box>
1416
- </Show>
1417
- </>
1418
- )
1419
- }
1420
-
1421
- function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) {
1422
- const ctx = use()
1423
- const local = useLocal()
1424
- const { theme } = useTheme()
1425
- const sync = useSync()
1426
- const toast = useToast()
1427
- const renderer = useRenderer()
1428
- const t = useLanguage().t
1429
- const [copyHover, setCopyHover] = createSignal(false)
1430
- const messages = createMemo(() => sync.data.message[props.message.sessionID]?.[props.message.agentID ?? "main"] ?? [])
1431
- const model = createMemo(() =>
1432
- props.message.modelID === "mimo-auto"
1433
- ? t("tui.model.mimo_auto.name")
1434
- : Model.name(ctx.providers(), props.message.providerID, props.message.modelID),
1435
- )
1436
-
1437
- const final = createMemo(() => {
1438
- return props.message.finish && props.message.finish !== "tool-calls"
1439
- })
1440
-
1441
- const duration = createMemo(() => {
1442
- if (!final()) return 0
1443
- if (!props.message.time.completed) return 0
1444
- const user = messages().find((x) => x.role === "user" && x.id === props.message.parentID)
1445
- if (!user || !user.time) return 0
1446
- return props.message.time.completed - user.time.created
1447
- })
1448
-
1449
- const keybind = useKeybind()
1450
-
1451
- const handleCopy = () => {
1452
- if (renderer.getSelection()?.getSelectedText()) return
1453
- const text = props.parts
1454
- .filter((p) => p.type === "text")
1455
- .map((p) => (p as TextPart).text)
1456
- .join("\n")
1457
- .trim()
1458
- if (!text) return
1459
- Clipboard.copy(text)
1460
- .then(() => toast.show({ message: t("tui.toast.copied_to_clipboard"), variant: "success" }))
1461
- .catch(() => toast.show({ message: "Failed to copy to clipboard", variant: "error" }))
1462
- }
1463
-
1464
- // Goal judge verdict for this specific turn, if the stop-condition judge
1465
- // evaluated it. Rendered as a foldable per-turn marker so the user can trace
1466
- // back which turn failed the check — without polluting the message stream.
1467
- const verdict = createMemo(() => sync.data.session_goal?.[props.message.sessionID]?.verdicts?.[props.message.id])
1468
- const [verdictOpen, setVerdictOpen] = createSignal(false)
1469
- const verdictMark = createMemo(() => {
1470
- const v = verdict()
1471
- if (!v) return undefined
1472
- if (v.error) return { icon: "!", fg: theme.textMuted, label: "Judge: error (stopped)" }
1473
- if (v.ok) return { icon: "✓", fg: theme.success, label: "Judge: met" }
1474
- if (v.impossible) return { icon: "⊘", fg: theme.error, label: "Judge: impossible" }
1475
- return { icon: "⟳", fg: theme.warning, label: `Judge [round ${v.attempt}]: not met` }
1476
- })
1477
-
1478
- // Both the `actor` and `workflow` tools spawn agents that register as
1479
- // subagents in this session, so the `session_child_first` keybind opens the
1480
- // Subagents panel for either. Advertise it with copy matching the tool that
1481
- // produced the message; a mixed message falls back to the generic subagent
1482
- // wording.
1483
- const hasActorPart = createMemo(() => props.parts.some((x) => x.type === "tool" && x.tool === "actor"))
1484
- const hasWorkflowPart = createMemo(() => props.parts.some((x) => x.type === "tool" && x.tool === "workflow"))
1485
-
1486
- return (
1487
- <>
1488
- <For each={props.parts}>
1489
- {(part, index) => {
1490
- // The StructuredOutput tool call is the mechanism that produces
1491
- // message.structured; we render that value as a dedicated colored block
1492
- // below, so skip the redundant gray one-liner tool part here.
1493
- if (part.type === "tool" && part.tool === "StructuredOutput") return null
1494
- const component = createMemo(() => PART_MAPPING[part.type as keyof typeof PART_MAPPING])
1495
- return (
1496
- <Show when={component()}>
1497
- <Dynamic
1498
- last={index() === props.parts.length - 1}
1499
- component={component()}
1500
- part={part as any}
1501
- message={props.message}
1502
- />
1503
- </Show>
1504
- )
1505
- }}
1506
- </For>
1507
- <Show when={props.message.structured !== undefined && props.message.structured !== null}>
1508
- <StructuredOutput value={props.message.structured} />
1509
- </Show>
1510
- <Show when={hasActorPart() || hasWorkflowPart()}>
1511
- <box paddingTop={1} paddingLeft={3}>
1512
- <text fg={theme.text}>
1513
- {keybind.print("session_child_first")}
1514
- <span style={{ fg: theme.textMuted }}>{hasWorkflowPart() ? " view workflow agents" : " view subagents"}</span>
1515
- </text>
1516
- </box>
1517
- </Show>
1518
- <Show when={props.message.error && props.message.error.name !== "MessageAbortedError"}>
1519
- <ErrorBlock error={props.message.error!} />
1520
- </Show>
1521
- <Switch>
1522
- <Match when={props.last || final() || props.message.error?.name === "MessageAbortedError"}>
1523
- <box paddingLeft={3} flexDirection="row" justifyContent="space-between" marginTop={1}>
1524
- <text>
1525
- <span
1526
- style={{
1527
- fg:
1528
- props.message.error?.name === "MessageAbortedError"
1529
- ? theme.textMuted
1530
- : getAgentBrandColor(props.message.agent),
1531
- }}
1532
- >
1533
- ▣{" "}
1534
- </span>{" "}
1535
- <span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
1536
- <span style={{ fg: theme.textMuted }}> · {model()}</span>
1537
- <Show when={duration()}>
1538
- <span style={{ fg: theme.textMuted }}> · {Locale.duration(duration())}</span>
1539
- </Show>
1540
- <Show when={props.message.error?.name === "MessageAbortedError"}>
1541
- <span style={{ fg: theme.textMuted }}> · interrupted</span>
1542
- </Show>
1543
- </text>
1544
- <Show when={props.message.time.completed}>
1545
- <box
1546
- onMouseOver={() => setCopyHover(true)}
1547
- onMouseOut={() => setCopyHover(false)}
1548
- onMouseUp={handleCopy}
1549
- >
1550
- <text fg={copyHover() ? theme.text : theme.textMuted}>⎘ copy</text>
1551
- </box>
1552
- </Show>
1553
- </box>
1554
- </Match>
1555
- </Switch>
1556
- <Show when={verdictMark()}>
1557
- {(mark) => (
1558
- <box paddingLeft={3} onMouseUp={() => setVerdictOpen((x) => !x)}>
1559
- <text>
1560
- <span style={{ fg: theme.textMuted }}>{verdictOpen() ? "▼" : "▶"} </span>
1561
- <span style={{ fg: mark().fg }}>
1562
- {mark().icon} {mark().label}
1563
- </span>
1564
- </text>
1565
- <Show when={verdictOpen()}>
1566
- <box paddingLeft={2}>
1567
- <text fg={theme.textMuted} wrapMode="word">
1568
- {verdict()!.reason}
1569
- </text>
1570
- </box>
1571
- </Show>
1572
- </box>
1573
- )}
1574
- </Show>
1575
- </>
1576
- )
1577
- }
1578
-
1579
- const PART_MAPPING = {
1580
- text: TextPart,
1581
- tool: ToolPart,
1582
- reasoning: ReasoningPart,
1583
- }
1584
-
1585
- type MessageError = NonNullable<AssistantMessage["error"]>
1586
-
1587
- function errorBody(error: MessageError): string {
1588
- if (error.name === "MessageOutputLengthError") return "Output length limit reached"
1589
- return (error.data as { message?: string }).message ?? "Unknown error"
1590
- }
1591
-
1592
- function errorMeta(error: MessageError): string | undefined {
1593
- if (error.name === "APIError") {
1594
- const parts: string[] = []
1595
- if (error.data.statusCode !== undefined) parts.push(`status ${error.data.statusCode}`)
1596
- parts.push(error.data.isRetryable ? "retryable" : "non-retryable")
1597
- return parts.join(" · ")
1598
- }
1599
- if (error.name === "ProviderAuthError") return `provider: ${error.data.providerID}`
1600
- if (error.name === "StructuredOutputError") return `retries: ${error.data.retries}`
1601
- return undefined
1602
- }
1603
-
1604
- function ErrorBlock(props: { error: MessageError }) {
1605
- const { theme } = useTheme()
1606
- const meta = createMemo(() => errorMeta(props.error))
1607
- return (
1608
- <box flexDirection="column" paddingLeft={3} marginTop={1}>
1609
- <text fg={theme.error} wrapMode="word">
1610
- <span style={{ fg: theme.error }}>✗ </span>
1611
- {errorBody(props.error)}
1612
- </text>
1613
- <Show when={meta()}>
1614
- <box paddingLeft={3}>
1615
- <text fg={theme.textMuted} wrapMode="word">
1616
- {meta()}
1617
- </text>
1618
- </box>
1619
- </Show>
1620
- </box>
1621
- )
1622
- }
1623
-
1624
- // Structured output is a message-level field (AssistantMessage.structured), not a
1625
- // part, so the parts loop never shows it. Agents called with a schema (common in
1626
- // workflows) put their whole answer here — render it as syntax-highlighted JSON so
1627
- // it's not invisible. Collapsible for large payloads.
1628
- function StructuredOutput(props: { value: unknown }) {
1629
- const { theme, syntax } = useTheme()
1630
- const [collapsed, setCollapsed] = createSignal(false)
1631
- const json = createMemo(() => {
1632
- try {
1633
- return JSON.stringify(props.value, null, 2)
1634
- } catch {
1635
- return String(props.value)
1636
- }
1637
- })
1638
- const lineCount = createMemo(() => json().split("\n").length)
1639
- const overflow = createMemo(() => lineCount() > 20)
1640
- const shown = createMemo(() => (collapsed() ? json().split("\n").slice(0, 20).join("\n") + "\n…" : json()))
1641
- return (
1642
- <box paddingLeft={3} marginTop={1} flexDirection="column" flexShrink={0}>
1643
- <box flexDirection="row" gap={1} onMouseUp={() => overflow() && setCollapsed((p) => !p)}>
1644
- <text fg={theme.accent} attributes={TextAttributes.BOLD}>
1645
- ⊟ structured output
1646
- </text>
1647
- <Show when={overflow()}>
1648
- <text fg={theme.textMuted}>
1649
- · {lineCount()} lines{collapsed() ? " · click to expand" : ""}
1650
- </text>
1651
- </Show>
1652
- </box>
1653
- <box marginTop={1}>
1654
- <code filetype="json" drawUnstyledText={false} syntaxStyle={syntax()} content={shown()} fg={theme.text} />
1655
- </box>
1656
- </box>
1657
- )
1658
- }
1659
-
1660
- function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: AssistantMessage }) {
1661
- const { theme, subtleSyntax } = useTheme()
1662
- const ctx = use()
1663
- const [expanded, setExpanded] = createSignal(false)
1664
-
1665
- const content = createMemo(() => {
1666
- return props.part.text.replace("[REDACTED]", "").trim()
1667
- })
1668
- const isDone = createMemo(() => props.part.time.end !== undefined)
1669
- const inMinimal = createMemo(() => ctx.thinkingMode() === "hide")
1670
- const duration = createMemo(() => {
1671
- const end = props.part.time.end
1672
- return end === undefined ? 0 : Math.max(0, end - props.part.time.start)
1673
- })
1674
- const summary = createMemo(() => reasoningSummary(content()))
1675
-
1676
- const toggle = () => {
1677
- if (!inMinimal()) return
1678
- setExpanded((prev) => !prev)
1679
- }
1680
-
1681
- return (
1682
- <Show when={content()}>
1683
- <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexDirection="column" flexShrink={0}>
1684
- <box onMouseUp={toggle}>
1685
- <ReasoningHeader
1686
- toggleable={inMinimal()}
1687
- open={!inMinimal() || expanded()}
1688
- done={isDone()}
1689
- title={summary().title}
1690
- duration={isDone() ? Locale.duration(duration()) : undefined}
1691
- />
1692
- </box>
1693
- <Show when={(!inMinimal() || expanded()) && summary().body}>
1694
- <box paddingLeft={inMinimal() ? 2 : 0} marginTop={1}>
1695
- <code
1696
- filetype="markdown"
1697
- drawUnstyledText={false}
1698
- streaming={true}
1699
- syntaxStyle={subtleSyntax()}
1700
- content={summary().body}
1701
- conceal={ctx.conceal()}
1702
- fg={theme.textMuted}
1703
- />
1704
- </box>
1705
- </Show>
1706
- </box>
1707
- </Show>
1708
- )
1709
- }
1710
-
1711
- function ReasoningHeader(props: {
1712
- toggleable: boolean
1713
- open: boolean
1714
- done: boolean
1715
- title: string | null
1716
- duration?: string
1717
- }) {
1718
- const { theme } = useTheme()
1719
- const fg = () =>
1720
- props.open
1721
- ? RGBA.fromValues(theme.warning.r, theme.warning.g, theme.warning.b, theme.thinkingOpacity)
1722
- : theme.warning
1723
-
1724
- return (
1725
- <Switch>
1726
- <Match when={!props.done}>
1727
- <box flexDirection="row">
1728
- <Spinner color={fg()}>{props.title ? "Thinking: " + props.title : "Thinking"}</Spinner>
1729
- </box>
1730
- </Match>
1731
- <Match when={true}>
1732
- <text fg={fg()} wrapMode="none">
1733
- <Show when={props.toggleable}>
1734
- <span>{props.open ? "- " : "+ "}</span>
1735
- </Show>
1736
- <span>Thought</span>
1737
- <Show when={props.title || props.duration}>
1738
- <span>: </span>
1739
- </Show>
1740
- <Show when={props.title}>
1741
- <span>{props.title}</span>
1742
- </Show>
1743
- <Show when={props.duration}>
1744
- <span>
1745
- {props.title ? " · " : ""}
1746
- {props.duration}
1747
- </span>
1748
- </Show>
1749
- </text>
1750
- </Match>
1751
- </Switch>
1752
- )
1753
- }
1754
-
1755
- function TextPart(props: { last: boolean; part: TextPart; message: AssistantMessage }) {
1756
- const ctx = use()
1757
- const { theme, syntax } = useTheme()
1758
- return (
1759
- <Show when={props.part.text.trim()}>
1760
- <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
1761
- <Switch>
1762
- <Match when={Flag.OPENDASH_EXPERIMENTAL_MARKDOWN}>
1763
- <markdown
1764
- syntaxStyle={syntax()}
1765
- streaming={true}
1766
- content={props.part.text.trim()}
1767
- conceal={ctx.conceal()}
1768
- fg={theme.markdownText}
1769
- bg={theme.background}
1770
- />
1771
- </Match>
1772
- <Match when={!Flag.OPENDASH_EXPERIMENTAL_MARKDOWN}>
1773
- <code
1774
- filetype="markdown"
1775
- drawUnstyledText={false}
1776
- streaming={true}
1777
- syntaxStyle={syntax()}
1778
- content={props.part.text.trim()}
1779
- conceal={ctx.conceal()}
1780
- fg={theme.text}
1781
- />
1782
- </Match>
1783
- </Switch>
1784
- </box>
1785
- </Show>
1786
- )
1787
- }
1788
-
1789
- // Pending messages moved to individual tool pending functions
1790
-
1791
- function ToolPart(props: { last: boolean; part: ToolPart; message: AssistantMessage }) {
1792
- const ctx = use()
1793
- const sync = useSync()
1794
-
1795
- // Hide tool if showDetails is false and tool completed successfully
1796
- const shouldHide = createMemo(() => {
1797
- if (ctx.showDetails()) return false
1798
- if (props.part.state.status !== "completed") return false
1799
- return true
1800
- })
1801
-
1802
- const toolprops = {
1803
- get metadata() {
1804
- return props.part.state.status === "pending" ? {} : (props.part.state.metadata ?? {})
1805
- },
1806
- get input() {
1807
- return props.part.state.input ?? {}
1808
- },
1809
- get output() {
1810
- return props.part.state.status === "completed" ? props.part.state.output : undefined
1811
- },
1812
- get permission() {
1813
- const permissions = sync.data.permission[props.message.sessionID] ?? []
1814
- const permissionIndex = permissions.findIndex((x) => x.tool?.callID === props.part.callID)
1815
- return permissions[permissionIndex]
1816
- },
1817
- get tool() {
1818
- return props.part.tool
1819
- },
1820
- get part() {
1821
- return props.part
1822
- },
1823
- }
1824
-
1825
- return (
1826
- <Show when={!shouldHide()}>
1827
- <Switch>
1828
- <Match when={props.part.tool === "bash"}>
1829
- <Bash {...toolprops} />
1830
- </Match>
1831
- <Match when={props.part.tool === "glob"}>
1832
- <Glob {...toolprops} />
1833
- </Match>
1834
- <Match when={props.part.tool === "read"}>
1835
- <Read {...toolprops} />
1836
- </Match>
1837
- <Match when={props.part.tool === "grep"}>
1838
- <Grep {...toolprops} />
1839
- </Match>
1840
- <Match when={props.part.tool === "webfetch"}>
1841
- <WebFetch {...toolprops} />
1842
- </Match>
1843
- <Match when={props.part.tool === "codesearch"}>
1844
- <CodeSearch {...toolprops} />
1845
- </Match>
1846
- <Match when={props.part.tool === "websearch"}>
1847
- <WebSearch {...toolprops} />
1848
- </Match>
1849
- <Match when={props.part.tool === "write"}>
1850
- <Write {...toolprops} />
1851
- </Match>
1852
- <Match when={props.part.tool === "edit"}>
1853
- <Edit {...toolprops} />
1854
- </Match>
1855
- <Match when={props.part.tool === "actor"}>
1856
- <Task {...toolprops} />
1857
- </Match>
1858
- <Match when={props.part.tool === "task"}>
1859
- <WorkItemTask {...toolprops} />
1860
- </Match>
1861
- <Match when={props.part.tool === "apply_patch"}>
1862
- <ApplyPatch {...toolprops} />
1863
- </Match>
1864
- <Match when={props.part.tool === "question"}>
1865
- <Question {...toolprops} />
1866
- </Match>
1867
- <Match when={props.part.tool === "skill"}>
1868
- <Skill {...toolprops} />
1869
- </Match>
1870
- <Match when={props.part.tool === "workflow"}>
1871
- <Workflow {...toolprops} />
1872
- </Match>
1873
- <Match when={props.part.tool === "plan_exit"}>
1874
- <PlanExit {...toolprops} />
1875
- </Match>
1876
- <Match when={true}>
1877
- <GenericTool {...toolprops} />
1878
- </Match>
1879
- </Switch>
1880
- </Show>
1881
- )
1882
- }
1883
-
1884
- type ToolProps<T> = {
1885
- input: Partial<Tool.InferParameters<T>>
1886
- metadata: Partial<Tool.InferMetadata<T>>
1887
- permission: Record<string, any>
1888
- tool: string
1889
- output?: string
1890
- part: ToolPart
1891
- }
1892
- function PlanExit(props: ToolProps<any>) {
1893
- const { theme } = useTheme()
1894
- const dismissed = createMemo(
1895
- () => props.part.state.status === "completed" && props.part.state.metadata?.switched === false,
1896
- )
1897
- const feedback = createMemo(() => (dismissed() ? props.metadata.feedback : undefined))
1898
-
1899
- return (
1900
- <>
1901
- <InlineTool icon="⚙" pending="Asking..." complete={true} part={props.part} dismissed={dismissed()}>
1902
- plan_exit
1903
- </InlineTool>
1904
- <Show when={feedback()}>
1905
- <box paddingLeft={6}>
1906
- <text fg={theme.textMuted}>{feedback()}</text>
1907
- </box>
1908
- </Show>
1909
- </>
1910
- )
1911
- }
1912
-
1913
- function GenericTool(props: ToolProps<any>) {
1914
- const { theme } = useTheme()
1915
- const ctx = use()
1916
- const output = createMemo(() => props.output?.trim() ?? "")
1917
- const [expanded, setExpanded] = createSignal(false)
1918
- const lines = createMemo(() => output().split("\n"))
1919
- const maxLines = 3
1920
- const overflow = createMemo(() => lines().length > maxLines)
1921
- const limited = createMemo(() => {
1922
- if (expanded() || !overflow()) return output()
1923
- return [...lines().slice(0, maxLines), "…"].join("\n")
1924
- })
1925
-
1926
- return (
1927
- <Show
1928
- when={props.output && ctx.showGenericToolOutput()}
1929
- fallback={
1930
- <InlineTool icon="⚙" pending="Writing command..." complete={true} part={props.part}>
1931
- {props.tool} {input(props.input)}
1932
- </InlineTool>
1933
- }
1934
- >
1935
- <BlockTool
1936
- title={`# ${props.tool} ${input(props.input)}`}
1937
- part={props.part}
1938
- onClick={overflow() ? () => setExpanded((prev) => !prev) : undefined}
1939
- >
1940
- <box gap={1}>
1941
- <text fg={theme.text}>{limited()}</text>
1942
- <Show when={overflow()}>
1943
- <text fg={theme.textMuted}>{expanded() ? "Click to collapse" : "Click to expand"}</text>
1944
- </Show>
1945
- </box>
1946
- </BlockTool>
1947
- </Show>
1948
- )
1949
- }
1950
-
1951
- // Inline renderer for the work-item `task` tool (distinct from <Task>, which
1952
- // renders the subagent-spawning `actor` tool). Shows the operation as a concise
1953
- // one-liner derived from the nested `{ operation: { action } }` discriminator,
1954
- // so task create/start/done don't fall through to GenericTool's raw-JSON dump.
1955
- function WorkItemTask(props: ToolProps<typeof TaskTool>) {
1956
- const summary = createMemo(() => {
1957
- const op = (props.input as { operation?: Record<string, any> }).operation
1958
- if (!op || typeof op !== "object") return "task"
1959
- const verb = typeof op.action === "string" ? op.action : "task"
1960
- if (verb === "create") return op.summary ? `create "${op.summary}"` : "create"
1961
- if (verb === "list") return op.status ? `list ${op.status}` : "list"
1962
- if (op.id) return `${verb} ${op.id}`
1963
- return verb
1964
- })
1965
- return (
1966
- <InlineTool icon="#" pending="Updating tasks..." complete={true} part={props.part}>
1967
- task {summary()}
1968
- </InlineTool>
1969
- )
1970
- }
1971
-
1972
- // Inline renderer for the dynamic-workflow `workflow` tool. The "run" op blocks
1973
- // until terminal and streams a transcript (phase transitions + log() messages)
1974
- // into part-state metadata via ctx.metadata; the tool's `Workflow` view here
1975
- // reads metadata.transcript reactively (each ctx.metadata call fires a
1976
- // message.part.delta) and renders it as multi-line chat content alongside the
1977
- // live header from sync.data.workflow[runID]. That way phase/log events show
1978
- // up in the main agent's conversation as the workflow runs, not as a single
1979
- // silent line that only updates once the run finishes.
1980
- function Workflow(props: ToolProps<typeof WorkflowTool>) {
1981
- const sync = useSync()
1982
- const fullRoute = useRoute()
1983
-
1984
- const operation = createMemo(() => {
1985
- const op = (props.input as { operation?: string }).operation
1986
- return typeof op === "string" ? op : "run"
1987
- })
1988
-
1989
- const runID = createMemo(
1990
- () => (props.metadata.runID as string | undefined) ?? (props.input as { run_id?: string }).run_id,
1991
- )
1992
-
1993
- const run = createMemo(() => {
1994
- const id = runID()
1995
- if (!id) return undefined
1996
- return sync.data.workflow[id]
1997
- })
1998
-
1999
- // Spinner is true while EITHER side reports running — the tool part stays
2000
- // running until execute() returns (the whole workflow duration, since we
2001
- // block), and the bus-fed run row independently reports "running" until the
2002
- // workflow.finished event lands. Either signal alone is enough.
2003
- const isRunning = createMemo(() => {
2004
- if (props.part.state.status === "running") return true
2005
- const r = run()
2006
- return r?.status === "running"
2007
- })
2008
-
2009
- const transcript = createMemo(() => {
2010
- const t = (props.metadata as { transcript?: { kind: "phase" | "log"; text: string }[] }).transcript
2011
- return Array.isArray(t) ? t : []
2012
- })
2013
-
2014
- const name = createMemo(() => run()?.name ?? (props.input as { name?: string }).name ?? "inline")
2015
- const status = createMemo(() => run()?.status ?? (props.metadata.status as string | undefined))
2016
-
2017
- // Counters/phase prefer the live metadata streamed by the tool's 250ms flush
2018
- // loop, falling back to the bus run row. The bus row only learns counters via
2019
- // loadWorkflows polling (which only the /workflows dialog runs), so during a run
2020
- // the inline panel would otherwise sit at 0✓ 0✗ 0⟳ — the streamed metadata is
2021
- // the authoritative live source for this in-conversation view.
2022
- const counters = createMemo(() => {
2023
- const m = (props.metadata as { counters?: { running: number; succeeded: number; failed: number } }).counters
2024
- if (m) return m
2025
- const r = run()
2026
- return r ? { running: r.running, succeeded: r.succeeded, failed: r.failed } : undefined
2027
- })
2028
- const currentPhase = createMemo(
2029
- () => (props.metadata as { currentPhase?: string }).currentPhase ?? run()?.currentPhase,
2030
- )
2031
-
2032
- // Non-"run" ops (status/wait/cancel/resume) are one-shot control calls with no
2033
- // live transcript — keep them as a compact inline line.
2034
- return (
2035
- <Show when={operation() === "run"} fallback={
2036
- <InlineTool icon="⚡" spinner={isRunning()} pending="Starting workflow..." complete={true} part={props.part}>
2037
- {`workflow ${operation()}${runID() ? ` ${runID()}` : ""}`}
2038
- </InlineTool>
2039
- }>
2040
- <WorkflowPanel
2041
- name={name()}
2042
- status={status()}
2043
- counters={counters()}
2044
- currentPhase={currentPhase()}
2045
- transcript={transcript()}
2046
- running={isRunning()}
2047
- part={props.part}
2048
- onOpen={
2049
- runID() && fullRoute.data.type === "session"
2050
- ? () => {
2051
- const d = fullRoute.data
2052
- if (d.type === "session") fullRoute.navigate({ ...d, workflowRunID: runID() })
2053
- }
2054
- : undefined
2055
- }
2056
- />
2057
- </Show>
2058
- )
2059
- }
2060
-
2061
- // Bold panel for a `workflow run`. The transcript (phase + log lines streamed
2062
- // every 250ms into part metadata) is the run's live activity — agents spawning,
2063
- // per-source hits, facts checked. The old renderer dumped it all as one muted-
2064
- // gray InlineTool blob, so a busy run read as "stuck". Here phases are bold
2065
- // accent section headers, logs render in readable text, and a running run shows
2066
- // a spinner on its current phase so progress is always visible. Bounded to the
2067
- // last N lines in the conversation flow; full history lives in the detail dialog.
2068
- const WORKFLOW_PANEL_TAIL = 12
2069
-
2070
- // WorkflowPage is conditionally rendered (fallback of the conversation Show), so it
2071
- // fully unmounts when you navigate into a subagent and remounts on return — which
2072
- // would reset its scrollbox to the top. Remember the last scroll offset per runID
2073
- // here so returning restores the position, like the persistent conversation scroll.
2074
- const workflowScrollByRun = new Map<string, number>()
2075
- function WorkflowPanel(props: {
2076
- name: string
2077
- status?: string
2078
- counters?: { succeeded: number; failed: number; running: number }
2079
- currentPhase?: string
2080
- transcript: { kind: "phase" | "log"; text: string }[]
2081
- running: boolean
2082
- part: ToolPart
2083
- onOpen?: () => void
2084
- }) {
2085
- const { theme } = useTheme()
2086
- const renderer = useRenderer()
2087
- const [collapsed, setCollapsed] = createSignal(false)
2088
- const [openHover, setOpenHover] = createSignal(false)
2089
-
2090
- const statusColor = createMemo(() => {
2091
- const s = props.status
2092
- if (s === "completed") return theme.success
2093
- if (s === "failed") return theme.error
2094
- if (s === "cancelled") return theme.textMuted
2095
- return theme.warning
2096
- })
2097
-
2098
- const hiddenCount = createMemo(() => Math.max(0, props.transcript.length - WORKFLOW_PANEL_TAIL))
2099
- const entries = createMemo(() => (collapsed() ? [] : props.transcript.slice(-WORKFLOW_PANEL_TAIL)))
2100
-
2101
- return (
2102
- <box
2103
- border={["left"]}
2104
- paddingTop={1}
2105
- paddingBottom={1}
2106
- paddingLeft={2}
2107
- marginTop={1}
2108
- gap={1}
2109
- backgroundColor={theme.backgroundPanel}
2110
- customBorderChars={SplitBorder.customBorderChars}
2111
- borderColor={theme.background}
2112
- onMouseUp={() => {
2113
- if (renderer.getSelection()?.getSelectedText()) return
2114
- setCollapsed((p) => !p)
2115
- }}
2116
- >
2117
- <box flexDirection="row" gap={1} paddingLeft={3}>
2118
- <Show when={props.running} fallback={<text fg={theme.accent} attributes={TextAttributes.BOLD}>⚡</text>}>
2119
- <spinner frames={["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]} interval={80} color={theme.accent} />
2120
- </Show>
2121
- <text attributes={TextAttributes.BOLD} fg={theme.accent}>
2122
- {props.name}
2123
- </text>
2124
- <Show when={props.status}>
2125
- <text fg={statusColor()} attributes={TextAttributes.BOLD}>
2126
- {props.status}
2127
- </text>
2128
- </Show>
2129
- <Show when={props.currentPhase}>
2130
- <text fg={theme.textMuted}>· {props.currentPhase}</text>
2131
- </Show>
2132
- <Show when={props.counters}>
2133
- <text fg={theme.success}>{props.counters!.succeeded}✓</text>
2134
- <text fg={props.counters!.failed > 0 ? theme.error : theme.textMuted}>{props.counters!.failed}✗</text>
2135
- <text fg={props.counters!.running > 0 ? theme.warning : theme.textMuted}>{props.counters!.running}⟳</text>
2136
- </Show>
2137
- <Show when={props.onOpen}>
2138
- <box flexGrow={1} />
2139
- <text
2140
- fg={openHover() ? theme.text : theme.markdownLink}
2141
- onMouseOver={() => setOpenHover(true)}
2142
- onMouseOut={() => setOpenHover(false)}
2143
- onMouseUp={(evt) => {
2144
- evt.stopPropagation()
2145
- if (renderer.getSelection()?.getSelectedText()) return
2146
- props.onOpen?.()
2147
- }}
2148
- >
2149
- open ↗
2150
- </text>
2151
- </Show>
2152
- </box>
2153
- <Show
2154
- when={!collapsed()}
2155
- fallback={
2156
- <text paddingLeft={3} fg={theme.textMuted}>
2157
- {props.transcript.length} lines · click to expand
2158
- </text>
2159
- }
2160
- >
2161
- <box paddingLeft={3}>
2162
- <Show when={hiddenCount() > 0}>
2163
- <text fg={theme.textMuted}>+{hiddenCount()} earlier lines · open detail for full history</text>
2164
- </Show>
2165
- <For each={entries()}>
2166
- {(e) => (
2167
- <Show
2168
- when={e.kind === "phase"}
2169
- fallback={<text fg={theme.text}>{e.text}</text>}
2170
- >
2171
- <text fg={theme.accent} attributes={TextAttributes.BOLD}>
2172
- ▸ {e.text}
2173
- </text>
2174
- </Show>
2175
- )}
2176
- </For>
2177
- </box>
2178
- </Show>
2179
- </box>
2180
- )
2181
- }
2182
-
2183
- // Full-screen workflow detail page: occupies the conversation column (like a
2184
- // subagent view) and shows one run's structure tree + transcript, live while
2185
- // running. An agent row navigates to that subagent's full conversation; a nested
2186
- // workflow row drills into the child run; "Main" returns to the conversation.
2187
- function WorkflowPage(props: {
2188
- runID: string
2189
- onBack: () => void
2190
- onOpenAgent: (actorID: string) => void
2191
- onOpenChild: (childRunID: string) => void
2192
- }) {
2193
- const sync = useSync()
2194
- const dialog = useDialog()
2195
- const keybind = useKeybind()
2196
- const { theme } = useTheme()
2197
- const renderer = useRenderer()
2198
- const tuiConfig = useTuiConfig()
2199
- const scrollAcceleration = createMemo(() => getScrollAcceleration(tuiConfig))
2200
- let pageScroll: ScrollBoxRenderable | undefined
2201
-
2202
- const run = createMemo(() => sync.data.workflow[props.runID])
2203
-
2204
- // Describe what a running subagent is currently doing, from its live message
2205
- // stream (last message's last meaningful part): a tool call → "⚙ <tool>", else
2206
- // the latest text snippet. Returns undefined when nothing's streamed yet.
2207
- const liveActivity = (actorID: string): string | undefined => {
2208
- const sid = run()?.sessionID
2209
- if (!sid) return undefined
2210
- const msgs = sync.data.message[sid]?.[actorID]
2211
- const last = msgs?.[msgs.length - 1]
2212
- if (!last) return undefined
2213
- const parts = sync.data.part[last.id] ?? []
2214
- for (let i = parts.length - 1; i >= 0; i--) {
2215
- const p = parts[i] as { type?: string; tool?: string; text?: string }
2216
- if (p.type === "tool" && p.tool) return `⚙ ${p.tool}`
2217
- if (p.type === "text" && p.text) return p.text
2218
- }
2219
- return undefined
2220
- }
2221
- const transcript = createMemo(() => sync.data.workflowTranscript[props.runID] ?? [])
2222
- const structure = createMemo(() => sync.data.workflowStructure[props.runID] ?? [])
2223
-
2224
- // Keyed on props.runID so a parent→child sub-workflow navigation (which does NOT
2225
- // remount this component, since the <Show> fallback stays mounted while
2226
- // workflowRunID is merely a different value) re-loads the new run's data, restores
2227
- // its scroll, and re-arms the poll. The effect's onCleanup runs with `runID` bound
2228
- // to the run being LEFT, so it saves that run's scroll under the correct key —
2229
- // unlike reading props.runID at unmount, which is already stale.
2230
- createEffect(
2231
- on(
2232
- () => props.runID,
2233
- (runID) => {
2234
- sync.loadWorkflowTranscript(runID)
2235
- sync.loadWorkflowStructure(runID)
2236
- // Restore the scroll position saved when we last left this run's page.
2237
- // Deferred + retried so the cards (from the persisted structure store) are
2238
- // laid out first, giving scrollTop a real range to land within.
2239
- const saved = workflowScrollByRun.get(runID)
2240
- if (saved) {
2241
- let tries = 0
2242
- const restore = () => {
2243
- if (pageScroll) pageScroll.scrollTop = saved
2244
- if (++tries < 5 && (pageScroll?.scrollTop ?? 0) < saved - 1) setTimeout(restore, 60)
2245
- }
2246
- setTimeout(restore, 0)
2247
- } else if (pageScroll) {
2248
- pageScroll.scrollTop = 0
2249
- }
2250
- const interval = setInterval(() => {
2251
- sync.loadWorkflowStructure(runID)
2252
- sync.loadWorkflowTranscript(runID)
2253
- }, 1000)
2254
- onCleanup(() => {
2255
- clearInterval(interval)
2256
- if (pageScroll) workflowScrollByRun.set(runID, pageScroll.scrollTop)
2257
- })
2258
- },
2259
- ),
2260
- )
2261
-
2262
- const statusColor = createMemo(() => {
2263
- const s = run()?.status
2264
- if (s === "completed") return theme.success
2265
- if (s === "failed") return theme.error
2266
- if (s === "cancelled") return theme.textMuted
2267
- return theme.warning
2268
- })
2269
-
2270
- const resumable = createMemo(() => {
2271
- const s = run()?.status
2272
- return s === "running" || s === "failed" || s === "cancelled"
2273
- })
2274
- const resume = async () => {
2275
- const ok = await DialogConfirm.show(
2276
- dialog,
2277
- "Resume workflow",
2278
- `Re-run "${run()?.name ?? props.runID}"? This re-executes the workflow and may incur cost.`,
2279
- )
2280
- if (ok === true) void sync.resumeWorkflow(props.runID)
2281
- }
2282
-
2283
- return (
2284
- <box flexGrow={1} gap={1}>
2285
- <box flexDirection="row" gap={1} flexShrink={0}>
2286
- <text
2287
- fg={theme.text}
2288
- onMouseUp={() => {
2289
- if (renderer.getSelection()?.getSelectedText()) return
2290
- props.onBack()
2291
- }}
2292
- >
2293
- ‹ Main <span style={{ fg: theme.textMuted }}>{keybind.print("session_parent")}</span>
2294
- </text>
2295
- <box flexGrow={1} />
2296
- <text attributes={TextAttributes.BOLD} fg={theme.accent}>
2297
- {run()?.name ?? props.runID}
2298
- </text>
2299
- <Show when={run()?.status}>
2300
- <text attributes={TextAttributes.BOLD} fg={statusColor()}>
2301
- {run()!.status}
2302
- </text>
2303
- </Show>
2304
- </box>
2305
- <Show when={run()}>
2306
- <box flexDirection="row" gap={1} flexShrink={0}>
2307
- <Show when={run()!.currentPhase}>
2308
- <text fg={theme.textMuted}>{run()!.currentPhase}</text>
2309
- </Show>
2310
- <text fg={theme.success}>{run()!.succeeded}✓</text>
2311
- <text fg={run()!.failed > 0 ? theme.error : theme.textMuted}>{run()!.failed}✗</text>
2312
- <text fg={run()!.running > 0 ? theme.warning : theme.textMuted}>{run()!.running}⟳</text>
2313
- <Show when={resumable()}>
2314
- <text fg={theme.markdownLink} onMouseUp={() => void resume()}>
2315
- ↻ resume
2316
- </text>
2317
- </Show>
2318
- </box>
2319
- </Show>
2320
- <scrollbox
2321
- ref={(r) => (pageScroll = r)}
2322
- flexGrow={1}
2323
- scrollAcceleration={scrollAcceleration()}
2324
- >
2325
- <WorkflowTree
2326
- nodes={structure()}
2327
- onOpenChild={props.onOpenChild}
2328
- onOpenAgent={props.onOpenAgent}
2329
- liveActivity={liveActivity}
2330
- />
2331
- <Show when={transcript().length > 0}>
2332
- <box paddingTop={1}>
2333
- <text fg={theme.textMuted}>transcript</text>
2334
- <For each={transcript()}>
2335
- {(e) => (
2336
- <Show when={e.kind === "phase"} fallback={<text fg={theme.text}>{e.text}</text>}>
2337
- <text attributes={TextAttributes.BOLD} fg={theme.accent}>
2338
- ▸ {e.text}
2339
- </text>
2340
- </Show>
2341
- )}
2342
- </For>
2343
- </box>
2344
- </Show>
2345
- <Show when={run()?.error}>
2346
- <text fg={theme.error}>{run()!.error}</text>
2347
- </Show>
2348
- </scrollbox>
2349
- </box>
2350
- )
2351
- }
2352
-
2353
- function CollapsibleError(props: { error: string; paddingLeft?: number }) {
2354
- const { theme } = useTheme()
2355
- const renderer = useRenderer()
2356
- const [expanded, setExpanded] = createSignal(false)
2357
-
2358
-
2359
- const lineCount = createMemo(() => props.error.split("\n").length)
2360
-
2361
- return (
2362
- <box
2363
- paddingLeft={props.paddingLeft}
2364
- onMouseUp={(evt) => {
2365
- evt.stopPropagation()
2366
- if (renderer.getSelection()?.getSelectedText()) return
2367
- setExpanded((prev) => !prev)
2368
- }}
2369
- >
2370
- <Show
2371
- when={expanded()}
2372
- fallback={
2373
- <text fg={theme.error}>
2374
- + Error ({lineCount()} {lineCount() === 1 ? "line" : "lines"})
2375
- </text>
2376
- }
2377
- >
2378
- <text fg={theme.error}>- Error</text>
2379
- <box paddingLeft={2}>
2380
- <text fg={theme.error}>{props.error}</text>
2381
- </box>
2382
- </Show>
2383
- </box>
2384
- )
2385
- }
2386
-
2387
- function InlineTool(props: {
2388
- icon: string
2389
- iconColor?: RGBA
2390
- complete: any
2391
- pending: string
2392
- spinner?: boolean
2393
- dismissed?: boolean
2394
- children: JSX.Element
2395
- part: ToolPart
2396
- onClick?: () => void
2397
- }) {
2398
- const [margin, setMargin] = createSignal(0)
2399
- const { theme } = useTheme()
2400
- const ctx = use()
2401
- const sync = useSync()
2402
- const renderer = useRenderer()
2403
- const [hover, setHover] = createSignal(false)
2404
-
2405
- const permission = createMemo(() => {
2406
- const callID = sync.data.permission[ctx.sessionID]?.at(0)?.tool?.callID
2407
- if (!callID) return false
2408
- return callID === props.part.callID
2409
- })
2410
-
2411
- const fg = createMemo(() => {
2412
- if (permission()) return theme.warning
2413
- if (hover() && props.onClick) return theme.text
2414
- if (props.complete) return theme.textMuted
2415
- return theme.text
2416
- })
2417
-
2418
- const error = createMemo(() => (props.part.state.status === "error" ? props.part.state.error : undefined))
2419
-
2420
- const denied = createMemo(
2421
- () =>
2422
- error()?.includes("QuestionRejectedError") ||
2423
- error()?.includes("rejected permission") ||
2424
- error()?.includes("specified a rule") ||
2425
- error()?.includes("user dismissed"),
2426
- )
2427
-
2428
- // Agent-recoverable failures (bad args, malformed call, unknown task/actor id)
2429
- // are flagged on the error state. Render them muted (struck through, no red
2430
- // block) like denials — the agent self-corrects; the user needn't be alarmed.
2431
- const recoverable = createMemo(() => {
2432
- const state = props.part.state
2433
- return state.status === "error" && state.metadata?.recoverable === true
2434
- })
2435
-
2436
- return (
2437
- <box
2438
- marginTop={margin()}
2439
- paddingLeft={3}
2440
- onMouseOver={() => props.onClick && setHover(true)}
2441
- onMouseOut={() => setHover(false)}
2442
- onMouseUp={() => {
2443
- if (renderer.getSelection()?.getSelectedText()) return
2444
- props.onClick?.()
2445
- }}
2446
- renderBefore={function () {
2447
- const el = this as BoxRenderable
2448
- const parent = el.parent
2449
- if (!parent) {
2450
- return
2451
- }
2452
- if (el.height > 1) {
2453
- setMargin(1)
2454
- return
2455
- }
2456
- const children = parent.getChildren()
2457
- const index = children.indexOf(el)
2458
- const previous = children[index - 1]
2459
- if (!previous) {
2460
- setMargin(0)
2461
- return
2462
- }
2463
- if (previous.height > 1 || previous.id.startsWith("text-")) {
2464
- setMargin(1)
2465
- return
2466
- }
2467
- }}
2468
- >
2469
- <Switch>
2470
- <Match when={props.spinner}>
2471
- <Spinner color={fg()} children={props.children} />
2472
- </Match>
2473
- <Match when={true}>
2474
- <text paddingLeft={3} fg={fg()} attributes={denied() || recoverable() || props.dismissed ? TextAttributes.STRIKETHROUGH : undefined}>
2475
- <Show fallback={<>~ {props.pending}</>} when={props.complete}>
2476
- <span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children}
2477
- </Show>
2478
- </text>
2479
- </Match>
2480
- </Switch>
2481
- <Show when={error() && !denied() && !recoverable()}>
2482
- <CollapsibleError error={error()!} paddingLeft={3} />
2483
- </Show>
2484
- </box>
2485
- )
2486
- }
2487
-
2488
- function BlockTool(props: {
2489
- title: string
2490
- children: JSX.Element
2491
- onClick?: () => void
2492
- part?: ToolPart
2493
- spinner?: boolean
2494
- }) {
2495
- const { theme } = useTheme()
2496
- const renderer = useRenderer()
2497
- const [hover, setHover] = createSignal(false)
2498
- const error = createMemo(() => (props.part?.state.status === "error" ? props.part.state.error : undefined))
2499
- return (
2500
- <box
2501
- border={["left"]}
2502
- paddingTop={1}
2503
- paddingBottom={1}
2504
- paddingLeft={2}
2505
- marginTop={1}
2506
- gap={1}
2507
- backgroundColor={hover() ? theme.backgroundMenu : theme.backgroundPanel}
2508
- customBorderChars={SplitBorder.customBorderChars}
2509
- borderColor={theme.background}
2510
- onMouseOver={() => props.onClick && setHover(true)}
2511
- onMouseOut={() => setHover(false)}
2512
- onMouseUp={() => {
2513
- if (renderer.getSelection()?.getSelectedText()) return
2514
- props.onClick?.()
2515
- }}
2516
- >
2517
- <Show
2518
- when={props.spinner}
2519
- fallback={
2520
- <text paddingLeft={3} fg={theme.textMuted}>
2521
- {props.title}
2522
- </text>
2523
- }
2524
- >
2525
- <Spinner color={theme.textMuted}>{props.title.replace(/^# /, "")}</Spinner>
2526
- </Show>
2527
- {props.children}
2528
- <Show when={error()}>
2529
- <CollapsibleError error={error()!} />
2530
- </Show>
2531
- </box>
2532
- )
2533
- }
2534
-
2535
- const TOOL_COLLAPSE_MAX_LINES = 3
2536
- const TOOL_COLLAPSE_MAX_LINE_LENGTH = 120
2537
-
2538
- function displayLines(content: string) {
2539
- if (!content) return []
2540
- return content.replace(/\n$/, "").split("\n")
2541
- }
2542
-
2543
- function hasLongDisplayLine(content: string) {
2544
- return displayLines(content).some((line) => line.length > TOOL_COLLAPSE_MAX_LINE_LENGTH)
2545
- }
2546
-
2547
- function Bash(props: ToolProps<typeof BashTool>) {
2548
- const { theme } = useTheme()
2549
- const sync = useSync()
2550
- const isRunning = createMemo(() => props.part.state.status === "running")
2551
- const output = createMemo(() => stripAnsi(props.metadata.output?.trim() ?? ""))
2552
- const [expanded, setExpanded] = createSignal(false)
2553
- const lines = createMemo(() => output().split("\n"))
2554
- const overflow = createMemo(() => lines().length > 10)
2555
- const limited = createMemo(() => {
2556
- if (expanded() || !overflow()) return output()
2557
- return [...lines().slice(0, 10), "…"].join("\n")
2558
- })
2559
-
2560
- const workdirDisplay = createMemo(() => {
2561
- const workdir = props.input.workdir
2562
- if (!workdir || workdir === ".") return undefined
2563
-
2564
- const base = sync.path.directory
2565
- if (!base) return undefined
2566
-
2567
- const absolute = path.resolve(base, workdir)
2568
- if (absolute === base) return undefined
2569
-
2570
- const home = Global.Path.home
2571
- if (!home) return absolute
2572
-
2573
- const match = absolute === home || absolute.startsWith(home + path.sep)
2574
- return match ? absolute.replace(home, "~") : absolute
2575
- })
2576
-
2577
- const title = createMemo(() => {
2578
- const desc = props.input.description ?? "Shell"
2579
- const wd = workdirDisplay()
2580
- if (!wd) return `# ${desc}`
2581
- if (desc.includes(wd)) return `# ${desc}`
2582
- return `# ${desc} in ${wd}`
2583
- })
2584
-
2585
- return (
2586
- <Switch>
2587
- <Match when={props.metadata.output !== undefined}>
2588
- <BlockTool
2589
- title={title()}
2590
- part={props.part}
2591
- spinner={isRunning()}
2592
- onClick={overflow() ? () => setExpanded((prev) => !prev) : undefined}
2593
- >
2594
- <box gap={1}>
2595
- <text fg={theme.text}>$ {props.input.command}</text>
2596
- <Show when={output()}>
2597
- <text fg={theme.text}>{limited()}</text>
2598
- </Show>
2599
- <Show when={overflow()}>
2600
- <text fg={theme.textMuted}>{expanded() ? "Click to collapse" : "Click to expand"}</text>
2601
- </Show>
2602
- </box>
2603
- </BlockTool>
2604
- </Match>
2605
- <Match when={true}>
2606
- <InlineTool icon="$" pending="Writing command..." complete={props.input.command} part={props.part}>
2607
- {props.input.command}
2608
- </InlineTool>
2609
- </Match>
2610
- </Switch>
2611
- )
2612
- }
2613
-
2614
- function Write(props: ToolProps<typeof WriteTool>) {
2615
- const { theme, syntax } = useTheme()
2616
- const [expanded, setExpanded] = createSignal(false)
2617
- const code = createMemo(() => {
2618
- if (!props.input.content) return ""
2619
- return props.input.content
2620
- })
2621
- const lineCount = createMemo(() => displayLines(code()).length)
2622
- const collapsed = createMemo(() => lineCount() > TOOL_COLLAPSE_MAX_LINES || hasLongDisplayLine(code()))
2623
-
2624
- return (
2625
- <Switch>
2626
- <Match when={props.metadata.diagnostics !== undefined}>
2627
- <BlockTool
2628
- title={"# Wrote " + normalizePath(props.input.file_path!)}
2629
- part={props.part}
2630
- onClick={collapsed() ? () => setExpanded((prev) => !prev) : undefined}
2631
- >
2632
- <Show
2633
- when={!collapsed() || expanded()}
2634
- fallback={
2635
- <text fg={theme.textMuted}>
2636
- Click to expand ({lineCount()} {lineCount() === 1 ? "line" : "lines"})
2637
- </text>
2638
- }
2639
- >
2640
- <line_number fg={theme.textMuted} minWidth={3} paddingRight={1}>
2641
- <code
2642
- conceal={false}
2643
- fg={theme.text}
2644
- filetype={filetype(props.input.file_path!)}
2645
- syntaxStyle={syntax()}
2646
- content={code()}
2647
- />
2648
- </line_number>
2649
- <Show when={collapsed()}>
2650
- <text fg={theme.textMuted}>Click to collapse</text>
2651
- </Show>
2652
- </Show>
2653
- <Diagnostics diagnostics={props.metadata.diagnostics} filePath={props.input.file_path ?? ""} />
2654
- </BlockTool>
2655
- </Match>
2656
- <Match when={true}>
2657
- <InlineTool icon="←" pending="Preparing write..." complete={props.input.file_path} part={props.part}>
2658
- Write {normalizePath(props.input.file_path!)}
2659
- </InlineTool>
2660
- </Match>
2661
- </Switch>
2662
- )
2663
- }
2664
-
2665
- function Glob(props: ToolProps<typeof GlobTool>) {
2666
- return (
2667
- <InlineTool icon="✱" pending="Finding files..." complete={props.input.pattern} part={props.part}>
2668
- Glob "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
2669
- <Show when={props.metadata.count}>
2670
- ({props.metadata.count} {props.metadata.count === 1 ? "match" : "matches"})
2671
- </Show>
2672
- </InlineTool>
2673
- )
2674
- }
2675
-
2676
- function Read(props: ToolProps<typeof ReadTool>) {
2677
- const { theme } = useTheme()
2678
- const isRunning = createMemo(() => props.part.state.status === "running")
2679
- const loaded = createMemo(() => {
2680
- if (props.part.state.status !== "completed") return []
2681
- if (props.part.state.time.compacted) return []
2682
- const value = props.metadata.loaded
2683
- if (!value || !Array.isArray(value)) return []
2684
- return value.filter((p): p is string => typeof p === "string")
2685
- })
2686
- return (
2687
- <>
2688
- <InlineTool
2689
- icon="→"
2690
- pending="Reading file..."
2691
- complete={props.input.file_path}
2692
- spinner={isRunning()}
2693
- part={props.part}
2694
- >
2695
- Read {normalizePath(props.input.file_path!)} {input(props.input, ["file_path"])}
2696
- </InlineTool>
2697
- <For each={loaded()}>
2698
- {(filepath) => (
2699
- <box paddingLeft={3}>
2700
- <text paddingLeft={3} fg={theme.textMuted}>
2701
- ↳ Loaded {normalizePath(filepath)}
2702
- </text>
2703
- </box>
2704
- )}
2705
- </For>
2706
- </>
2707
- )
2708
- }
2709
-
2710
- function Grep(props: ToolProps<typeof GrepTool>) {
2711
- return (
2712
- <InlineTool icon="✱" pending="Searching content..." complete={props.input.pattern} part={props.part}>
2713
- Grep "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
2714
- <Show when={props.metadata.matches}>
2715
- ({props.metadata.matches} {props.metadata.matches === 1 ? "match" : "matches"})
2716
- </Show>
2717
- </InlineTool>
2718
- )
2719
- }
2720
-
2721
- function WebFetch(props: ToolProps<typeof WebFetchTool>) {
2722
- return (
2723
- <InlineTool icon="%" pending="Fetching from the web..." complete={props.input.url} part={props.part}>
2724
- WebFetch {props.input.url}
2725
- </InlineTool>
2726
- )
2727
- }
2728
-
2729
- function CodeSearch(props: ToolProps<typeof CodeSearchTool>) {
2730
- const metadata = props.metadata as { results?: number }
2731
- return (
2732
- <InlineTool icon="◇" pending="Searching code..." complete={props.input.query} part={props.part}>
2733
- Exa Code Search "{props.input.query}" <Show when={metadata.results}>({metadata.results} results)</Show>
2734
- </InlineTool>
2735
- )
2736
- }
2737
-
2738
- function WebSearch(props: ToolProps<typeof WebSearchTool>) {
2739
- const metadata = props.metadata as { numResults?: number }
2740
- return (
2741
- <InlineTool icon="◈" pending="Searching web..." complete={props.input.query} part={props.part}>
2742
- Web Search "{props.input.query}" <Show when={metadata.numResults}>({metadata.numResults} results)</Show>
2743
- </InlineTool>
2744
- )
2745
- }
2746
-
2747
- function Task(props: ToolProps<typeof ActorTool>) {
2748
- const route = useRoute()
2749
- const sync = useSync()
2750
-
2751
- const input = createMemo(() => {
2752
- const raw = props.input as Partial<{ operation: { description: string; subagent_type: string } } & {
2753
- description: string
2754
- subagent_type: string
2755
- }>
2756
- return (raw?.operation ?? raw) as Partial<{ description: string; subagent_type: string }>
2757
- })
2758
-
2759
- const targetSession = createMemo(() => props.metadata.sessionId as string | undefined)
2760
- const targetBucket = createMemo(() => (props.metadata.actorId as string | undefined) ?? "main")
2761
-
2762
- createEffect(() => {
2763
- const session = targetSession()
2764
- const bucket = targetBucket()
2765
- if (session && !sync.data.message[session]?.[bucket]?.length)
2766
- void sync.session.sync(session)
2767
- })
2768
-
2769
- const messages = createMemo(() => sync.data.message[targetSession() ?? ""]?.[targetBucket()] ?? [])
2770
-
2771
- const tools = createMemo(() => {
2772
- return messages().flatMap((msg) =>
2773
- (sync.data.part[msg.id] ?? [])
2774
- .filter((part): part is ToolPart => part.type === "tool")
2775
- .map((part) => ({ tool: part.tool, state: part.state })),
2776
- )
2777
- })
2778
-
2779
- const current = createMemo(() =>
2780
- tools().findLast((x) => (x.state.status === "running" || x.state.status === "completed") && x.state.title),
2781
- )
2782
-
2783
- const isRunning = createMemo(() => props.part.state.status === "running")
2784
-
2785
- const duration = createMemo(() => {
2786
- const first = messages().find((x) => x.role === "user")?.time.created
2787
- const assistant = messages().findLast((x) => x.role === "assistant")?.time.completed
2788
- if (!first || !assistant) return 0
2789
- return assistant - first
2790
- })
2791
-
2792
- const content = createMemo(() => {
2793
- if (!input().description) return ""
2794
- let content = [`${Locale.titlecase(input().subagent_type ?? "General")} Task — ${input().description}`]
2795
-
2796
- if (isRunning() && tools().length > 0) {
2797
- // content[0] += ` · ${tools().length} toolcalls`
2798
- if (current()) {
2799
- const state = current()!.state
2800
- const title = state.status === "running" || state.status === "completed" ? state.title : undefined
2801
- content.push(`↳ ${Locale.titlecase(current()!.tool)} ${title}`)
2802
- } else content.push(`↳ ${tools().length} toolcalls`)
2803
- }
2804
-
2805
- if (props.part.state.status === "completed") {
2806
- content.push(`└ ${tools().length} toolcalls · ${Locale.duration(duration())}`)
2807
- }
2808
-
2809
- return content.join("\n")
2810
- })
2811
-
2812
- return (
2813
- <InlineTool
2814
- icon="│"
2815
- spinner={isRunning()}
2816
- complete={input().description}
2817
- pending="Delegating..."
2818
- part={props.part}
2819
- onClick={() => {
2820
- const session = targetSession()
2821
- if (!session) return
2822
- const actor = targetBucket()
2823
- if (
2824
- route.data.type === "session" &&
2825
- session === route.data.sessionID &&
2826
- actor !== "main"
2827
- ) {
2828
- route.navigate({ ...route.data, agentID: actor })
2829
- return
2830
- }
2831
- route.navigate({ type: "session", sessionID: session, agentID: actor !== "main" ? actor : undefined })
2832
- }}
2833
- >
2834
- {content()}
2835
- </InlineTool>
2836
- )
2837
- }
2838
-
2839
- function Edit(props: ToolProps<typeof EditTool>) {
2840
- const ctx = use()
2841
- const { theme, syntax } = useTheme()
2842
-
2843
- const view = createMemo(() => {
2844
- const diffStyle = ctx.tui.diff_style
2845
- if (diffStyle === "stacked") return "unified"
2846
- // Default to "auto" behavior
2847
- return ctx.width > 120 ? "split" : "unified"
2848
- })
2849
-
2850
- const ft = createMemo(() => filetype(props.input.file_path))
2851
-
2852
- const diffContent = createMemo(() => props.metadata.diff)
2853
-
2854
- return (
2855
- <Switch>
2856
- <Match when={props.metadata.diff !== undefined}>
2857
- <BlockTool title={"← Edit " + normalizePath(props.input.file_path!)} part={props.part}>
2858
- <box paddingLeft={1}>
2859
- <diff
2860
- diff={diffContent()}
2861
- view={view()}
2862
- filetype={ft()}
2863
- syntaxStyle={syntax()}
2864
- showLineNumbers={true}
2865
- width="100%"
2866
- wrapMode={ctx.diffWrapMode()}
2867
- fg={theme.text}
2868
- addedBg={theme.diffAddedBg}
2869
- removedBg={theme.diffRemovedBg}
2870
- contextBg={theme.diffContextBg}
2871
- addedSignColor={theme.diffHighlightAdded}
2872
- removedSignColor={theme.diffHighlightRemoved}
2873
- lineNumberFg={theme.diffLineNumber}
2874
- lineNumberBg={theme.diffContextBg}
2875
- addedLineNumberBg={theme.diffAddedLineNumberBg}
2876
- removedLineNumberBg={theme.diffRemovedLineNumberBg}
2877
- />
2878
- </box>
2879
- <Diagnostics diagnostics={props.metadata.diagnostics} filePath={props.input.file_path ?? ""} />
2880
- </BlockTool>
2881
- </Match>
2882
- <Match when={true}>
2883
- <InlineTool icon="←" pending="Preparing edit..." complete={props.input.file_path} part={props.part}>
2884
- Edit {normalizePath(props.input.file_path!)} {input({ replace_all: props.input.replace_all })}
2885
- </InlineTool>
2886
- </Match>
2887
- </Switch>
2888
- )
2889
- }
2890
-
2891
- function ApplyPatch(props: ToolProps<typeof ApplyPatchTool>) {
2892
- const ctx = use()
2893
- const { theme, syntax } = useTheme()
2894
- const [expanded, setExpanded] = createSignal<string[]>([])
2895
-
2896
- const files = createMemo(() => props.metadata.files ?? [])
2897
-
2898
- const view = createMemo(() => {
2899
- const diffStyle = ctx.tui.diff_style
2900
- if (diffStyle === "stacked") return "unified"
2901
- return ctx.width > 120 ? "split" : "unified"
2902
- })
2903
-
2904
- function Diff(p: { diff: string; filePath: string }) {
2905
- return (
2906
- <box paddingLeft={1}>
2907
- <diff
2908
- diff={p.diff}
2909
- view={view()}
2910
- filetype={filetype(p.filePath)}
2911
- syntaxStyle={syntax()}
2912
- showLineNumbers={true}
2913
- width="100%"
2914
- wrapMode={ctx.diffWrapMode()}
2915
- fg={theme.text}
2916
- addedBg={theme.diffAddedBg}
2917
- removedBg={theme.diffRemovedBg}
2918
- contextBg={theme.diffContextBg}
2919
- addedSignColor={theme.diffHighlightAdded}
2920
- removedSignColor={theme.diffHighlightRemoved}
2921
- lineNumberFg={theme.diffLineNumber}
2922
- lineNumberBg={theme.diffContextBg}
2923
- addedLineNumberBg={theme.diffAddedLineNumberBg}
2924
- removedLineNumberBg={theme.diffRemovedLineNumberBg}
2925
- />
2926
- </box>
2927
- )
2928
- }
2929
-
2930
- function title(file: { type: string; relativePath: string; filePath: string; deletions: number }) {
2931
- if (file.type === "delete") return "# Deleted " + file.relativePath
2932
- if (file.type === "add") return "# Created " + file.relativePath
2933
- if (file.type === "move") return "# Moved " + normalizePath(file.filePath) + " → " + file.relativePath
2934
- return "← Patched " + file.relativePath
2935
- }
2936
-
2937
- function toggle(filePath: string) {
2938
- setExpanded((prev) => (prev.includes(filePath) ? prev.filter((item) => item !== filePath) : [...prev, filePath]))
2939
- }
2940
-
2941
- return (
2942
- <Switch>
2943
- <Match when={files().length > 0}>
2944
- <For each={files()}>
2945
- {(file) => {
2946
- const open = createMemo(() => expanded().includes(file.filePath))
2947
- const count = createMemo(() => file.additions + file.deletions)
2948
- const collapsed = createMemo(() => count() > TOOL_COLLAPSE_MAX_LINES || hasLongDisplayLine(file.patch))
2949
-
2950
- return (
2951
- <BlockTool
2952
- title={title(file)}
2953
- part={props.part}
2954
- onClick={file.type !== "delete" && collapsed() ? () => toggle(file.filePath) : undefined}
2955
- >
2956
- <Show
2957
- when={file.type !== "delete"}
2958
- fallback={
2959
- <text fg={theme.diffRemoved}>
2960
- -{file.deletions} line{file.deletions !== 1 ? "s" : ""}
2961
- </text>
2962
- }
2963
- >
2964
- <Show
2965
- when={!collapsed() || open()}
2966
- fallback={
2967
- <text fg={theme.textMuted}>
2968
- Click to expand ({count()} change{count() !== 1 ? "s" : ""})
2969
- </text>
2970
- }
2971
- >
2972
- <Diff diff={file.patch} filePath={file.filePath} />
2973
- <Show when={collapsed()}>
2974
- <text fg={theme.textMuted}>Click to collapse</text>
2975
- </Show>
2976
- </Show>
2977
- <Diagnostics diagnostics={props.metadata.diagnostics} filePath={file.movePath ?? file.filePath} />
2978
- </Show>
2979
- </BlockTool>
2980
- )
2981
- }}
2982
- </For>
2983
- </Match>
2984
- <Match when={true}>
2985
- <InlineTool icon="%" pending="Preparing patch..." complete={false} part={props.part}>
2986
- Patch
2987
- </InlineTool>
2988
- </Match>
2989
- </Switch>
2990
- )
2991
- }
2992
-
2993
- function Question(props: ToolProps<typeof QuestionTool>) {
2994
- const { theme } = useTheme()
2995
- const count = createMemo(() => props.input.questions?.length ?? 0)
2996
-
2997
- function format(answer?: ReadonlyArray<string>) {
2998
- if (!answer?.length) return "(no answer)"
2999
- return answer.join(", ")
3000
- }
3001
-
3002
- return (
3003
- <Switch>
3004
- <Match when={props.metadata.answers}>
3005
- <BlockTool title="# Questions" part={props.part}>
3006
- <box gap={1}>
3007
- <For each={props.input.questions ?? []}>
3008
- {(q, i) => (
3009
- <box flexDirection="column">
3010
- <text fg={theme.textMuted}>{q.question}</text>
3011
- <text fg={theme.text}>{format(props.metadata.answers?.[i()])}</text>
3012
- </box>
3013
- )}
3014
- </For>
3015
- </box>
3016
- </BlockTool>
3017
- </Match>
3018
- <Match when={true}>
3019
- <InlineTool icon="→" pending="Asking questions..." complete={count()} part={props.part}>
3020
- Asked {count()} question{count() !== 1 ? "s" : ""}
3021
- </InlineTool>
3022
- </Match>
3023
- </Switch>
3024
- )
3025
- }
3026
-
3027
- function Skill(props: ToolProps<typeof SkillTool>) {
3028
- return (
3029
- <InlineTool icon="→" pending="Loading skill..." complete={props.input.name} part={props.part}>
3030
- Skill "{props.input.name}"
3031
- </InlineTool>
3032
- )
3033
- }
3034
-
3035
- function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) {
3036
- const { theme } = useTheme()
3037
- const errors = createMemo(() => {
3038
- const normalized = Filesystem.normalizePath(props.filePath)
3039
- const arr = props.diagnostics?.[normalized] ?? []
3040
- return arr.filter((x) => x.severity === 1).slice(0, 3)
3041
- })
3042
-
3043
- return (
3044
- <Show when={errors().length}>
3045
- <box>
3046
- <For each={errors()}>
3047
- {(diagnostic) => (
3048
- <text fg={theme.error}>
3049
- Error [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}] {diagnostic.message}
3050
- </text>
3051
- )}
3052
- </For>
3053
- </box>
3054
- </Show>
3055
- )
3056
- }
3057
-
3058
- function normalizePath(input?: string) {
3059
- if (!input) return ""
3060
-
3061
- const cwd = process.cwd()
3062
- const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input)
3063
- const relative = path.relative(cwd, absolute)
3064
-
3065
- if (!relative) return "."
3066
- if (!relative.startsWith("..")) return relative
3067
-
3068
- // outside cwd - use absolute
3069
- return absolute
3070
- }
3071
-
3072
- function input(input: Record<string, any>, omit?: string[]): string {
3073
- const primitives = Object.entries(input).filter(([key, value]) => {
3074
- if (omit?.includes(key)) return false
3075
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean"
3076
- })
3077
- if (primitives.length === 0) return ""
3078
- return `[${primitives.map(([key, value]) => `${key}=${value}`).join(", ")}]`
3079
- }
3080
-
3081
- function filetype(input?: string) {
3082
- if (!input) return "none"
3083
- const ext = path.extname(input)
3084
- const language = LANGUAGE_EXTENSIONS[ext]
3085
- if (["typescriptreact", "javascriptreact", "javascript"].includes(language)) return "typescript"
3086
- return language
3087
- }