@alumbwe/anvil 1.0.0

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 (529) hide show
  1. package/README.md +84 -0
  2. package/bin/anvil +2 -0
  3. package/bin/tree-sitter.wasm +0 -0
  4. package/package.json +67 -0
  5. package/src/__tests__/README.md +256 -0
  6. package/src/__tests__/bash-mode.test.ts +442 -0
  7. package/src/__tests__/cli-args.test.ts +181 -0
  8. package/src/__tests__/cli-harness.test.ts +52 -0
  9. package/src/__tests__/e2e/first-time-login.test.ts +173 -0
  10. package/src/__tests__/e2e/logout-relogin-flow.test.ts +110 -0
  11. package/src/__tests__/e2e/returning-user-auth.test.ts +113 -0
  12. package/src/__tests__/e2e-cli.test.ts +183 -0
  13. package/src/__tests__/helpers/launcher-disconnect-fixture.cjs +176 -0
  14. package/src/__tests__/helpers/mock-api-client.ts +64 -0
  15. package/src/__tests__/helpers/renderer-cleanup-fixture.tsx +89 -0
  16. package/src/__tests__/helpers/terminal-watchdog-fixture.ts +75 -0
  17. package/src/__tests__/home-directory-detection.test.ts +213 -0
  18. package/src/__tests__/integration/api-integration.test.ts +288 -0
  19. package/src/__tests__/integration/credentials-storage.test.ts +486 -0
  20. package/src/__tests__/integration/local-agents.test.ts +1187 -0
  21. package/src/__tests__/integration/login-flow-instrumentation.test.ts +134 -0
  22. package/src/__tests__/integration/login-polling-working.test.ts +285 -0
  23. package/src/__tests__/integration/queue-editing.test.tsx +261 -0
  24. package/src/__tests__/integration/usage-refresh-on-completion.test.ts +168 -0
  25. package/src/__tests__/integration-tmux.test.ts +188 -0
  26. package/src/__tests__/launcher-avx2-fallback.test.ts +630 -0
  27. package/src/__tests__/launcher-disconnect.test.ts +104 -0
  28. package/src/__tests__/mocks/hover-toggle-controller.ts +71 -0
  29. package/src/__tests__/open-tui-native-bundle.test.ts +378 -0
  30. package/src/__tests__/path-completion.test.ts +243 -0
  31. package/src/__tests__/project-files-chat-id.test.ts +34 -0
  32. package/src/__tests__/release/proxy-http-get.test.ts +667 -0
  33. package/src/__tests__/release/wrapper-safety.test.ts +412 -0
  34. package/src/__tests__/renderer-cleanup.test.ts +174 -0
  35. package/src/__tests__/rerender-perf.integration.test.ts +283 -0
  36. package/src/__tests__/terminal-reset-sequences.test.ts +36 -0
  37. package/src/__tests__/terminal-watchdog.test.ts +388 -0
  38. package/src/__tests__/test-utils.ts +271 -0
  39. package/src/__tests__/tmux-poc.ts +150 -0
  40. package/src/__tests__/unit/agent-mode-toggle.test.ts +137 -0
  41. package/src/__tests__/unit/copy-button.test.ts +157 -0
  42. package/src/__tests__/unit/create-run-config.test.ts +66 -0
  43. package/src/__tests__/unit/publish-confirmation.test.ts +70 -0
  44. package/src/__tests__/unit/segmented-control.test.ts +152 -0
  45. package/src/__tests__/utils/env.test.ts +169 -0
  46. package/src/__tests__/utils/project-picker.test.ts +39 -0
  47. package/src/agents/bundled-agents.generated.d.ts +14 -0
  48. package/src/agents/bundled-agents.generated.ts +3692 -0
  49. package/src/app.tsx +399 -0
  50. package/src/chat.tsx +1698 -0
  51. package/src/cli-args.ts +134 -0
  52. package/src/commands/__tests__/bash-command.test.ts +445 -0
  53. package/src/commands/__tests__/command-args.test.ts +349 -0
  54. package/src/commands/__tests__/copy-conversation-clipboard.test.ts +108 -0
  55. package/src/commands/__tests__/copy-conversation.test.ts +226 -0
  56. package/src/commands/__tests__/diagnostics-command.test.ts +35 -0
  57. package/src/commands/__tests__/freebuff-command-aliases.test.ts +56 -0
  58. package/src/commands/__tests__/image.test.ts +99 -0
  59. package/src/commands/__tests__/init.test.ts +456 -0
  60. package/src/commands/__tests__/new-command-rotates-chat.test.ts +91 -0
  61. package/src/commands/__tests__/process-diagnostics.test.ts +54 -0
  62. package/src/commands/__tests__/prompt-builders.test.ts +28 -0
  63. package/src/commands/__tests__/router-input.test.ts +298 -0
  64. package/src/commands/ads.ts +44 -0
  65. package/src/commands/command-registry.ts +726 -0
  66. package/src/commands/copy-conversation.ts +392 -0
  67. package/src/commands/help.ts +13 -0
  68. package/src/commands/image.ts +20 -0
  69. package/src/commands/init.ts +121 -0
  70. package/src/commands/process-diagnostics.ts +120 -0
  71. package/src/commands/prompt-builders.ts +100 -0
  72. package/src/commands/publish.ts +203 -0
  73. package/src/commands/router-utils.ts +80 -0
  74. package/src/commands/router.ts +487 -0
  75. package/src/commands/usage.ts +26 -0
  76. package/src/components/__tests__/ad-banner.test.tsx +83 -0
  77. package/src/components/__tests__/chat-input-bar.test.tsx +130 -0
  78. package/src/components/__tests__/freebuff-landing-heading-row.test.tsx +91 -0
  79. package/src/components/__tests__/freebuff-model-selector.test.tsx +519 -0
  80. package/src/components/__tests__/freebuff-offer-invariants.test.ts +54 -0
  81. package/src/components/__tests__/freebuff-takeover-prompt.test.tsx +212 -0
  82. package/src/components/__tests__/grid-layout.integration.test.tsx +304 -0
  83. package/src/components/__tests__/grid-layout.test.tsx +1051 -0
  84. package/src/components/__tests__/message-block.completion.test.tsx +104 -0
  85. package/src/components/__tests__/message-block.streaming.test.tsx +78 -0
  86. package/src/components/__tests__/message-with-agents.test.tsx +579 -0
  87. package/src/components/__tests__/multiline-input.test.tsx +1132 -0
  88. package/src/components/__tests__/queue-panel.test.tsx +398 -0
  89. package/src/components/__tests__/selectable-list.test.ts +232 -0
  90. package/src/components/__tests__/status-bar.test.tsx +44 -0
  91. package/src/components/__tests__/status-indicator.test.tsx +204 -0
  92. package/src/components/__tests__/terminal-thinking-orb.test.tsx +111 -0
  93. package/src/components/__tests__/user-error-banner.test.tsx +102 -0
  94. package/src/components/ad-banner.tsx +323 -0
  95. package/src/components/agent-checklist.tsx +350 -0
  96. package/src/components/agent-mode-toggle.tsx +241 -0
  97. package/src/components/anvil-mark.tsx +52 -0
  98. package/src/components/ask-user/__tests__/multiple-choice-form.test.ts +432 -0
  99. package/src/components/ask-user/__tests__/validation.test.ts +213 -0
  100. package/src/components/ask-user/components/accordion-question.tsx +153 -0
  101. package/src/components/ask-user/components/custom-answer-input.tsx +66 -0
  102. package/src/components/ask-user/components/options-list.tsx +133 -0
  103. package/src/components/ask-user/components/question-header.tsx +80 -0
  104. package/src/components/ask-user/components/question-option.tsx +89 -0
  105. package/src/components/ask-user/constants.ts +38 -0
  106. package/src/components/ask-user/index.tsx +631 -0
  107. package/src/components/ask-user/utils/validation.ts +85 -0
  108. package/src/components/attachment-card.tsx +65 -0
  109. package/src/components/blocks/agent-block-grid.tsx +58 -0
  110. package/src/components/blocks/agent-branch-item.tsx +311 -0
  111. package/src/components/blocks/agent-branch-wrapper.tsx +493 -0
  112. package/src/components/blocks/agent-list-branch.tsx +77 -0
  113. package/src/components/blocks/ask-user-branch.tsx +81 -0
  114. package/src/components/blocks/block-helpers.ts +11 -0
  115. package/src/components/blocks/blocks-renderer.tsx +289 -0
  116. package/src/components/blocks/content-with-markdown.tsx +33 -0
  117. package/src/components/blocks/image-block.tsx +128 -0
  118. package/src/components/blocks/implementor-row.tsx +429 -0
  119. package/src/components/blocks/single-block.tsx +201 -0
  120. package/src/components/blocks/thinking-block.tsx +67 -0
  121. package/src/components/blocks/tool-block-group.tsx +57 -0
  122. package/src/components/blocks/tool-branch.tsx +206 -0
  123. package/src/components/blocks/user-content-copy.tsx +157 -0
  124. package/src/components/bottom-banner.tsx +136 -0
  125. package/src/components/build-mode-buttons.tsx +110 -0
  126. package/src/components/button.tsx +66 -0
  127. package/src/components/chat-header.tsx +77 -0
  128. package/src/components/chat-history-screen.tsx +413 -0
  129. package/src/components/chat-input-bar.tsx +523 -0
  130. package/src/components/clickable-title-box.tsx +66 -0
  131. package/src/components/clickable.tsx +119 -0
  132. package/src/components/collapse-button.tsx +34 -0
  133. package/src/components/copy-button.tsx +203 -0
  134. package/src/components/elapsed-timer.tsx +55 -0
  135. package/src/components/error-boundary.tsx +55 -0
  136. package/src/components/feedback-container.tsx +181 -0
  137. package/src/components/feedback-icon-button.tsx +89 -0
  138. package/src/components/feedback-input-mode.tsx +344 -0
  139. package/src/components/file-attachment-card.tsx +98 -0
  140. package/src/components/freebuff-active-session-summary.tsx +63 -0
  141. package/src/components/freebuff-landing-screen.tsx +865 -0
  142. package/src/components/freebuff-model-selector.tsx +1087 -0
  143. package/src/components/freebuff-referral-banner.tsx +604 -0
  144. package/src/components/freebuff-superseded-screen.tsx +62 -0
  145. package/src/components/grid-layout.tsx +80 -0
  146. package/src/components/help-banner.tsx +127 -0
  147. package/src/components/highlighted-text.tsx +52 -0
  148. package/src/components/image-card.tsx +167 -0
  149. package/src/components/image-thumbnail.tsx +114 -0
  150. package/src/components/input-cursor.tsx +77 -0
  151. package/src/components/input-mode-banner.tsx +57 -0
  152. package/src/components/load-previous-button.tsx +48 -0
  153. package/src/components/login-modal.tsx +475 -0
  154. package/src/components/message-block.tsx +346 -0
  155. package/src/components/message-footer.tsx +258 -0
  156. package/src/components/message-with-agents.tsx +506 -0
  157. package/src/components/mode-divider.tsx +43 -0
  158. package/src/components/multiline-input.tsx +1241 -0
  159. package/src/components/out-of-credits-banner.tsx +160 -0
  160. package/src/components/pending-attachments-banner.tsx +116 -0
  161. package/src/components/pending-bash-message.tsx +59 -0
  162. package/src/components/progress-bar.tsx +81 -0
  163. package/src/components/project-picker-screen.tsx +485 -0
  164. package/src/components/publish-confirmation.tsx +493 -0
  165. package/src/components/publish-container.tsx +687 -0
  166. package/src/components/queue-panel.tsx +310 -0
  167. package/src/components/raised-pill.tsx +95 -0
  168. package/src/components/renderers/plan-box.tsx +59 -0
  169. package/src/components/review-screen.tsx +112 -0
  170. package/src/components/scroll-to-bottom-button.tsx +34 -0
  171. package/src/components/segmented-control.tsx +187 -0
  172. package/src/components/selectable-list.tsx +248 -0
  173. package/src/components/selected-chips.tsx +80 -0
  174. package/src/components/separator.tsx +40 -0
  175. package/src/components/session-ended-banner.tsx +226 -0
  176. package/src/components/shimmer-text.tsx +248 -0
  177. package/src/components/status-bar.tsx +313 -0
  178. package/src/components/subscription-limit-banner.tsx +206 -0
  179. package/src/components/suggested-prompts.tsx +184 -0
  180. package/src/components/suggestion-menu.tsx +215 -0
  181. package/src/components/terminal-command-display.tsx +151 -0
  182. package/src/components/terminal-link.tsx +97 -0
  183. package/src/components/terminal-thinking-orb.tsx +95 -0
  184. package/src/components/text-attachment-card.tsx +77 -0
  185. package/src/components/thinking.tsx +109 -0
  186. package/src/components/tools/__tests__/apply-patch.test.tsx +84 -0
  187. package/src/components/tools/__tests__/code-search.test.tsx +45 -0
  188. package/src/components/tools/__tests__/gravity-index.test.ts +76 -0
  189. package/src/components/tools/__tests__/render-ui.test.tsx +92 -0
  190. package/src/components/tools/__tests__/run-terminal-command.test.ts +233 -0
  191. package/src/components/tools/apply-patch.tsx +95 -0
  192. package/src/components/tools/code-search.tsx +45 -0
  193. package/src/components/tools/composio.tsx +152 -0
  194. package/src/components/tools/diff-viewer.tsx +76 -0
  195. package/src/components/tools/glob.tsx +61 -0
  196. package/src/components/tools/gravity-index.tsx +77 -0
  197. package/src/components/tools/list-directory.tsx +61 -0
  198. package/src/components/tools/read-docs.tsx +37 -0
  199. package/src/components/tools/read-files.tsx +91 -0
  200. package/src/components/tools/read-subtree.tsx +44 -0
  201. package/src/components/tools/read-url.tsx +33 -0
  202. package/src/components/tools/registry.ts +126 -0
  203. package/src/components/tools/render-ui.tsx +122 -0
  204. package/src/components/tools/run-terminal-command.tsx +79 -0
  205. package/src/components/tools/skill.tsx +29 -0
  206. package/src/components/tools/str-replace.tsx +77 -0
  207. package/src/components/tools/suggest-followups.tsx +369 -0
  208. package/src/components/tools/task-completed.tsx +16 -0
  209. package/src/components/tools/tool-call-item.tsx +273 -0
  210. package/src/components/tools/types.ts +55 -0
  211. package/src/components/tools/web-search.tsx +33 -0
  212. package/src/components/tools/write-file.tsx +16 -0
  213. package/src/components/tools/write-todos.tsx +95 -0
  214. package/src/components/top-banner.tsx +178 -0
  215. package/src/components/usage-banner.tsx +244 -0
  216. package/src/components/user-error-banner.tsx +56 -0
  217. package/src/components/validation-error-popover.tsx +192 -0
  218. package/src/contexts/__tests__/chat-runtime-context.test.tsx +149 -0
  219. package/src/contexts/chat-runtime-context.tsx +240 -0
  220. package/src/data/slash-commands.test.ts +24 -0
  221. package/src/data/slash-commands.ts +249 -0
  222. package/src/entry.ts +12 -0
  223. package/src/hooks/__tests__/holds-live-freebuff-slot.test.ts +49 -0
  224. package/src/hooks/__tests__/session-fetch-signal.test.ts +63 -0
  225. package/src/hooks/__tests__/use-activity-query.test.ts +1000 -0
  226. package/src/hooks/__tests__/use-ask-user-bridge.test.ts +176 -0
  227. package/src/hooks/__tests__/use-auth-query.test.ts +21 -0
  228. package/src/hooks/__tests__/use-chat-input-remount.test.tsx +66 -0
  229. package/src/hooks/__tests__/use-clipboard.test.tsx +73 -0
  230. package/src/hooks/__tests__/use-connection-status.test.ts +112 -0
  231. package/src/hooks/__tests__/use-directory-browser.test.ts +203 -0
  232. package/src/hooks/__tests__/use-gravity-ad.test.ts +73 -0
  233. package/src/hooks/__tests__/use-grid-layout.test.ts +349 -0
  234. package/src/hooks/__tests__/use-input-history.test.ts +699 -0
  235. package/src/hooks/__tests__/use-message-queue-editing.test.tsx +209 -0
  236. package/src/hooks/__tests__/use-message-queue.test.tsx +71 -0
  237. package/src/hooks/__tests__/use-path-tab-completion.test.ts +315 -0
  238. package/src/hooks/__tests__/use-queue-controls.test.ts +68 -0
  239. package/src/hooks/__tests__/use-queue-ui.test.tsx +83 -0
  240. package/src/hooks/__tests__/use-searchable-list.test.ts +359 -0
  241. package/src/hooks/__tests__/use-send-message-timer.test.ts +146 -0
  242. package/src/hooks/__tests__/use-suggestion-engine-mention.test.ts +361 -0
  243. package/src/hooks/__tests__/use-suggestion-engine.test.ts +485 -0
  244. package/src/hooks/__tests__/use-terminal-focus.test.ts +66 -0
  245. package/src/hooks/__tests__/use-terminal-layout.test.ts +675 -0
  246. package/src/hooks/__tests__/use-timeout.test.ts +330 -0
  247. package/src/hooks/__tests__/use-usage-query.test.ts +502 -0
  248. package/src/hooks/__tests__/use-user-details-query.test.ts +195 -0
  249. package/src/hooks/helpers/__tests__/send-message.test.ts +1918 -0
  250. package/src/hooks/helpers/send-message.ts +654 -0
  251. package/src/hooks/stream-state.ts +83 -0
  252. package/src/hooks/use-activity-query.ts +668 -0
  253. package/src/hooks/use-agent-validation.ts +74 -0
  254. package/src/hooks/use-ask-user-bridge.ts +92 -0
  255. package/src/hooks/use-auth-query.ts +253 -0
  256. package/src/hooks/use-auth-state.ts +152 -0
  257. package/src/hooks/use-chat-input.ts +105 -0
  258. package/src/hooks/use-chat-keyboard.ts +321 -0
  259. package/src/hooks/use-chat-messages.ts +254 -0
  260. package/src/hooks/use-chat-state.ts +165 -0
  261. package/src/hooks/use-chat-streaming.ts +180 -0
  262. package/src/hooks/use-chat-ui.ts +131 -0
  263. package/src/hooks/use-clipboard.ts +151 -0
  264. package/src/hooks/use-connection-status.ts +142 -0
  265. package/src/hooks/use-directory-browser.ts +88 -0
  266. package/src/hooks/use-elapsed-time.ts +116 -0
  267. package/src/hooks/use-event.ts +34 -0
  268. package/src/hooks/use-exit-handler.ts +66 -0
  269. package/src/hooks/use-fetch-login-url.ts +65 -0
  270. package/src/hooks/use-fingerprint.ts +61 -0
  271. package/src/hooks/use-freebuff-ctrl-c-exit.ts +23 -0
  272. package/src/hooks/use-freebuff-session-progress.ts +34 -0
  273. package/src/hooks/use-freebuff-session.ts +806 -0
  274. package/src/hooks/use-freebuff-streak-query.ts +61 -0
  275. package/src/hooks/use-gravity-ad.ts +656 -0
  276. package/src/hooks/use-grid-layout.ts +73 -0
  277. package/src/hooks/use-input-history.ts +173 -0
  278. package/src/hooks/use-login-keyboard-handlers.ts +75 -0
  279. package/src/hooks/use-login-polling.ts +114 -0
  280. package/src/hooks/use-logo.tsx +161 -0
  281. package/src/hooks/use-message-queue.ts +387 -0
  282. package/src/hooks/use-now.ts +20 -0
  283. package/src/hooks/use-path-tab-completion.ts +88 -0
  284. package/src/hooks/use-publish-mutation.ts +60 -0
  285. package/src/hooks/use-queue-controls.ts +68 -0
  286. package/src/hooks/use-queue-ui.ts +74 -0
  287. package/src/hooks/use-scroll-management.ts +184 -0
  288. package/src/hooks/use-searchable-list.ts +98 -0
  289. package/src/hooks/use-send-message.ts +773 -0
  290. package/src/hooks/use-sheen-animation.tsx +88 -0
  291. package/src/hooks/use-subscription-query.ts +71 -0
  292. package/src/hooks/use-suggestion-engine.ts +783 -0
  293. package/src/hooks/use-terminal-breakpoints.ts +77 -0
  294. package/src/hooks/use-terminal-dimensions.ts +46 -0
  295. package/src/hooks/use-terminal-focus.ts +29 -0
  296. package/src/hooks/use-terminal-layout.ts +189 -0
  297. package/src/hooks/use-theme.tsx +140 -0
  298. package/src/hooks/use-timeout.ts +85 -0
  299. package/src/hooks/use-update-preference.ts +66 -0
  300. package/src/hooks/use-usage-monitor.ts +55 -0
  301. package/src/hooks/use-usage-query.ts +124 -0
  302. package/src/hooks/use-user-details-query.ts +93 -0
  303. package/src/hooks/use-why-did-you-update.ts +177 -0
  304. package/src/index.tsx +441 -0
  305. package/src/init/__tests__/init-direnv.test.ts +526 -0
  306. package/src/init/init-app.ts +34 -0
  307. package/src/init/init-direnv.ts +133 -0
  308. package/src/login/constants.ts +60 -0
  309. package/src/login/login-flow.ts +204 -0
  310. package/src/login/plain-login.ts +108 -0
  311. package/src/login/utils.ts +183 -0
  312. package/src/native/ripgrep.ts +80 -0
  313. package/src/polyfills/bun-strip-ansi.ts +12 -0
  314. package/src/pre-init/tree-sitter-wasm.ts +96 -0
  315. package/src/project-files.ts +102 -0
  316. package/src/smoke/terminal-command-broker.ts +439 -0
  317. package/src/state/__tests__/chat-store-focus.test.ts +22 -0
  318. package/src/state/__tests__/feedback-store.test.ts +257 -0
  319. package/src/state/chat-history-store.ts +30 -0
  320. package/src/state/chat-store.ts +544 -0
  321. package/src/state/feedback-store.ts +160 -0
  322. package/src/state/freebuff-model-store.ts +42 -0
  323. package/src/state/freebuff-session-store.ts +53 -0
  324. package/src/state/login-store.ts +150 -0
  325. package/src/state/message-block-store.ts +149 -0
  326. package/src/state/publish-store.ts +146 -0
  327. package/src/state/queue-panel-store.ts +26 -0
  328. package/src/state/review-store.ts +24 -0
  329. package/src/testing/env.ts +46 -0
  330. package/src/types/chat-state.ts +15 -0
  331. package/src/types/chat.ts +241 -0
  332. package/src/types/contracts/send-message.ts +12 -0
  333. package/src/types/env.ts +98 -0
  334. package/src/types/freebuff-session.ts +17 -0
  335. package/src/types/function-params.ts +28 -0
  336. package/src/types/react19-compat.d.ts +19 -0
  337. package/src/types/store.ts +111 -0
  338. package/src/types/theme-system.ts +144 -0
  339. package/src/types/utils.ts +3 -0
  340. package/src/utils/__tests__/active-run.test.ts +140 -0
  341. package/src/utils/__tests__/activity-tracker.test.ts +440 -0
  342. package/src/utils/__tests__/agent-display.test.ts +139 -0
  343. package/src/utils/__tests__/analytics-client.test.ts +262 -0
  344. package/src/utils/__tests__/anonymous-id.test.ts +74 -0
  345. package/src/utils/__tests__/anvil-api.test.ts +578 -0
  346. package/src/utils/__tests__/arrays.test.ts +264 -0
  347. package/src/utils/__tests__/bash-context-processor.test.ts +38 -0
  348. package/src/utils/__tests__/block-processor.test.ts +810 -0
  349. package/src/utils/__tests__/chat-history.test.ts +203 -0
  350. package/src/utils/__tests__/chat-input-key-intercept.test.ts +40 -0
  351. package/src/utils/__tests__/chat-meta.test.ts +130 -0
  352. package/src/utils/__tests__/clipboard-linux.test.ts +359 -0
  353. package/src/utils/__tests__/clipboard.test.ts +910 -0
  354. package/src/utils/__tests__/code-search-summary.test.ts +84 -0
  355. package/src/utils/__tests__/collapse-helpers.test.ts +1109 -0
  356. package/src/utils/__tests__/error-handling.test.ts +658 -0
  357. package/src/utils/__tests__/exit-cleanly.test.ts +110 -0
  358. package/src/utils/__tests__/feedback-helpers.test.ts +444 -0
  359. package/src/utils/__tests__/feedback-submission.test.ts +26 -0
  360. package/src/utils/__tests__/fetch-usage.test.ts +355 -0
  361. package/src/utils/__tests__/fingerprint.test.ts +144 -0
  362. package/src/utils/__tests__/fixtures/terminal-command-broker-child.ts +7 -0
  363. package/src/utils/__tests__/fixtures/terminal-command-broker-entry.ts +3 -0
  364. package/src/utils/__tests__/fixtures/terminal-command-broker-owner.ts +33 -0
  365. package/src/utils/__tests__/format-elapsed-time.test.ts +103 -0
  366. package/src/utils/__tests__/format-timeout.test.ts +87 -0
  367. package/src/utils/__tests__/freebuff-instance-owner.test.ts +69 -0
  368. package/src/utils/__tests__/freebuff-model-navigation.test.ts +102 -0
  369. package/src/utils/__tests__/freebuff-premium-reset.test.ts +79 -0
  370. package/src/utils/__tests__/freebuff-referral-cache.test.ts +116 -0
  371. package/src/utils/__tests__/freebuff-session-api.test.ts +215 -0
  372. package/src/utils/__tests__/freebuff-session-display.test.ts +23 -0
  373. package/src/utils/__tests__/freebuff-streak-line.test.ts +217 -0
  374. package/src/utils/__tests__/image-dimensions.test.ts +249 -0
  375. package/src/utils/__tests__/image-processor.test.ts +209 -0
  376. package/src/utils/__tests__/implementor-helpers.test.ts +1458 -0
  377. package/src/utils/__tests__/keyboard-actions.test.ts +660 -0
  378. package/src/utils/__tests__/layout-helpers.test.ts +36 -0
  379. package/src/utils/__tests__/lazy-response-ads.test.ts +167 -0
  380. package/src/utils/__tests__/log-shipper.test.ts +53 -0
  381. package/src/utils/__tests__/markdown-renderer.test.tsx +421 -0
  382. package/src/utils/__tests__/message-block-helpers.test.ts +1263 -0
  383. package/src/utils/__tests__/message-updater.test.ts +645 -0
  384. package/src/utils/__tests__/osc-timeout-scenarios.test.ts +172 -0
  385. package/src/utils/__tests__/pending-attachments.test.ts +277 -0
  386. package/src/utils/__tests__/polling-backoff.test.ts +51 -0
  387. package/src/utils/__tests__/queue-panel-actions.test.ts +148 -0
  388. package/src/utils/__tests__/run-state-storage.test.ts +919 -0
  389. package/src/utils/__tests__/safe-json.test.ts +77 -0
  390. package/src/utils/__tests__/sdk-event-handlers.test.ts +685 -0
  391. package/src/utils/__tests__/send-message-helpers.test.ts +1898 -0
  392. package/src/utils/__tests__/send-message-timer.test.ts +64 -0
  393. package/src/utils/__tests__/settings.test.ts +99 -0
  394. package/src/utils/__tests__/strings.test.ts +192 -0
  395. package/src/utils/__tests__/terminal-color-detection.test.ts +425 -0
  396. package/src/utils/__tests__/terminal-command-broker.test.ts +528 -0
  397. package/src/utils/__tests__/terminal-enter-detection.test.ts +77 -0
  398. package/src/utils/__tests__/terminal-io.test.ts +137 -0
  399. package/src/utils/__tests__/terminal-protocol-controller.test.ts +119 -0
  400. package/src/utils/__tests__/text-layout.test.ts +82 -0
  401. package/src/utils/__tests__/theme-platform-detection.test.ts +125 -0
  402. package/src/utils/__tests__/think-tag-parser.test.ts +159 -0
  403. package/src/utils/__tests__/trace-writer.test.ts +223 -0
  404. package/src/utils/__tests__/trim-chat-logs.test.ts +78 -0
  405. package/src/utils/__tests__/usage-banner-state.test.ts +298 -0
  406. package/src/utils/__tests__/validation-error-formatting.test.ts +126 -0
  407. package/src/utils/__tests__/windows-terminal-health.test.ts +101 -0
  408. package/src/utils/__tests__/write-file-atomic.test.ts +127 -0
  409. package/src/utils/active-run.ts +131 -0
  410. package/src/utils/activity-tracker.ts +66 -0
  411. package/src/utils/agent-display.ts +87 -0
  412. package/src/utils/agent-helpers.ts +27 -0
  413. package/src/utils/agent-id-utils.ts +14 -0
  414. package/src/utils/ai-message-id.ts +12 -0
  415. package/src/utils/analytics.ts +361 -0
  416. package/src/utils/anonymous-id.ts +87 -0
  417. package/src/utils/anvil-api.ts +612 -0
  418. package/src/utils/anvil-client.ts +217 -0
  419. package/src/utils/arrays.ts +117 -0
  420. package/src/utils/auth.ts +258 -0
  421. package/src/utils/bash-context-processor.ts +47 -0
  422. package/src/utils/bash-messages.ts +108 -0
  423. package/src/utils/block-margins.ts +35 -0
  424. package/src/utils/block-operations.ts +523 -0
  425. package/src/utils/block-processor.ts +213 -0
  426. package/src/utils/chat-history.ts +253 -0
  427. package/src/utils/chat-input-key-intercept.ts +52 -0
  428. package/src/utils/chat-meta.ts +90 -0
  429. package/src/utils/chat-scroll-accel.ts +151 -0
  430. package/src/utils/clipboard-image.ts +588 -0
  431. package/src/utils/clipboard.ts +397 -0
  432. package/src/utils/code-search-summary.ts +70 -0
  433. package/src/utils/collapse-helpers.ts +256 -0
  434. package/src/utils/config-dir.ts +24 -0
  435. package/src/utils/constants.ts +190 -0
  436. package/src/utils/create-event-handler-state.ts +73 -0
  437. package/src/utils/create-run-config.ts +121 -0
  438. package/src/utils/detect-shell.ts +116 -0
  439. package/src/utils/directory-browser.ts +72 -0
  440. package/src/utils/engagement.ts +55 -0
  441. package/src/utils/env.ts +92 -0
  442. package/src/utils/error-handling.ts +255 -0
  443. package/src/utils/error-messages.ts +62 -0
  444. package/src/utils/exit-cleanly.ts +86 -0
  445. package/src/utils/feedback-helpers.ts +103 -0
  446. package/src/utils/feedback-submission.ts +22 -0
  447. package/src/utils/fetch-usage.ts +76 -0
  448. package/src/utils/fingerprint.ts +245 -0
  449. package/src/utils/format-elapsed-time.ts +33 -0
  450. package/src/utils/format-session-units.ts +6 -0
  451. package/src/utils/format-timeout.ts +28 -0
  452. package/src/utils/format-validation-errors-for-message.ts +84 -0
  453. package/src/utils/freebuff-agent-selection.ts +33 -0
  454. package/src/utils/freebuff-instance-owner.ts +66 -0
  455. package/src/utils/freebuff-model-navigation.ts +50 -0
  456. package/src/utils/freebuff-premium-reset.ts +55 -0
  457. package/src/utils/freebuff-referral-cache.ts +51 -0
  458. package/src/utils/freebuff-session-api.ts +243 -0
  459. package/src/utils/freebuff-session-display.ts +21 -0
  460. package/src/utils/freebuff-streak-line.ts +93 -0
  461. package/src/utils/git.ts +17 -0
  462. package/src/utils/helpers.ts +47 -0
  463. package/src/utils/image-display.ts +67 -0
  464. package/src/utils/image-handler.ts +325 -0
  465. package/src/utils/image-processor.ts +133 -0
  466. package/src/utils/image-thumbnail.ts +78 -0
  467. package/src/utils/implementor-helpers.ts +787 -0
  468. package/src/utils/input-modes.ts +174 -0
  469. package/src/utils/keyboard-actions.ts +392 -0
  470. package/src/utils/keypad-keys.ts +47 -0
  471. package/src/utils/layout-helpers.ts +33 -0
  472. package/src/utils/lazy-response-ads.ts +1 -0
  473. package/src/utils/local-agent-registry.ts +474 -0
  474. package/src/utils/log-shipper.ts +126 -0
  475. package/src/utils/logger.ts +327 -0
  476. package/src/utils/markdown-renderer.tsx +1090 -0
  477. package/src/utils/math.ts +3 -0
  478. package/src/utils/message-block-helpers.ts +684 -0
  479. package/src/utils/message-history.ts +143 -0
  480. package/src/utils/message-tree-utils.ts +67 -0
  481. package/src/utils/message-updater.ts +279 -0
  482. package/src/utils/open-file.ts +146 -0
  483. package/src/utils/open-url.ts +63 -0
  484. package/src/utils/path-completion.ts +111 -0
  485. package/src/utils/path-helpers.ts +38 -0
  486. package/src/utils/pending-attachments.ts +360 -0
  487. package/src/utils/polling-backoff.ts +59 -0
  488. package/src/utils/project-picker.ts +12 -0
  489. package/src/utils/queue-panel-actions.ts +70 -0
  490. package/src/utils/recent-projects.ts +156 -0
  491. package/src/utils/renderer-cleanup.ts +233 -0
  492. package/src/utils/response-ad-positions.ts +1 -0
  493. package/src/utils/run-state-storage.ts +603 -0
  494. package/src/utils/safe-json.ts +153 -0
  495. package/src/utils/sdk-event-handlers.ts +571 -0
  496. package/src/utils/send-message-helpers.ts +210 -0
  497. package/src/utils/send-message-timer.ts +110 -0
  498. package/src/utils/settings.ts +226 -0
  499. package/src/utils/skill-registry.ts +94 -0
  500. package/src/utils/spawn-agent-matcher.ts +55 -0
  501. package/src/utils/status-indicator-state.ts +107 -0
  502. package/src/utils/stream-chunk-processor.ts +57 -0
  503. package/src/utils/strings.ts +271 -0
  504. package/src/utils/subscription.ts +31 -0
  505. package/src/utils/syntax-highlighter.tsx +19 -0
  506. package/src/utils/terminal-color-detection.ts +474 -0
  507. package/src/utils/terminal-command-broker.ts +467 -0
  508. package/src/utils/terminal-enter-detection.ts +63 -0
  509. package/src/utils/terminal-images.ts +229 -0
  510. package/src/utils/terminal-io.ts +85 -0
  511. package/src/utils/terminal-protocol-controller.ts +173 -0
  512. package/src/utils/terminal-reset-sequences.ts +33 -0
  513. package/src/utils/terminal-title.ts +84 -0
  514. package/src/utils/terminal-watchdog.ts +366 -0
  515. package/src/utils/text-layout.ts +149 -0
  516. package/src/utils/theme-config.ts +141 -0
  517. package/src/utils/theme-system.ts +1206 -0
  518. package/src/utils/think-tag-parser.ts +95 -0
  519. package/src/utils/time-format.ts +21 -0
  520. package/src/utils/trace-writer.ts +162 -0
  521. package/src/utils/ui-constants.ts +69 -0
  522. package/src/utils/update-checker.ts +110 -0
  523. package/src/utils/usage-banner-state.ts +146 -0
  524. package/src/utils/validation-error-formatting.ts +86 -0
  525. package/src/utils/validation-error-helpers.ts +19 -0
  526. package/src/utils/windows-terminal-health.ts +124 -0
  527. package/src/utils/word-wrap-utils.ts +53 -0
  528. package/src/utils/write-file-atomic.ts +54 -0
  529. package/src/utils/yield-to-event-loop.ts +9 -0
