@alumbwe/anvil 1.0.18 → 1.0.20

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 (494) hide show
  1. package/README.md +28 -30
  2. package/bin/anvil +2 -0
  3. package/package.json +71 -75
  4. package/src/agents/bundled-agents.generated.d.ts +14 -0
  5. package/src/agents/bundled-agents.generated.ts +3760 -0
  6. package/src/app.tsx +399 -0
  7. package/src/chat.tsx +1698 -0
  8. package/src/cli-args.ts +134 -0
  9. package/src/commands/__tests__/anvil-command-aliases.test.ts +56 -0
  10. package/src/commands/__tests__/bash-command.test.ts +445 -0
  11. package/src/commands/__tests__/command-args.test.ts +349 -0
  12. package/src/commands/__tests__/copy-conversation-clipboard.test.ts +108 -0
  13. package/src/commands/__tests__/copy-conversation.test.ts +226 -0
  14. package/src/commands/__tests__/diagnostics-command.test.ts +35 -0
  15. package/src/commands/__tests__/image.test.ts +99 -0
  16. package/src/commands/__tests__/init.test.ts +456 -0
  17. package/src/commands/__tests__/new-command-rotates-chat.test.ts +91 -0
  18. package/src/commands/__tests__/process-diagnostics.test.ts +54 -0
  19. package/src/commands/__tests__/prompt-builders.test.ts +28 -0
  20. package/src/commands/__tests__/router-input.test.ts +298 -0
  21. package/src/commands/ads.ts +44 -0
  22. package/src/commands/command-registry.ts +726 -0
  23. package/src/commands/copy-conversation.ts +392 -0
  24. package/src/commands/help.ts +13 -0
  25. package/src/commands/image.ts +20 -0
  26. package/src/commands/init.ts +121 -0
  27. package/src/commands/process-diagnostics.ts +120 -0
  28. package/src/commands/prompt-builders.ts +100 -0
  29. package/src/commands/publish.ts +203 -0
  30. package/src/commands/router-utils.ts +80 -0
  31. package/src/commands/router.ts +487 -0
  32. package/src/commands/usage.ts +26 -0
  33. package/src/components/__tests__/ad-banner.test.tsx +83 -0
  34. package/src/components/__tests__/anvil-landing-heading-row.test.tsx +91 -0
  35. package/src/components/__tests__/anvil-model-selector.test.tsx +519 -0
  36. package/src/components/__tests__/anvil-offer-invariants.test.ts +54 -0
  37. package/src/components/__tests__/anvil-takeover-prompt.test.tsx +212 -0
  38. package/src/components/__tests__/chat-input-bar.test.tsx +130 -0
  39. package/src/components/__tests__/grid-layout.integration.test.tsx +304 -0
  40. package/src/components/__tests__/grid-layout.test.tsx +1051 -0
  41. package/src/components/__tests__/message-block.completion.test.tsx +104 -0
  42. package/src/components/__tests__/message-block.streaming.test.tsx +78 -0
  43. package/src/components/__tests__/message-with-agents.test.tsx +579 -0
  44. package/src/components/__tests__/multiline-input.test.tsx +1132 -0
  45. package/src/components/__tests__/queue-panel.test.tsx +398 -0
  46. package/src/components/__tests__/selectable-list.test.ts +232 -0
  47. package/src/components/__tests__/status-bar.test.tsx +44 -0
  48. package/src/components/__tests__/status-indicator.test.tsx +204 -0
  49. package/src/components/__tests__/terminal-thinking-orb.test.tsx +111 -0
  50. package/src/components/__tests__/user-error-banner.test.tsx +102 -0
  51. package/src/components/ad-banner.tsx +323 -0
  52. package/src/components/agent-checklist.tsx +350 -0
  53. package/src/components/agent-mode-toggle.tsx +241 -0
  54. package/src/components/anvil-active-session-summary.tsx +63 -0
  55. package/src/components/anvil-landing-screen.tsx +865 -0
  56. package/src/components/anvil-mark.tsx +52 -0
  57. package/src/components/anvil-model-selector.tsx +1087 -0
  58. package/src/components/anvil-referral-banner.tsx +604 -0
  59. package/src/components/anvil-superseded-screen.tsx +62 -0
  60. package/src/components/ask-user/__tests__/multiple-choice-form.test.ts +432 -0
  61. package/src/components/ask-user/__tests__/validation.test.ts +213 -0
  62. package/src/components/ask-user/components/accordion-question.tsx +153 -0
  63. package/src/components/ask-user/components/custom-answer-input.tsx +66 -0
  64. package/src/components/ask-user/components/options-list.tsx +133 -0
  65. package/src/components/ask-user/components/question-header.tsx +80 -0
  66. package/src/components/ask-user/components/question-option.tsx +89 -0
  67. package/src/components/ask-user/constants.ts +38 -0
  68. package/src/components/ask-user/index.tsx +631 -0
  69. package/src/components/ask-user/utils/validation.ts +85 -0
  70. package/src/components/attachment-card.tsx +65 -0
  71. package/src/components/blocks/agent-block-grid.tsx +58 -0
  72. package/src/components/blocks/agent-branch-item.tsx +311 -0
  73. package/src/components/blocks/agent-branch-wrapper.tsx +493 -0
  74. package/src/components/blocks/agent-list-branch.tsx +77 -0
  75. package/src/components/blocks/ask-user-branch.tsx +81 -0
  76. package/src/components/blocks/block-helpers.ts +11 -0
  77. package/src/components/blocks/blocks-renderer.tsx +289 -0
  78. package/src/components/blocks/content-with-markdown.tsx +33 -0
  79. package/src/components/blocks/image-block.tsx +128 -0
  80. package/src/components/blocks/implementor-row.tsx +429 -0
  81. package/src/components/blocks/single-block.tsx +201 -0
  82. package/src/components/blocks/thinking-block.tsx +67 -0
  83. package/src/components/blocks/tool-block-group.tsx +57 -0
  84. package/src/components/blocks/tool-branch.tsx +206 -0
  85. package/src/components/blocks/user-content-copy.tsx +157 -0
  86. package/src/components/bottom-banner.tsx +136 -0
  87. package/src/components/build-mode-buttons.tsx +110 -0
  88. package/src/components/button.tsx +66 -0
  89. package/src/components/chat-header.tsx +77 -0
  90. package/src/components/chat-history-screen.tsx +413 -0
  91. package/src/components/chat-input-bar.tsx +523 -0
  92. package/src/components/clickable-title-box.tsx +66 -0
  93. package/src/components/clickable.tsx +119 -0
  94. package/src/components/collapse-button.tsx +34 -0
  95. package/src/components/copy-button.tsx +203 -0
  96. package/src/components/elapsed-timer.tsx +55 -0
  97. package/src/components/error-boundary.tsx +55 -0
  98. package/src/components/feedback-container.tsx +181 -0
  99. package/src/components/feedback-icon-button.tsx +89 -0
  100. package/src/components/feedback-input-mode.tsx +344 -0
  101. package/src/components/file-attachment-card.tsx +98 -0
  102. package/src/components/grid-layout.tsx +80 -0
  103. package/src/components/help-banner.tsx +127 -0
  104. package/src/components/highlighted-text.tsx +52 -0
  105. package/src/components/image-card.tsx +167 -0
  106. package/src/components/image-thumbnail.tsx +114 -0
  107. package/src/components/input-cursor.tsx +77 -0
  108. package/src/components/input-mode-banner.tsx +57 -0
  109. package/src/components/load-previous-button.tsx +48 -0
  110. package/src/components/login-modal.tsx +475 -0
  111. package/src/components/message-block.tsx +346 -0
  112. package/src/components/message-footer.tsx +258 -0
  113. package/src/components/message-with-agents.tsx +506 -0
  114. package/src/components/mode-divider.tsx +43 -0
  115. package/src/components/multiline-input.tsx +1241 -0
  116. package/src/components/out-of-credits-banner.tsx +160 -0
  117. package/src/components/pending-attachments-banner.tsx +116 -0
  118. package/src/components/pending-bash-message.tsx +59 -0
  119. package/src/components/progress-bar.tsx +81 -0
  120. package/src/components/project-picker-screen.tsx +485 -0
  121. package/src/components/publish-confirmation.tsx +493 -0
  122. package/src/components/publish-container.tsx +687 -0
  123. package/src/components/queue-panel.tsx +310 -0
  124. package/src/components/raised-pill.tsx +95 -0
  125. package/src/components/renderers/plan-box.tsx +59 -0
  126. package/src/components/review-screen.tsx +112 -0
  127. package/src/components/scroll-to-bottom-button.tsx +34 -0
  128. package/src/components/segmented-control.tsx +187 -0
  129. package/src/components/selectable-list.tsx +248 -0
  130. package/src/components/selected-chips.tsx +80 -0
  131. package/src/components/separator.tsx +40 -0
  132. package/src/components/session-ended-banner.tsx +226 -0
  133. package/src/components/shimmer-text.tsx +248 -0
  134. package/src/components/status-bar.tsx +313 -0
  135. package/src/components/subscription-limit-banner.tsx +206 -0
  136. package/src/components/suggested-prompts.tsx +184 -0
  137. package/src/components/suggestion-menu.tsx +215 -0
  138. package/src/components/terminal-command-display.tsx +151 -0
  139. package/src/components/terminal-link.tsx +97 -0
  140. package/src/components/terminal-thinking-orb.tsx +95 -0
  141. package/src/components/text-attachment-card.tsx +77 -0
  142. package/src/components/thinking.tsx +109 -0
  143. package/src/components/tools/__tests__/apply-patch.test.tsx +84 -0
  144. package/src/components/tools/__tests__/code-search.test.tsx +45 -0
  145. package/src/components/tools/__tests__/gravity-index.test.ts +76 -0
  146. package/src/components/tools/__tests__/render-ui.test.tsx +92 -0
  147. package/src/components/tools/__tests__/run-terminal-command.test.ts +233 -0
  148. package/src/components/tools/apply-patch.tsx +95 -0
  149. package/src/components/tools/code-search.tsx +45 -0
  150. package/src/components/tools/composio.tsx +152 -0
  151. package/src/components/tools/diff-viewer.tsx +76 -0
  152. package/src/components/tools/glob.tsx +61 -0
  153. package/src/components/tools/gravity-index.tsx +77 -0
  154. package/src/components/tools/list-directory.tsx +61 -0
  155. package/src/components/tools/read-docs.tsx +37 -0
  156. package/src/components/tools/read-files.tsx +91 -0
  157. package/src/components/tools/read-subtree.tsx +44 -0
  158. package/src/components/tools/read-url.tsx +33 -0
  159. package/src/components/tools/registry.ts +126 -0
  160. package/src/components/tools/render-ui.tsx +122 -0
  161. package/src/components/tools/run-terminal-command.tsx +79 -0
  162. package/src/components/tools/skill.tsx +29 -0
  163. package/src/components/tools/str-replace.tsx +77 -0
  164. package/src/components/tools/suggest-followups.tsx +369 -0
  165. package/src/components/tools/task-completed.tsx +16 -0
  166. package/src/components/tools/tool-call-item.tsx +273 -0
  167. package/src/components/tools/types.ts +55 -0
  168. package/src/components/tools/web-search.tsx +33 -0
  169. package/src/components/tools/write-file.tsx +16 -0
  170. package/src/components/tools/write-todos.tsx +95 -0
  171. package/src/components/top-banner.tsx +178 -0
  172. package/src/components/usage-banner.tsx +244 -0
  173. package/src/components/user-error-banner.tsx +56 -0
  174. package/src/components/validation-error-popover.tsx +192 -0
  175. package/src/contexts/__tests__/chat-runtime-context.test.tsx +149 -0
  176. package/src/contexts/chat-runtime-context.tsx +240 -0
  177. package/src/data/slash-commands.test.ts +24 -0
  178. package/src/data/slash-commands.ts +249 -0
  179. package/src/entry.ts +12 -0
  180. package/src/hooks/__tests__/holds-live-anvil-slot.test.ts +49 -0
  181. package/src/hooks/__tests__/session-fetch-signal.test.ts +63 -0
  182. package/src/hooks/__tests__/use-activity-query.test.ts +1000 -0
  183. package/src/hooks/__tests__/use-ask-user-bridge.test.ts +176 -0
  184. package/src/hooks/__tests__/use-auth-query.test.ts +21 -0
  185. package/src/hooks/__tests__/use-chat-input-remount.test.tsx +66 -0
  186. package/src/hooks/__tests__/use-clipboard.test.tsx +73 -0
  187. package/src/hooks/__tests__/use-connection-status.test.ts +112 -0
  188. package/src/hooks/__tests__/use-directory-browser.test.ts +203 -0
  189. package/src/hooks/__tests__/use-gravity-ad.test.ts +73 -0
  190. package/src/hooks/__tests__/use-grid-layout.test.ts +349 -0
  191. package/src/hooks/__tests__/use-input-history.test.ts +699 -0
  192. package/src/hooks/__tests__/use-message-queue-editing.test.tsx +209 -0
  193. package/src/hooks/__tests__/use-message-queue.test.tsx +71 -0
  194. package/src/hooks/__tests__/use-path-tab-completion.test.ts +315 -0
  195. package/src/hooks/__tests__/use-queue-controls.test.ts +68 -0
  196. package/src/hooks/__tests__/use-queue-ui.test.tsx +83 -0
  197. package/src/hooks/__tests__/use-searchable-list.test.ts +359 -0
  198. package/src/hooks/__tests__/use-send-message-timer.test.ts +146 -0
  199. package/src/hooks/__tests__/use-suggestion-engine-mention.test.ts +361 -0
  200. package/src/hooks/__tests__/use-suggestion-engine.test.ts +485 -0
  201. package/src/hooks/__tests__/use-terminal-focus.test.ts +66 -0
  202. package/src/hooks/__tests__/use-terminal-layout.test.ts +675 -0
  203. package/src/hooks/__tests__/use-timeout.test.ts +330 -0
  204. package/src/hooks/__tests__/use-usage-query.test.ts +502 -0
  205. package/src/hooks/__tests__/use-user-details-query.test.ts +195 -0
  206. package/src/hooks/helpers/__tests__/send-message.test.ts +1918 -0
  207. package/src/hooks/helpers/send-message.ts +654 -0
  208. package/src/hooks/stream-state.ts +83 -0
  209. package/src/hooks/use-activity-query.ts +668 -0
  210. package/src/hooks/use-agent-validation.ts +74 -0
  211. package/src/hooks/use-anvil-ctrl-c-exit.ts +23 -0
  212. package/src/hooks/use-anvil-session-progress.ts +34 -0
  213. package/src/hooks/use-anvil-session.ts +806 -0
  214. package/src/hooks/use-anvil-streak-query.ts +61 -0
  215. package/src/hooks/use-ask-user-bridge.ts +92 -0
  216. package/src/hooks/use-auth-query.ts +262 -0
  217. package/src/hooks/use-auth-state.ts +152 -0
  218. package/src/hooks/use-chat-input.ts +105 -0
  219. package/src/hooks/use-chat-keyboard.ts +321 -0
  220. package/src/hooks/use-chat-messages.ts +254 -0
  221. package/src/hooks/use-chat-state.ts +165 -0
  222. package/src/hooks/use-chat-streaming.ts +180 -0
  223. package/src/hooks/use-chat-ui.ts +131 -0
  224. package/src/hooks/use-clipboard.ts +151 -0
  225. package/src/hooks/use-connection-status.ts +142 -0
  226. package/src/hooks/use-directory-browser.ts +88 -0
  227. package/src/hooks/use-elapsed-time.ts +116 -0
  228. package/src/hooks/use-event.ts +34 -0
  229. package/src/hooks/use-exit-handler.ts +66 -0
  230. package/src/hooks/use-fetch-login-url.ts +65 -0
  231. package/src/hooks/use-fingerprint.ts +61 -0
  232. package/src/hooks/use-gravity-ad.ts +656 -0
  233. package/src/hooks/use-grid-layout.ts +73 -0
  234. package/src/hooks/use-input-history.ts +173 -0
  235. package/src/hooks/use-login-keyboard-handlers.ts +75 -0
  236. package/src/hooks/use-login-polling.ts +114 -0
  237. package/src/hooks/use-logo.tsx +161 -0
  238. package/src/hooks/use-message-queue.ts +387 -0
  239. package/src/hooks/use-now.ts +20 -0
  240. package/src/hooks/use-path-tab-completion.ts +88 -0
  241. package/src/hooks/use-publish-mutation.ts +60 -0
  242. package/src/hooks/use-queue-controls.ts +68 -0
  243. package/src/hooks/use-queue-ui.ts +74 -0
  244. package/src/hooks/use-scroll-management.ts +184 -0
  245. package/src/hooks/use-searchable-list.ts +98 -0
  246. package/src/hooks/use-send-message.ts +773 -0
  247. package/src/hooks/use-sheen-animation.tsx +88 -0
  248. package/src/hooks/use-subscription-query.ts +71 -0
  249. package/src/hooks/use-suggestion-engine.ts +783 -0
  250. package/src/hooks/use-terminal-breakpoints.ts +77 -0
  251. package/src/hooks/use-terminal-dimensions.ts +46 -0
  252. package/src/hooks/use-terminal-focus.ts +29 -0
  253. package/src/hooks/use-terminal-layout.ts +189 -0
  254. package/src/hooks/use-theme.tsx +140 -0
  255. package/src/hooks/use-timeout.ts +85 -0
  256. package/src/hooks/use-update-preference.ts +66 -0
  257. package/src/hooks/use-usage-monitor.ts +55 -0
  258. package/src/hooks/use-usage-query.ts +124 -0
  259. package/src/hooks/use-user-details-query.ts +93 -0
  260. package/src/hooks/use-why-did-you-update.ts +177 -0
  261. package/src/index.tsx +473 -0
  262. package/src/init/__tests__/init-direnv.test.ts +526 -0
  263. package/src/init/init-app.ts +34 -0
  264. package/src/init/init-direnv.ts +133 -0
  265. package/src/login/constants.ts +60 -0
  266. package/src/login/login-flow.ts +204 -0
  267. package/src/login/plain-login.ts +108 -0
  268. package/src/login/utils.ts +183 -0
  269. package/src/native/ripgrep.ts +80 -0
  270. package/src/polyfills/bun-strip-ansi.ts +12 -0
  271. package/src/pre-init/tree-sitter-wasm.ts +96 -0
  272. package/src/project-files.ts +102 -0
  273. package/src/setup/key-setup.ts +295 -0
  274. package/src/setup/load-env.ts +106 -0
  275. package/src/state/__tests__/chat-store-focus.test.ts +22 -0
  276. package/src/state/__tests__/feedback-store.test.ts +257 -0
  277. package/src/state/anvil-model-store.ts +42 -0
  278. package/src/state/anvil-session-store.ts +53 -0
  279. package/src/state/chat-history-store.ts +30 -0
  280. package/src/state/chat-store.ts +544 -0
  281. package/src/state/feedback-store.ts +160 -0
  282. package/src/state/login-store.ts +150 -0
  283. package/src/state/message-block-store.ts +149 -0
  284. package/src/state/publish-store.ts +146 -0
  285. package/src/state/queue-panel-store.ts +26 -0
  286. package/src/state/review-store.ts +24 -0
  287. package/src/types/anvil-session.ts +17 -0
  288. package/src/types/chat-state.ts +15 -0
  289. package/src/types/chat.ts +241 -0
  290. package/src/types/contracts/send-message.ts +12 -0
  291. package/src/types/env.ts +98 -0
  292. package/src/types/function-params.ts +28 -0
  293. package/src/types/react19-compat.d.ts +19 -0
  294. package/src/types/store.ts +111 -0
  295. package/src/types/theme-system.ts +144 -0
  296. package/src/types/utils.ts +3 -0
  297. package/src/utils/__tests__/active-run.test.ts +140 -0
  298. package/src/utils/__tests__/activity-tracker.test.ts +440 -0
  299. package/src/utils/__tests__/agent-display.test.ts +139 -0
  300. package/src/utils/__tests__/analytics-client.test.ts +262 -0
  301. package/src/utils/__tests__/anonymous-id.test.ts +74 -0
  302. package/src/utils/__tests__/anvil-api.test.ts +578 -0
  303. package/src/utils/__tests__/anvil-instance-owner.test.ts +69 -0
  304. package/src/utils/__tests__/anvil-model-navigation.test.ts +102 -0
  305. package/src/utils/__tests__/anvil-premium-reset.test.ts +79 -0
  306. package/src/utils/__tests__/anvil-referral-cache.test.ts +116 -0
  307. package/src/utils/__tests__/anvil-session-api.test.ts +215 -0
  308. package/src/utils/__tests__/anvil-session-display.test.ts +23 -0
  309. package/src/utils/__tests__/anvil-streak-line.test.ts +217 -0
  310. package/src/utils/__tests__/arrays.test.ts +264 -0
  311. package/src/utils/__tests__/bash-context-processor.test.ts +38 -0
  312. package/src/utils/__tests__/block-processor.test.ts +810 -0
  313. package/src/utils/__tests__/chat-history.test.ts +203 -0
  314. package/src/utils/__tests__/chat-input-key-intercept.test.ts +40 -0
  315. package/src/utils/__tests__/chat-meta.test.ts +130 -0
  316. package/src/utils/__tests__/clipboard-linux.test.ts +359 -0
  317. package/src/utils/__tests__/clipboard.test.ts +910 -0
  318. package/src/utils/__tests__/code-search-summary.test.ts +84 -0
  319. package/src/utils/__tests__/collapse-helpers.test.ts +1109 -0
  320. package/src/utils/__tests__/error-handling.test.ts +658 -0
  321. package/src/utils/__tests__/exit-cleanly.test.ts +110 -0
  322. package/src/utils/__tests__/feedback-helpers.test.ts +444 -0
  323. package/src/utils/__tests__/feedback-submission.test.ts +26 -0
  324. package/src/utils/__tests__/fetch-usage.test.ts +355 -0
  325. package/src/utils/__tests__/fingerprint.test.ts +144 -0
  326. package/src/utils/__tests__/fixtures/terminal-command-broker-child.ts +7 -0
  327. package/src/utils/__tests__/fixtures/terminal-command-broker-entry.ts +3 -0
  328. package/src/utils/__tests__/fixtures/terminal-command-broker-owner.ts +33 -0
  329. package/src/utils/__tests__/format-elapsed-time.test.ts +103 -0
  330. package/src/utils/__tests__/format-timeout.test.ts +87 -0
  331. package/src/utils/__tests__/image-dimensions.test.ts +249 -0
  332. package/src/utils/__tests__/image-processor.test.ts +209 -0
  333. package/src/utils/__tests__/implementor-helpers.test.ts +1458 -0
  334. package/src/utils/__tests__/keyboard-actions.test.ts +660 -0
  335. package/src/utils/__tests__/layout-helpers.test.ts +36 -0
  336. package/src/utils/__tests__/lazy-response-ads.test.ts +167 -0
  337. package/src/utils/__tests__/log-shipper.test.ts +53 -0
  338. package/src/utils/__tests__/markdown-renderer.test.tsx +421 -0
  339. package/src/utils/__tests__/message-block-helpers.test.ts +1263 -0
  340. package/src/utils/__tests__/message-updater.test.ts +645 -0
  341. package/src/utils/__tests__/osc-timeout-scenarios.test.ts +172 -0
  342. package/src/utils/__tests__/pending-attachments.test.ts +277 -0
  343. package/src/utils/__tests__/polling-backoff.test.ts +51 -0
  344. package/src/utils/__tests__/queue-panel-actions.test.ts +148 -0
  345. package/src/utils/__tests__/run-state-storage.test.ts +919 -0
  346. package/src/utils/__tests__/safe-json.test.ts +77 -0
  347. package/src/utils/__tests__/sdk-event-handlers.test.ts +685 -0
  348. package/src/utils/__tests__/send-message-helpers.test.ts +1898 -0
  349. package/src/utils/__tests__/send-message-timer.test.ts +64 -0
  350. package/src/utils/__tests__/settings.test.ts +99 -0
  351. package/src/utils/__tests__/strings.test.ts +192 -0
  352. package/src/utils/__tests__/terminal-color-detection.test.ts +425 -0
  353. package/src/utils/__tests__/terminal-command-broker.test.ts +528 -0
  354. package/src/utils/__tests__/terminal-enter-detection.test.ts +77 -0
  355. package/src/utils/__tests__/terminal-io.test.ts +137 -0
  356. package/src/utils/__tests__/terminal-protocol-controller.test.ts +119 -0
  357. package/src/utils/__tests__/text-layout.test.ts +82 -0
  358. package/src/utils/__tests__/theme-platform-detection.test.ts +125 -0
  359. package/src/utils/__tests__/think-tag-parser.test.ts +159 -0
  360. package/src/utils/__tests__/trace-writer.test.ts +223 -0
  361. package/src/utils/__tests__/trim-chat-logs.test.ts +78 -0
  362. package/src/utils/__tests__/usage-banner-state.test.ts +298 -0
  363. package/src/utils/__tests__/validation-error-formatting.test.ts +126 -0
  364. package/src/utils/__tests__/windows-terminal-health.test.ts +101 -0
  365. package/src/utils/__tests__/write-file-atomic.test.ts +127 -0
  366. package/src/utils/active-run.ts +131 -0
  367. package/src/utils/activity-tracker.ts +66 -0
  368. package/src/utils/agent-display.ts +87 -0
  369. package/src/utils/agent-helpers.ts +27 -0
  370. package/src/utils/agent-id-utils.ts +14 -0
  371. package/src/utils/ai-message-id.ts +12 -0
  372. package/src/utils/analytics.ts +361 -0
  373. package/src/utils/anonymous-id.ts +87 -0
  374. package/src/utils/anvil-agent-selection.ts +33 -0
  375. package/src/utils/anvil-api.ts +612 -0
  376. package/src/utils/anvil-client.ts +217 -0
  377. package/src/utils/anvil-instance-owner.ts +66 -0
  378. package/src/utils/anvil-model-navigation.ts +50 -0
  379. package/src/utils/anvil-premium-reset.ts +55 -0
  380. package/src/utils/anvil-referral-cache.ts +51 -0
  381. package/src/utils/anvil-session-api.ts +243 -0
  382. package/src/utils/anvil-session-display.ts +21 -0
  383. package/src/utils/anvil-streak-line.ts +93 -0
  384. package/src/utils/arrays.ts +117 -0
  385. package/src/utils/auth.ts +258 -0
  386. package/src/utils/bash-context-processor.ts +47 -0
  387. package/src/utils/bash-messages.ts +108 -0
  388. package/src/utils/block-margins.ts +35 -0
  389. package/src/utils/block-operations.ts +523 -0
  390. package/src/utils/block-processor.ts +213 -0
  391. package/src/utils/chat-history.ts +253 -0
  392. package/src/utils/chat-input-key-intercept.ts +52 -0
  393. package/src/utils/chat-meta.ts +90 -0
  394. package/src/utils/chat-scroll-accel.ts +151 -0
  395. package/src/utils/clipboard-image.ts +588 -0
  396. package/src/utils/clipboard.ts +397 -0
  397. package/src/utils/code-search-summary.ts +70 -0
  398. package/src/utils/collapse-helpers.ts +256 -0
  399. package/src/utils/config-dir.ts +24 -0
  400. package/src/utils/constants.ts +190 -0
  401. package/src/utils/create-event-handler-state.ts +73 -0
  402. package/src/utils/create-run-config.ts +121 -0
  403. package/src/utils/detect-shell.ts +116 -0
  404. package/src/utils/directory-browser.ts +72 -0
  405. package/src/utils/engagement.ts +55 -0
  406. package/src/utils/env.ts +92 -0
  407. package/src/utils/error-handling.ts +255 -0
  408. package/src/utils/error-messages.ts +62 -0
  409. package/src/utils/exit-cleanly.ts +86 -0
  410. package/src/utils/feedback-helpers.ts +103 -0
  411. package/src/utils/feedback-submission.ts +22 -0
  412. package/src/utils/fetch-usage.ts +76 -0
  413. package/src/utils/fingerprint.ts +245 -0
  414. package/src/utils/format-elapsed-time.ts +33 -0
  415. package/src/utils/format-session-units.ts +6 -0
  416. package/src/utils/format-timeout.ts +28 -0
  417. package/src/utils/format-validation-errors-for-message.ts +84 -0
  418. package/src/utils/git.ts +17 -0
  419. package/src/utils/helpers.ts +47 -0
  420. package/src/utils/image-display.ts +67 -0
  421. package/src/utils/image-handler.ts +325 -0
  422. package/src/utils/image-processor.ts +133 -0
  423. package/src/utils/image-thumbnail.ts +78 -0
  424. package/src/utils/implementor-helpers.ts +787 -0
  425. package/src/utils/input-modes.ts +174 -0
  426. package/src/utils/keyboard-actions.ts +392 -0
  427. package/src/utils/keypad-keys.ts +47 -0
  428. package/src/utils/layout-helpers.ts +33 -0
  429. package/src/utils/lazy-response-ads.ts +1 -0
  430. package/src/utils/local-agent-registry.ts +474 -0
  431. package/src/utils/log-shipper.ts +126 -0
  432. package/src/utils/logger.ts +327 -0
  433. package/src/utils/markdown-renderer.tsx +1090 -0
  434. package/src/utils/math.ts +3 -0
  435. package/src/utils/message-block-helpers.ts +684 -0
  436. package/src/utils/message-history.ts +143 -0
  437. package/src/utils/message-tree-utils.ts +67 -0
  438. package/src/utils/message-updater.ts +279 -0
  439. package/src/utils/open-file.ts +146 -0
  440. package/src/utils/open-url.ts +63 -0
  441. package/src/utils/path-completion.ts +111 -0
  442. package/src/utils/path-helpers.ts +38 -0
  443. package/src/utils/pending-attachments.ts +360 -0
  444. package/src/utils/polling-backoff.ts +59 -0
  445. package/src/utils/project-picker.ts +12 -0
  446. package/src/utils/queue-panel-actions.ts +70 -0
  447. package/src/utils/recent-projects.ts +156 -0
  448. package/src/utils/renderer-cleanup.ts +233 -0
  449. package/src/utils/response-ad-positions.ts +1 -0
  450. package/src/utils/run-state-storage.ts +603 -0
  451. package/src/utils/safe-json.ts +153 -0
  452. package/src/utils/sdk-event-handlers.ts +571 -0
  453. package/src/utils/send-message-helpers.ts +210 -0
  454. package/src/utils/send-message-timer.ts +110 -0
  455. package/src/utils/settings.ts +226 -0
  456. package/src/utils/skill-registry.ts +94 -0
  457. package/src/utils/spawn-agent-matcher.ts +55 -0
  458. package/src/utils/status-indicator-state.ts +107 -0
  459. package/src/utils/stream-chunk-processor.ts +57 -0
  460. package/src/utils/strings.ts +271 -0
  461. package/src/utils/subscription.ts +31 -0
  462. package/src/utils/syntax-highlighter.tsx +19 -0
  463. package/src/utils/terminal-color-detection.ts +474 -0
  464. package/src/utils/terminal-command-broker.ts +467 -0
  465. package/src/utils/terminal-enter-detection.ts +63 -0
  466. package/src/utils/terminal-images.ts +229 -0
  467. package/src/utils/terminal-io.ts +85 -0
  468. package/src/utils/terminal-protocol-controller.ts +173 -0
  469. package/src/utils/terminal-reset-sequences.ts +33 -0
  470. package/src/utils/terminal-title.ts +84 -0
  471. package/src/utils/terminal-watchdog.ts +366 -0
  472. package/src/utils/text-layout.ts +149 -0
  473. package/src/utils/theme-config.ts +141 -0
  474. package/src/utils/theme-system.ts +1206 -0
  475. package/src/utils/think-tag-parser.ts +95 -0
  476. package/src/utils/time-format.ts +21 -0
  477. package/src/utils/trace-writer.ts +162 -0
  478. package/src/utils/ui-constants.ts +69 -0
  479. package/src/utils/update-checker.ts +110 -0
  480. package/src/utils/usage-banner-state.ts +146 -0
  481. package/src/utils/validation-error-formatting.ts +86 -0
  482. package/src/utils/validation-error-helpers.ts +19 -0
  483. package/src/utils/windows-terminal-health.ts +124 -0
  484. package/src/utils/word-wrap-utils.ts +53 -0
  485. package/src/utils/write-file-atomic.ts +54 -0
  486. package/src/utils/yield-to-event-loop.ts +9 -0
  487. package/bin/anvil.cjs +0 -40
  488. package/dist/bundled.js +0 -123450
  489. package/dist/bundled.js.map +0 -827
  490. package/dist/vendor/ripgrep/arm64-darwin/rg +0 -0
  491. package/dist/vendor/ripgrep/arm64-linux/rg +0 -0
  492. package/dist/vendor/ripgrep/x64-darwin/rg +0 -0
  493. package/dist/vendor/ripgrep/x64-linux/rg +0 -0
  494. package/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