@@ -0,0 +1,95 @@
1
+ import { TextAttributes } from '@opentui/core'
2
+
3
+ import { DiffViewer } from './diff-viewer'
4
+ import { defineToolComponent } from './types'
5
+ import { useTheme } from '../../hooks/use-theme'
6
+
7
+ import type { ToolRenderConfig } from './types'
8
+
9
+ type PatchOperation =
10
+ | { type: 'create_file'; path: string; diff: string }
11
+ | { type: 'update_file'; path: string; diff: string }
12
+ | { type: 'delete_file'; path: string }
13
+
14
+ function parseOperation(input: unknown): PatchOperation | null {
15
+ if (!input || typeof input !== 'object') return null
16
+ const op = (input as { operation?: unknown }).operation
17
+ if (!op || typeof op !== 'object') return null
18
+ const { type, path, diff } = op as Record<string, unknown>
19
+ if (typeof type !== 'string' || typeof path !== 'string') return null
20
+ if (type === 'create_file' && typeof diff === 'string') {
21
+ return { type: 'create_file', path, diff }
22
+ }
23
+ if (type === 'update_file' && typeof diff === 'string') {
24
+ return { type: 'update_file', path, diff }
25
+ }
26
+ if (type === 'delete_file') {
27
+ return { type: 'delete_file', path }
28
+ }
29
+ return null
30
+ }
31
+
32
+ interface EditHeaderProps {
33
+ name: string
34
+ filePath: string
35
+ }
36
+
37
+ const EditHeader = ({ name, filePath }: EditHeaderProps) => {
38
+ const theme = useTheme()
39
+ const bulletChar = '• '
40
+
41
+ return (
42
+ <box style={{ flexDirection: 'row', alignItems: 'center', width: '100%' }}>
43
+ <text style={{ wrapMode: 'word' }}>
44
+ <span fg={theme.foreground}>{bulletChar}</span>
45
+ <span fg={theme.foreground} attributes={TextAttributes.BOLD}>
46
+ {name}
47
+ </span>
48
+ <span fg={theme.foreground}>{` ${filePath}`}</span>
49
+ </text>
50
+ </box>
51
+ )
52
+ }
53
+
54
+ interface PatchOperationItemProps {
55
+ operation: PatchOperation
56
+ }
57
+
58
+ const PatchOperationItem = ({ operation }: PatchOperationItemProps) => {
59
+ if (operation.type === 'create_file') {
60
+ return <EditHeader name="Create" filePath={operation.path} />
61
+ }
62
+
63
+ if (operation.type === 'delete_file') {
64
+ return <EditHeader name="Delete" filePath={operation.path} />
65
+ }
66
+
67
+ return (
68
+ <box style={{ flexDirection: 'column', width: '100%' }}>
69
+ <EditHeader name="Edit" filePath={operation.path} />
70
+ <box style={{ paddingLeft: 2, width: '100%' }}>
71
+ <DiffViewer diffText={operation.diff} />
72
+ </box>
73
+ </box>
74
+ )
75
+ }
76
+
77
+ export const ApplyPatchComponent = defineToolComponent({
78
+ toolName: 'apply_patch',
79
+
80
+ render(toolBlock): ToolRenderConfig {
81
+ const operation = parseOperation(toolBlock.input)
82
+
83
+ if (!operation) {
84
+ return { content: null }
85
+ }
86
+
87
+ return {
88
+ content: (
89
+ <box style={{ flexDirection: 'column', gap: 0, width: '100%' }}>
90
+ <PatchOperationItem operation={operation} />
91
+ </box>
92
+ ),
93
+ }
94
+ },
95
+ })
@@ -0,0 +1,45 @@
1
+ import React from 'react'
2
+
3
+ import { SimpleToolCallItem } from './tool-call-item'
4
+ import { defineToolComponent } from './types'
5
+ import { countCodeSearchResults } from '../../utils/code-search-summary'
6
+
7
+ import type { ToolRenderConfig } from './types'
8
+
9
+ /**
10
+ * UI component for code_search tool.
11
+ * Displays a single line showing the search pattern, flags, and number of results.
12
+ * Does not support expand/collapse - always shows as a single line.
13
+ */
14
+ export const CodeSearchComponent = defineToolComponent({
15
+ toolName: 'code_search',
16
+
17
+ render(toolBlock): ToolRenderConfig {
18
+ const input = toolBlock.input as any
19
+ const pattern = input?.pattern ?? ''
20
+ const cwd = input?.cwd ?? ''
21
+
22
+ const totalResults = countCodeSearchResults(toolBlock.output)
23
+
24
+ // Build single-line summary
25
+ let summary = ''
26
+
27
+ summary += `${pattern}`
28
+
29
+ if (cwd) {
30
+ summary += ` in ${cwd}`
31
+ }
32
+
33
+ // Disable showing flags since they are noisy.
34
+ // if (flags) {
35
+ // summary += ` ${flags}`
36
+ // }
37
+
38
+ summary += ` (${totalResults} result${totalResults === 1 ? '' : 's'})`
39
+
40
+ // Return as content using SimpleToolCallItem
41
+ return {
42
+ content: <SimpleToolCallItem name="Search" description={summary} />,
43
+ }
44
+ },
45
+ })
@@ -0,0 +1,152 @@
1
+ import { SimpleToolCallItem } from './tool-call-item'
2
+ import { defineToolComponent } from './types'
3
+
4
+ import type { ToolBlock, ToolRenderConfig } from './types'
5
+
6
+ /**
7
+ * Formats an array of items as a comma-separated list, truncated to maxItems.
8
+ */
9
+ function formatList(items: string[], maxItems = 3): string {
10
+ if (items.length === 0) return ''
11
+ const shown = items.slice(0, maxItems)
12
+ const remainder = items.length - shown.length
13
+ const suffix = remainder > 0 ? ` +${remainder} more` : ''
14
+ return shown.join(', ') + suffix
15
+ }
16
+
17
+ /**
18
+ * UI component for composio_manage_connections tool.
19
+ * Shows "App Connections" with the toolkit names being connected.
20
+ */
21
+ export const ManageConnectionsComponent = defineToolComponent({
22
+ toolName: 'composio_manage_connections',
23
+
24
+ render(toolBlock: ToolBlock & { toolName: 'composio_manage_connections' }): ToolRenderConfig {
25
+ const input = toolBlock.input as {
26
+ toolkits?: string[]
27
+ reinitiate_all?: boolean
28
+ } | undefined
29
+ const toolkits = input?.toolkits ?? []
30
+ const description = toolkits.length > 0 ? formatList(toolkits) : ''
31
+
32
+ return {
33
+ content: (
34
+ <SimpleToolCallItem name="App Connections" description={description} />
35
+ ),
36
+ collapsedPreview: description,
37
+ }
38
+ },
39
+ })
40
+
41
+ /**
42
+ * Stringify a non-string tool value for display, breaking cycles so a raw
43
+ * composio result can't throw during the TUI render.
44
+ */
45
+ function stringifyToolValue(value: unknown): string {
46
+ if (typeof value === 'string') return value
47
+ try {
48
+ return JSON.stringify(value)
49
+ } catch {
50
+ const ancestors: unknown[] = []
51
+ return JSON.stringify(value, function (this: unknown, _key, val) {
52
+ if (ancestors.length > 0) {
53
+ const thisPos = ancestors.indexOf(this)
54
+ if (thisPos !== -1) {
55
+ ancestors.splice(thisPos + 1)
56
+ } else {
57
+ ancestors.push(this)
58
+ }
59
+ if (
60
+ typeof val === 'object' &&
61
+ val !== null &&
62
+ ancestors.includes(val)
63
+ ) {
64
+ return '[Circular]'
65
+ }
66
+ } else {
67
+ ancestors.push(val)
68
+ }
69
+ return val
70
+ })
71
+ }
72
+ }
73
+
74
+ /**
75
+ * UI component for composio_multi_execute_tool tool.
76
+ * Shows "App Action" with the thought or tool slugs being executed.
77
+ */
78
+ export const ExecuteToolComponent = defineToolComponent({
79
+ toolName: 'composio_multi_execute_tool',
80
+
81
+ render(toolBlock: ToolBlock & { toolName: 'composio_multi_execute_tool' }): ToolRenderConfig {
82
+ const input = toolBlock.input as {
83
+ tools?: Array<Record<string, unknown>>
84
+ thought?: string
85
+ } | undefined
86
+ const tools = input?.tools ?? []
87
+ const thought = input?.thought
88
+
89
+ // Prefer the thought as description, otherwise extract tool slugs
90
+ const description =
91
+ thought ??
92
+ (tools.length > 0
93
+ ? formatList(tools.map((t) => stringifyToolValue(t.slug)))
94
+ : '')
95
+
96
+ return {
97
+ content: (
98
+ <SimpleToolCallItem name="App Action" description={description} />
99
+ ),
100
+ collapsedPreview: description,
101
+ }
102
+ },
103
+ })
104
+
105
+ /**
106
+ * UI component for composio_search_tools tool.
107
+ * Shows "App Search" with the search queries.
108
+ */
109
+ export const SearchToolsComponent = defineToolComponent({
110
+ toolName: 'composio_search_tools',
111
+
112
+ render(toolBlock: ToolBlock & { toolName: 'composio_search_tools' }): ToolRenderConfig {
113
+ const input = toolBlock.input as {
114
+ queries?: unknown[]
115
+ } | undefined
116
+ const queries = input?.queries ?? []
117
+ const description =
118
+ queries.length > 0
119
+ ? formatList(queries.map((q) => stringifyToolValue(q)))
120
+ : ''
121
+
122
+ return {
123
+ content: (
124
+ <SimpleToolCallItem name="App Search" description={description} />
125
+ ),
126
+ collapsedPreview: description,
127
+ }
128
+ },
129
+ })
130
+
131
+ /**
132
+ * UI component for composio_get_tool_schemas tool.
133
+ * Shows "App Schemas" with the tool slugs being queried.
134
+ */
135
+ export const GetToolSchemasComponent = defineToolComponent({
136
+ toolName: 'composio_get_tool_schemas',
137
+
138
+ render(toolBlock: ToolBlock & { toolName: 'composio_get_tool_schemas' }): ToolRenderConfig {
139
+ const input = toolBlock.input as {
140
+ tool_slugs?: string[]
141
+ } | undefined
142
+ const toolSlugs = input?.tool_slugs ?? []
143
+ const description = toolSlugs.length > 0 ? formatList(toolSlugs) : ''
144
+
145
+ return {
146
+ content: (
147
+ <SimpleToolCallItem name="App Schemas" description={description} />
148
+ ),
149
+ collapsedPreview: description,
150
+ }
151
+ },
152
+ })
@@ -0,0 +1,76 @@
1
+ import { TextAttributes } from '@opentui/core'
2
+
3
+ import { useTheme } from '../../hooks/use-theme'
4
+
5
+ interface DiffViewerProps {
6
+ diffText: string
7
+ }
8
+
9
+ const DIFF_LINE_COLORS = {
10
+ dark: {
11
+ added: '#7ACC35',
12
+ removed: '#BF6C69',
13
+ },
14
+ light: {
15
+ added: '#4A9E1C',
16
+ removed: '#C53030',
17
+ },
18
+ }
19
+
20
+ const lineColor = (
21
+ line: string,
22
+ themeName: 'dark' | 'light',
23
+ mutedColor: string,
24
+ ): { fg: string; attrs?: number } => {
25
+ if (line.startsWith('@@')) {
26
+ return { fg: 'cyan', attrs: TextAttributes.BOLD }
27
+ }
28
+ if (line.startsWith('+++') || line.startsWith('---')) {
29
+ return { fg: mutedColor, attrs: TextAttributes.BOLD }
30
+ }
31
+ if (
32
+ line.startsWith('diff ') ||
33
+ line.startsWith('index ') ||
34
+ line.startsWith('rename ') ||
35
+ line.startsWith('similarity ')
36
+ ) {
37
+ return { fg: mutedColor }
38
+ }
39
+ if (line.startsWith('+')) {
40
+ return { fg: DIFF_LINE_COLORS[themeName].added }
41
+ }
42
+ if (line.startsWith('-')) {
43
+ return { fg: DIFF_LINE_COLORS[themeName].removed }
44
+ }
45
+ if (line.startsWith('\\')) {
46
+ return { fg: mutedColor }
47
+ }
48
+ return { fg: '' }
49
+ }
50
+
51
+ export const DiffViewer = ({ diffText }: DiffViewerProps) => {
52
+ const theme = useTheme()
53
+
54
+ const lines = diffText.trim().split('\n')
55
+
56
+ return (
57
+ <box
58
+ style={{ flexDirection: 'column', gap: 0, width: '100%', flexGrow: 1 }}
59
+ >
60
+ {lines
61
+ .filter((rawLine) => !rawLine.startsWith('@@'))
62
+ .map((rawLine, idx) => {
63
+ const line = rawLine.length === 0 ? ' ' : rawLine
64
+ const { fg, attrs } = lineColor(line, theme.name, theme.muted)
65
+ const resolvedFg = fg || theme.foreground
66
+ return (
67
+ <text key={`diff-line-${idx}`} style={{ wrapMode: 'none' }}>
68
+ <span fg={resolvedFg} attributes={attrs}>
69
+ {line}
70
+ </span>
71
+ </text>
72
+ )
73
+ })}
74
+ </box>
75
+ )
76
+ }
@@ -0,0 +1,61 @@
1
+ import { SimpleToolCallItem } from './tool-call-item'
2
+ import { defineToolComponent } from './types'
3
+
4
+ import type { ToolRenderConfig } from './types'
5
+
6
+ /**
7
+ * UI component for glob tool.
8
+ * Displays a single line showing the glob pattern and number of matching files.
9
+ * Does not support expand/collapse - always shows as a single line.
10
+ */
11
+ export const GlobComponent = defineToolComponent({
12
+ toolName: 'glob',
13
+
14
+ render(toolBlock): ToolRenderConfig {
15
+ const input = toolBlock.input as any
16
+ const pattern = input?.pattern ?? ''
17
+ const cwd = input?.cwd ?? ''
18
+
19
+ // Parse output to check for errors
20
+ let hasError = false
21
+
22
+ if (toolBlock.output) {
23
+ const outputArray = Array.isArray(toolBlock.output)
24
+ ? toolBlock.output
25
+ : [toolBlock.output]
26
+
27
+ for (const item of outputArray) {
28
+ const output = item as any
29
+ if (output?.type === 'json' && output?.value) {
30
+ const value = output.value as any
31
+ if (value.errorMessage) {
32
+ hasError = true
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ if (!pattern) {
39
+ return { content: null }
40
+ }
41
+
42
+ // Build single-line summary
43
+ let summary = pattern
44
+
45
+ if (cwd) {
46
+ summary += ` in ${cwd}`
47
+ }
48
+
49
+ if (hasError) {
50
+ summary += ' (error)'
51
+ }
52
+ // TODO(James): Reenable when we pass tool results as an object
53
+ // else {
54
+ // summary += ` (${fileCount} file${fileCount === 1 ? '' : 's'})`
55
+ // }
56
+
57
+ return {
58
+ content: <SimpleToolCallItem name="Glob" description={summary} />,
59
+ }
60
+ },
61
+ })
@@ -0,0 +1,77 @@
1
+ import { SimpleToolCallItem } from './tool-call-item'
2
+ import { defineToolComponent } from './types'
3
+
4
+ import type { ToolRenderConfig } from './types'
5
+
6
+ const asTrimmedString = (value: unknown): string =>
7
+ typeof value === 'string' ? value.trim() : ''
8
+
9
+ const DEFAULT_NAME = 'Services'
10
+
11
+ export interface GravityIndexParts {
12
+ /** Bold label naming the action in plain verb-first language. */
13
+ name: string
14
+ /** Non-bold target the action operates on (query, slug, category). May be empty. */
15
+ description: string
16
+ }
17
+
18
+ /**
19
+ * Splits a gravity_index tool call into a bold verb-first label (e.g.
20
+ * "Search services") and the plain target it acts on, so the action reads as
21
+ * a single natural phrase instead of a "Brand · Verb" subcommand.
22
+ */
23
+ export const getGravityIndexParts = (input: unknown): GravityIndexParts => {
24
+ if (!input || typeof input !== 'object') {
25
+ return { name: DEFAULT_NAME, description: '' }
26
+ }
27
+
28
+ const params = input as Record<string, unknown>
29
+ const action = asTrimmedString(params.action)
30
+
31
+ switch (action) {
32
+ case 'search':
33
+ return {
34
+ name: 'Search services',
35
+ description: asTrimmedString(params.query),
36
+ }
37
+ case 'browse': {
38
+ const category = asTrimmedString(params.category)
39
+ const keyword = asTrimmedString(params.q)
40
+ return {
41
+ name: 'Browse services',
42
+ description: [category, keyword].filter(Boolean).join(' · '),
43
+ }
44
+ }
45
+ case 'list_categories':
46
+ return { name: 'List service categories', description: '' }
47
+ case 'get_service':
48
+ return {
49
+ name: 'Fetch service',
50
+ description: asTrimmedString(params.slug),
51
+ }
52
+ case 'report_integration': {
53
+ const slug = asTrimmedString(params.integrated_slug)
54
+ return {
55
+ name: 'Report integration',
56
+ description: slug ? `${slug} integration` : 'integration',
57
+ }
58
+ }
59
+ default:
60
+ return { name: DEFAULT_NAME, description: '' }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * UI component for gravity_index.
66
+ * Displays a one-line summary of what Gravity Index is searching or doing.
67
+ */
68
+ export const GravityIndexComponent = defineToolComponent({
69
+ toolName: 'gravity_index',
70
+
71
+ render(toolBlock): ToolRenderConfig {
72
+ const { name, description } = getGravityIndexParts(toolBlock.input)
73
+ return {
74
+ content: <SimpleToolCallItem name={name} description={description} />,
75
+ }
76
+ },
77
+ })
@@ -0,0 +1,61 @@
1
+ import React from 'react'
2
+
3
+ import { SimpleToolCallItem } from './tool-call-item'
4
+ import { defineToolComponent } from './types'
5
+ import { useTheme } from '../../hooks/use-theme'
6
+
7
+ import type { ToolRenderConfig } from './types'
8
+
9
+ /**
10
+ * UI component for list_directory tool.
11
+ * Displays a single line showing the directories being listed.
12
+ * Does not support expand/collapse - always shows as a single line.
13
+ */
14
+ export const ListDirectoryComponent = defineToolComponent({
15
+ toolName: 'list_directory',
16
+
17
+ render(toolBlock): ToolRenderConfig {
18
+ const input = toolBlock.input as any
19
+
20
+ // Extract directories from input
21
+ let directories: string[] = []
22
+
23
+ if (Array.isArray(input?.directories)) {
24
+ directories = input.directories
25
+ .map((dir: any) =>
26
+ typeof dir === 'object' && dir.path ? dir.path : dir,
27
+ )
28
+ .filter(
29
+ (path: any) => typeof path === 'string' && path.trim().length > 0,
30
+ )
31
+ } else if (
32
+ typeof input?.path === 'string' &&
33
+ input.path.trim().length > 0
34
+ ) {
35
+ directories = [input.path.trim()]
36
+ }
37
+
38
+ if (directories.length === 0) {
39
+ return { content: null }
40
+ }
41
+
42
+ // Format directory list
43
+ const description = directories.join(', ')
44
+
45
+ // Use a wrapper component to access theme
46
+ const ListDirectoryContent = () => {
47
+ const theme = useTheme()
48
+ return (
49
+ <SimpleToolCallItem
50
+ name="List"
51
+ description={description}
52
+ descriptionColor={theme.directory}
53
+ />
54
+ )
55
+ }
56
+
57
+ return {
58
+ content: <ListDirectoryContent />,
59
+ }
60
+ },
61
+ })
@@ -0,0 +1,37 @@
1
+ import { SimpleToolCallItem } from './tool-call-item'
2
+ import { defineToolComponent } from './types'
3
+
4
+ import type { ToolRenderConfig } from './types'
5
+
6
+ /**
7
+ * UI component for read_docs tool.
8
+ * Displays library name and topic in a compact format.
9
+ * Does not support expand/collapse - always shows as a simple line.
10
+ */
11
+ export const ReadDocsComponent = defineToolComponent({
12
+ toolName: 'read_docs',
13
+
14
+ render(toolBlock): ToolRenderConfig {
15
+ const input = toolBlock.input as any
16
+
17
+ // Extract library and topic from input
18
+ const libraryTitle =
19
+ typeof input?.libraryTitle === 'string' ? input.libraryTitle.trim() : ''
20
+ const topic = typeof input?.topic === 'string' ? input.topic.trim() : ''
21
+
22
+ if (!libraryTitle && !topic) {
23
+ return { content: null }
24
+ }
25
+
26
+ const description =
27
+ libraryTitle && topic
28
+ ? `${libraryTitle}: ${topic}`
29
+ : libraryTitle || topic
30
+
31
+ return {
32
+ content: (
33
+ <SimpleToolCallItem name="Read Docs" description={description} />
34
+ ),
35
+ }
36
+ },
37
+ })
@@ -0,0 +1,91 @@
1
+ import { readFilePathsOf } from '@anvil/common/tools/params/tool/read-files'
2
+ import { isEnvTemplateFilePath } from '@anvil/common/util/env-file-path'
3
+ import { TextAttributes } from '@opentui/core'
4
+
5
+ import { SimpleToolCallItem } from './tool-call-item'
6
+ import { defineToolComponent } from './types'
7
+ import { useTheme } from '../../hooks/use-theme'
8
+ import { isSensitiveFile } from '../../utils/create-run-config'
9
+
10
+ import type { ToolRenderConfig } from './types'
11
+
12
+ function FilePathsDescription({ filePaths }: { filePaths: string[] }) {
13
+ const theme = useTheme()
14
+
15
+ return (
16
+ <>
17
+ {filePaths.map((fp, idx) => {
18
+ const isLast = idx === filePaths.length - 1
19
+ const separator = isLast ? '' : ', '
20
+
21
+ if (isSensitiveFile(fp)) {
22
+ return (
23
+ <span key={fp}>
24
+ <span fg={theme.muted} attributes={TextAttributes.STRIKETHROUGH}>
25
+ {fp}
26
+ </span>
27
+ <span fg={theme.muted}> (blocked)</span>
28
+ <span fg={theme.foreground}>{separator}</span>
29
+ </span>
30
+ )
31
+ }
32
+
33
+ if (isEnvTemplateFilePath(fp)) {
34
+ return (
35
+ <span key={fp}>
36
+ <span fg={theme.foreground}>{fp}</span>
37
+ <span fg={theme.muted}> (allowed - example only)</span>
38
+ <span fg={theme.foreground}>{separator}</span>
39
+ </span>
40
+ )
41
+ }
42
+
43
+ return (
44
+ <span key={fp} fg={theme.foreground}>
45
+ {fp}
46
+ {separator}
47
+ </span>
48
+ )
49
+ })}
50
+ </>
51
+ )
52
+ }
53
+
54
+ /**
55
+ * UI component for read_files tool.
56
+ * Displays file paths with labels for blocked/template files.
57
+ */
58
+ export const ReadFilesComponent = defineToolComponent({
59
+ toolName: 'read_files',
60
+
61
+ render(toolBlock): ToolRenderConfig {
62
+ const input = toolBlock.input as any
63
+
64
+ // Extract file paths from input
65
+ const filePaths: string[] = readFilePathsOf(input?.paths)
66
+
67
+ if (filePaths.length === 0) {
68
+ return { content: null }
69
+ }
70
+
71
+ // Check if any files need special labels
72
+ const hasSpecialFiles = filePaths.some(
73
+ (fp) => isSensitiveFile(fp) || isEnvTemplateFilePath(fp),
74
+ )
75
+
76
+ return {
77
+ content: (
78
+ <SimpleToolCallItem
79
+ name="Read"
80
+ description={
81
+ hasSpecialFiles ? (
82
+ <FilePathsDescription filePaths={filePaths} />
83
+ ) : (
84
+ filePaths.join(', ')
85
+ )
86
+ }
87
+ />
88
+ ),
89
+ }
90
+ },
91
+ })