package/src/app.tsx ADDED
@@ -0,0 +1,399 @@
1
+ import { isRetryableStatusCode, getErrorStatusCode } from '@anvil/sdk'
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
3
+ import { useShallow } from 'zustand/react/shallow'
4
+
5
+ import { Chat } from './chat'
6
+ import { ChatHistoryScreen } from './components/chat-history-screen'
7
+ import { ChatRuntimeProvider } from './contexts/chat-runtime-context'
8
+ import { AnvilSupersededScreen } from './components/anvil-superseded-screen'
9
+ import { LoginModal } from './components/login-modal'
10
+ import { ProjectPickerScreen } from './components/project-picker-screen'
11
+ import { AnvilLandingScreen } from './components/anvil-landing-screen'
12
+ import { useAuthQuery } from './hooks/use-auth-query'
13
+ import { useAuthState } from './hooks/use-auth-state'
14
+ import { useAnvilSession } from './hooks/use-anvil-session'
15
+ import { useTerminalFocus } from './hooks/use-terminal-focus'
16
+ import { getProjectRoot, startNewChat } from './project-files'
17
+ import { useChatHistoryStore } from './state/chat-history-store'
18
+ import { stopActiveRun } from './utils/active-run'
19
+ import { useChatStore } from './state/chat-store'
20
+ import type { TopBannerType } from './types/store'
21
+ import { IS_ANVIL } from './utils/constants'
22
+ import { findGitRoot } from './utils/git'
23
+
24
+ import type { MultilineInputHandle } from './components/multiline-input'
25
+ import type { AgentMode } from './utils/constants'
26
+ import type { AuthStatus } from './utils/status-indicator-state'
27
+ import type { FileTreeNode } from '@anvil/common/util/file'
28
+
29
+ interface AppProps {
30
+ initialPrompt: string | null
31
+ agentId?: string
32
+ requireAuth: boolean | null
33
+ hasInvalidCredentials: boolean
34
+ fileTree: FileTreeNode[]
35
+ continueChat: boolean
36
+ continueChatId?: string
37
+ initialMode?: AgentMode
38
+ showProjectPicker: boolean
39
+ onProjectChange: (projectPath: string) => void
40
+ }
41
+
42
+ export const App = ({
43
+ initialPrompt,
44
+ agentId,
45
+ requireAuth,
46
+ hasInvalidCredentials,
47
+ fileTree,
48
+ continueChat,
49
+ continueChatId,
50
+ initialMode,
51
+ showProjectPicker,
52
+ onProjectChange,
53
+ }: AppProps) => {
54
+ const inputRef = useRef<MultilineInputHandle | null>(null)
55
+ const initialPromptConsumedRef = useRef(false)
56
+ const consumeInitialPrompt = useCallback(() => {
57
+ if (!initialPrompt || initialPromptConsumedRef.current) {
58
+ return null
59
+ }
60
+ initialPromptConsumedRef.current = true
61
+ return initialPrompt
62
+ }, [initialPrompt])
63
+ const {
64
+ setInputFocused,
65
+ setIsFocusSupported,
66
+ resetChatStore,
67
+ activeTopBanner,
68
+ setActiveTopBanner,
69
+ closeTopBanner,
70
+ chatSessionId,
71
+ } = useChatStore(
72
+ useShallow((store) => ({
73
+ setInputFocused: store.setInputFocused,
74
+ setIsFocusSupported: store.setIsFocusSupported,
75
+ resetChatStore: store.reset,
76
+ activeTopBanner: store.activeTopBanner,
77
+ setActiveTopBanner: store.setActiveTopBanner,
78
+ closeTopBanner: store.closeTopBanner,
79
+ chatSessionId: store.chatSessionId,
80
+ })),
81
+ )
82
+
83
+ // Wrap in useCallback to prevent re-subscribing on every render
84
+ const handleSupportDetected = useCallback(() => {
85
+ setIsFocusSupported(true)
86
+ }, [setIsFocusSupported])
87
+
88
+ // Enable terminal focus detection to stop cursor blinking when window loses focus
89
+ // Cursor starts visible but not blinking; blinking enabled once terminal support confirmed
90
+ useTerminalFocus({
91
+ onFocusChange: setInputFocused,
92
+ onSupportDetected: handleSupportDetected,
93
+ })
94
+
95
+ // Get auth query for network status tracking
96
+ const authQuery = useAuthQuery()
97
+
98
+ const {
99
+ isAuthenticated,
100
+ setIsAuthenticated,
101
+ setUser,
102
+ handleLoginSuccess,
103
+ logoutMutation,
104
+ } = useAuthState({
105
+ requireAuth,
106
+ inputRef,
107
+ setInputFocused,
108
+ resetChatStore,
109
+ })
110
+
111
+ const projectRoot = getProjectRoot()
112
+ const gitRoot = useMemo(
113
+ () => findGitRoot({ cwd: projectRoot }),
114
+ [projectRoot],
115
+ )
116
+ const showGitRootBanner = Boolean(gitRoot && gitRoot !== projectRoot)
117
+ const [gitRootBannerDismissed, setGitRootBannerDismissed] = useState(false)
118
+ const prevTopBannerRef = useRef<TopBannerType | null>(null)
119
+
120
+ useEffect(() => {
121
+ setGitRootBannerDismissed(false)
122
+ }, [projectRoot])
123
+
124
+ useEffect(() => {
125
+ const prevBanner = prevTopBannerRef.current
126
+ if (
127
+ prevBanner === 'gitRoot' &&
128
+ activeTopBanner === null &&
129
+ showGitRootBanner
130
+ ) {
131
+ setGitRootBannerDismissed(true)
132
+ }
133
+ prevTopBannerRef.current = activeTopBanner
134
+ }, [activeTopBanner, showGitRootBanner])
135
+
136
+ useEffect(() => {
137
+ if (!showGitRootBanner) {
138
+ if (activeTopBanner === 'gitRoot') {
139
+ closeTopBanner()
140
+ }
141
+ return
142
+ }
143
+ if (!gitRootBannerDismissed && activeTopBanner === null) {
144
+ setActiveTopBanner('gitRoot')
145
+ }
146
+ }, [
147
+ activeTopBanner,
148
+ closeTopBanner,
149
+ gitRootBannerDismissed,
150
+ setActiveTopBanner,
151
+ showGitRootBanner,
152
+ ])
153
+
154
+ const handleSwitchToGitRoot = useCallback(() => {
155
+ if (gitRoot) {
156
+ onProjectChange(gitRoot)
157
+ }
158
+ }, [gitRoot, onProjectChange])
159
+
160
+ // Chat history state from store
161
+ const { showChatHistory, closeChatHistory } = useChatHistoryStore()
162
+
163
+ // State to track which chat to resume (set when user selects from history)
164
+ const [resumeChatId, setResumeChatId] = useState<string | null>(null)
165
+
166
+ const handleResumeChat = useCallback(
167
+ (chatId: string) => {
168
+ // Abort any in-flight run BEFORE resetting the store and switching
169
+ // chats: an orphaned run would keep checkpointing, and its writes could
170
+ // land in the resumed chat's directory, overwriting that transcript.
171
+ stopActiveRun('history-resume')
172
+ closeChatHistory()
173
+ // Reset chat store to clear previous messages before loading the selected chat
174
+ resetChatStore()
175
+ setResumeChatId(chatId)
176
+ },
177
+ [closeChatHistory, resetChatStore],
178
+ )
179
+
180
+ const handleNewChat = useCallback(() => {
181
+ stopActiveRun('new-chat')
182
+ closeChatHistory()
183
+ resetChatStore()
184
+ // Rotate the chat id so the new conversation saves to its own directory
185
+ // instead of overwriting the current (possibly resumed) chat's history
186
+ startNewChat()
187
+ setResumeChatId(null)
188
+ }, [closeChatHistory, resetChatStore])
189
+
190
+ // Determine effective continueChat values
191
+ const effectiveContinueChat = continueChat || resumeChatId !== null
192
+ const effectiveContinueChatId = resumeChatId ?? continueChatId
193
+
194
+ // Derive auth reachability + retrying state from authQuery error
195
+ const authError = authQuery.error
196
+ const authErrorStatusCode = authError
197
+ ? getErrorStatusCode(authError)
198
+ : undefined
199
+
200
+ let authStatus: AuthStatus = 'ok'
201
+ if (authQuery.isError && authErrorStatusCode !== undefined) {
202
+ if (isRetryableStatusCode(authErrorStatusCode)) {
203
+ // Retryable errors (408 timeout, 429 rate limit, 5xx server errors)
204
+ authStatus = 'retrying'
205
+ } else if (authErrorStatusCode >= 500) {
206
+ // Non-retryable server errors (unlikely but possible future codes)
207
+ authStatus = 'unreachable'
208
+ }
209
+ // 4xx client errors (401, 403, etc.) keep 'ok' - network is fine, just auth failed
210
+ }
211
+
212
+ // Render project picker FIRST when at home directory or outside a project.
213
+ // This deliberately precedes the login/auth and free-session gates so the
214
+ // user always gets to pick a working directory before anything else — auth
215
+ // failures or a banned anvil session would otherwise replace the
216
+ // picker mid-flash and look like being kicked out of the app.
217
+ if (showProjectPicker) {
218
+ return (
219
+ <ProjectPickerScreen
220
+ onSelectProject={onProjectChange}
221
+ initialPath={projectRoot}
222
+ />
223
+ )
224
+ }
225
+
226
+ // Render login modal when not authenticated AND auth service is reachable
227
+ // Don't show login modal during network outages OR while retrying
228
+ if (
229
+ requireAuth !== null &&
230
+ isAuthenticated === false &&
231
+ authStatus === 'ok'
232
+ ) {
233
+ return (
234
+ <LoginModal
235
+ onLoginSuccess={handleLoginSuccess}
236
+ hasInvalidCredentials={hasInvalidCredentials}
237
+ />
238
+ )
239
+ }
240
+
241
+ // Reset the runtime only when the active chat identity changes. View-only
242
+ // routes such as history and session gates keep the same key.
243
+ return (
244
+ <AuthedSurface
245
+ runtimeKey={chatSessionId}
246
+ consumeInitialPrompt={consumeInitialPrompt}
247
+ agentId={agentId}
248
+ fileTree={fileTree}
249
+ inputRef={inputRef}
250
+ setIsAuthenticated={setIsAuthenticated}
251
+ setUser={setUser}
252
+ logoutMutation={logoutMutation}
253
+ continueChat={effectiveContinueChat}
254
+ continueChatId={effectiveContinueChatId}
255
+ authStatus={authStatus}
256
+ initialMode={initialMode}
257
+ gitRoot={gitRoot}
258
+ onSwitchToGitRoot={handleSwitchToGitRoot}
259
+ showChatHistory={showChatHistory}
260
+ onSelectChat={handleResumeChat}
261
+ onCancelChatHistory={closeChatHistory}
262
+ onNewChat={handleNewChat}
263
+ />
264
+ )
265
+ }
266
+
267
+ interface AuthedSurfaceProps {
268
+ runtimeKey: string
269
+ consumeInitialPrompt: () => string | null
270
+ agentId?: string
271
+ fileTree: FileTreeNode[]
272
+ inputRef: React.MutableRefObject<MultilineInputHandle | null>
273
+ setIsAuthenticated: React.Dispatch<React.SetStateAction<boolean | null>>
274
+ setUser: React.Dispatch<
275
+ React.SetStateAction<import('./utils/auth').User | null>
276
+ >
277
+ logoutMutation: ReturnType<typeof useAuthState>['logoutMutation']
278
+ continueChat: boolean
279
+ continueChatId: string | undefined
280
+ authStatus: AuthStatus
281
+ initialMode: AgentMode | undefined
282
+ gitRoot: string | null | undefined
283
+ onSwitchToGitRoot: () => void
284
+ showChatHistory: boolean
285
+ onSelectChat: (chatId: string) => void
286
+ onCancelChatHistory: () => void
287
+ onNewChat: () => void
288
+ }
289
+
290
+ /**
291
+ * Rendered only after auth is confirmed. Owns the anvil session gate
292
+ * so `useAnvilSession` runs exactly once per authed session (not before
293
+ * we have a token).
294
+ */
295
+ const AuthedSurface = (props: AuthedSurfaceProps) => {
296
+ const { session, failure: sessionFailure } = useAnvilSession()
297
+
298
+ return (
299
+ <ChatRuntimeProvider
300
+ key={props.runtimeKey}
301
+ agentId={props.agentId}
302
+ inputRef={props.inputRef}
303
+ continueChat={props.continueChat}
304
+ continueChatId={props.continueChatId}
305
+ >
306
+ <AuthedSurfaceRoutes
307
+ {...props}
308
+ session={session}
309
+ sessionFailure={sessionFailure}
310
+ />
311
+ </ChatRuntimeProvider>
312
+ )
313
+ }
314
+
315
+ const AuthedSurfaceRoutes = ({
316
+ consumeInitialPrompt,
317
+ fileTree,
318
+ inputRef,
319
+ setIsAuthenticated,
320
+ setUser,
321
+ logoutMutation,
322
+ authStatus,
323
+ initialMode,
324
+ gitRoot,
325
+ onSwitchToGitRoot,
326
+ showChatHistory,
327
+ onSelectChat,
328
+ onCancelChatHistory,
329
+ onNewChat,
330
+ session,
331
+ sessionFailure,
332
+ }: AuthedSurfaceProps & {
333
+ session: ReturnType<typeof useAnvilSession>['session']
334
+ sessionFailure: ReturnType<typeof useAnvilSession>['failure']
335
+ }) => {
336
+ // Terminal state: a 409 from the gate means another CLI rotated our
337
+ // instance id. Show a dedicated screen and stop polling — don't fall back
338
+ // into the pre-chat screen, which would look like normal startup progress.
339
+ if (IS_ANVIL && session?.status === 'superseded') {
340
+ return <AnvilSupersededScreen />
341
+ }
342
+
343
+ // Route every non-admitted state through the pre-chat screen:
344
+ // null → initial GET in flight (brief)
345
+ // 'none' → no seat yet; show model-picker landing
346
+ // 'country_blocked' → terminal region-gate message
347
+ // 'banned' → terminal account-banned message
348
+ // 'rate_limited' → hit shared session quota; terminal for this run
349
+ // 'spend_limited' → daily provider-spend budget; return after reset
350
+ // 'ip_capped' → too many distinct users active on this egress IP
351
+ // 'takeover_prompt' → another local CLI already holds this account
352
+ //
353
+ // 'ended' deliberately falls through to <Chat>: the agent may still be
354
+ // finishing work under the server-side grace period, and the chat surface
355
+ // itself swaps the input box for the session-ended banner.
356
+ if (
357
+ IS_ANVIL &&
358
+ (session === null ||
359
+ session.status === 'none' ||
360
+ session.status === 'country_blocked' ||
361
+ session.status === 'banned' ||
362
+ session.status === 'rate_limited' ||
363
+ session.status === 'spend_limited' ||
364
+ session.status === 'ip_capped' ||
365
+ session.status === 'takeover_prompt')
366
+ ) {
367
+ return <AnvilLandingScreen session={session} failure={sessionFailure} />
368
+ }
369
+
370
+ // Chat history renders inside AuthedSurface so the anvil session stays
371
+ // mounted while the user browses history. Unmounting this surface would
372
+ // DELETE the session row and drop the user back onto the landing screen on
373
+ // return.
374
+ if (showChatHistory) {
375
+ return (
376
+ <ChatHistoryScreen
377
+ onSelectChat={onSelectChat}
378
+ onCancel={onCancelChatHistory}
379
+ onNewChat={onNewChat}
380
+ />
381
+ )
382
+ }
383
+
384
+ return (
385
+ <Chat
386
+ consumeInitialPrompt={consumeInitialPrompt}
387
+ fileTree={fileTree}
388
+ inputRef={inputRef}
389
+ setIsAuthenticated={setIsAuthenticated}
390
+ setUser={setUser}
391
+ logoutMutation={logoutMutation}
392
+ authStatus={authStatus}
393
+ initialMode={initialMode}
394
+ gitRoot={gitRoot}
395
+ onSwitchToGitRoot={onSwitchToGitRoot}
396
+ anvilSession={session}
397
+ />
398
+ )
399
+ }