@alumbwe/anvil 1.0.0 → 1.0.1

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/bin/anvil +1 -1
  2. package/dist/bundled.js +79559 -0
  3. package/dist/bundled.js.map +581 -0
  4. package/package.json +5 -2
  5. package/src/__tests__/README.md +0 -256
  6. package/src/__tests__/bash-mode.test.ts +0 -442
  7. package/src/__tests__/cli-args.test.ts +0 -181
  8. package/src/__tests__/cli-harness.test.ts +0 -52
  9. package/src/__tests__/e2e/first-time-login.test.ts +0 -173
  10. package/src/__tests__/e2e/logout-relogin-flow.test.ts +0 -110
  11. package/src/__tests__/e2e/returning-user-auth.test.ts +0 -113
  12. package/src/__tests__/e2e-cli.test.ts +0 -183
  13. package/src/__tests__/helpers/launcher-disconnect-fixture.cjs +0 -176
  14. package/src/__tests__/helpers/mock-api-client.ts +0 -64
  15. package/src/__tests__/helpers/renderer-cleanup-fixture.tsx +0 -89
  16. package/src/__tests__/helpers/terminal-watchdog-fixture.ts +0 -75
  17. package/src/__tests__/home-directory-detection.test.ts +0 -213
  18. package/src/__tests__/integration/api-integration.test.ts +0 -288
  19. package/src/__tests__/integration/credentials-storage.test.ts +0 -486
  20. package/src/__tests__/integration/local-agents.test.ts +0 -1187
  21. package/src/__tests__/integration/login-flow-instrumentation.test.ts +0 -134
  22. package/src/__tests__/integration/login-polling-working.test.ts +0 -285
  23. package/src/__tests__/integration/queue-editing.test.tsx +0 -261
  24. package/src/__tests__/integration/usage-refresh-on-completion.test.ts +0 -168
  25. package/src/__tests__/integration-tmux.test.ts +0 -188
  26. package/src/__tests__/launcher-avx2-fallback.test.ts +0 -630
  27. package/src/__tests__/launcher-disconnect.test.ts +0 -104
  28. package/src/__tests__/mocks/hover-toggle-controller.ts +0 -71
  29. package/src/__tests__/open-tui-native-bundle.test.ts +0 -378
  30. package/src/__tests__/path-completion.test.ts +0 -243
  31. package/src/__tests__/project-files-chat-id.test.ts +0 -34
  32. package/src/__tests__/release/proxy-http-get.test.ts +0 -667
  33. package/src/__tests__/release/wrapper-safety.test.ts +0 -412
  34. package/src/__tests__/renderer-cleanup.test.ts +0 -174
  35. package/src/__tests__/rerender-perf.integration.test.ts +0 -283
  36. package/src/__tests__/terminal-reset-sequences.test.ts +0 -36
  37. package/src/__tests__/terminal-watchdog.test.ts +0 -388
  38. package/src/__tests__/test-utils.ts +0 -271
  39. package/src/__tests__/tmux-poc.ts +0 -150
  40. package/src/__tests__/unit/agent-mode-toggle.test.ts +0 -137
  41. package/src/__tests__/unit/copy-button.test.ts +0 -157
  42. package/src/__tests__/unit/create-run-config.test.ts +0 -66
  43. package/src/__tests__/unit/publish-confirmation.test.ts +0 -70
  44. package/src/__tests__/unit/segmented-control.test.ts +0 -152
  45. package/src/__tests__/utils/env.test.ts +0 -169
  46. package/src/__tests__/utils/project-picker.test.ts +0 -39
  47. package/src/agents/bundled-agents.generated.d.ts +0 -14
  48. package/src/agents/bundled-agents.generated.ts +0 -3692
  49. package/src/app.tsx +0 -399
  50. package/src/chat.tsx +0 -1698
  51. package/src/cli-args.ts +0 -134
  52. package/src/commands/__tests__/bash-command.test.ts +0 -445
  53. package/src/commands/__tests__/command-args.test.ts +0 -349
  54. package/src/commands/__tests__/copy-conversation-clipboard.test.ts +0 -108
  55. package/src/commands/__tests__/copy-conversation.test.ts +0 -226
  56. package/src/commands/__tests__/diagnostics-command.test.ts +0 -35
  57. package/src/commands/__tests__/freebuff-command-aliases.test.ts +0 -56
  58. package/src/commands/__tests__/image.test.ts +0 -99
  59. package/src/commands/__tests__/init.test.ts +0 -456
  60. package/src/commands/__tests__/new-command-rotates-chat.test.ts +0 -91
  61. package/src/commands/__tests__/process-diagnostics.test.ts +0 -54
  62. package/src/commands/__tests__/prompt-builders.test.ts +0 -28
  63. package/src/commands/__tests__/router-input.test.ts +0 -298
  64. package/src/commands/ads.ts +0 -44
  65. package/src/commands/command-registry.ts +0 -726
  66. package/src/commands/copy-conversation.ts +0 -392
  67. package/src/commands/help.ts +0 -13
  68. package/src/commands/image.ts +0 -20
  69. package/src/commands/init.ts +0 -121
  70. package/src/commands/process-diagnostics.ts +0 -120
  71. package/src/commands/prompt-builders.ts +0 -100
  72. package/src/commands/publish.ts +0 -203
  73. package/src/commands/router-utils.ts +0 -80
  74. package/src/commands/router.ts +0 -487
  75. package/src/commands/usage.ts +0 -26
  76. package/src/components/__tests__/ad-banner.test.tsx +0 -83
  77. package/src/components/__tests__/chat-input-bar.test.tsx +0 -130
  78. package/src/components/__tests__/freebuff-landing-heading-row.test.tsx +0 -91
  79. package/src/components/__tests__/freebuff-model-selector.test.tsx +0 -519
  80. package/src/components/__tests__/freebuff-offer-invariants.test.ts +0 -54
  81. package/src/components/__tests__/freebuff-takeover-prompt.test.tsx +0 -212
  82. package/src/components/__tests__/grid-layout.integration.test.tsx +0 -304
  83. package/src/components/__tests__/grid-layout.test.tsx +0 -1051
  84. package/src/components/__tests__/message-block.completion.test.tsx +0 -104
  85. package/src/components/__tests__/message-block.streaming.test.tsx +0 -78
  86. package/src/components/__tests__/message-with-agents.test.tsx +0 -579
  87. package/src/components/__tests__/multiline-input.test.tsx +0 -1132
  88. package/src/components/__tests__/queue-panel.test.tsx +0 -398
  89. package/src/components/__tests__/selectable-list.test.ts +0 -232
  90. package/src/components/__tests__/status-bar.test.tsx +0 -44
  91. package/src/components/__tests__/status-indicator.test.tsx +0 -204
  92. package/src/components/__tests__/terminal-thinking-orb.test.tsx +0 -111
  93. package/src/components/__tests__/user-error-banner.test.tsx +0 -102
  94. package/src/components/ad-banner.tsx +0 -323
  95. package/src/components/agent-checklist.tsx +0 -350
  96. package/src/components/agent-mode-toggle.tsx +0 -241
  97. package/src/components/anvil-mark.tsx +0 -52
  98. package/src/components/ask-user/__tests__/multiple-choice-form.test.ts +0 -432
  99. package/src/components/ask-user/__tests__/validation.test.ts +0 -213
  100. package/src/components/ask-user/components/accordion-question.tsx +0 -153
  101. package/src/components/ask-user/components/custom-answer-input.tsx +0 -66
  102. package/src/components/ask-user/components/options-list.tsx +0 -133
  103. package/src/components/ask-user/components/question-header.tsx +0 -80
  104. package/src/components/ask-user/components/question-option.tsx +0 -89
  105. package/src/components/ask-user/constants.ts +0 -38
  106. package/src/components/ask-user/index.tsx +0 -631
  107. package/src/components/ask-user/utils/validation.ts +0 -85
  108. package/src/components/attachment-card.tsx +0 -65
  109. package/src/components/blocks/agent-block-grid.tsx +0 -58
  110. package/src/components/blocks/agent-branch-item.tsx +0 -311
  111. package/src/components/blocks/agent-branch-wrapper.tsx +0 -493
  112. package/src/components/blocks/agent-list-branch.tsx +0 -77
  113. package/src/components/blocks/ask-user-branch.tsx +0 -81
  114. package/src/components/blocks/block-helpers.ts +0 -11
  115. package/src/components/blocks/blocks-renderer.tsx +0 -289
  116. package/src/components/blocks/content-with-markdown.tsx +0 -33
  117. package/src/components/blocks/image-block.tsx +0 -128
  118. package/src/components/blocks/implementor-row.tsx +0 -429
  119. package/src/components/blocks/single-block.tsx +0 -201
  120. package/src/components/blocks/thinking-block.tsx +0 -67
  121. package/src/components/blocks/tool-block-group.tsx +0 -57
  122. package/src/components/blocks/tool-branch.tsx +0 -206
  123. package/src/components/blocks/user-content-copy.tsx +0 -157
  124. package/src/components/bottom-banner.tsx +0 -136
  125. package/src/components/build-mode-buttons.tsx +0 -110
  126. package/src/components/button.tsx +0 -66
  127. package/src/components/chat-header.tsx +0 -77
  128. package/src/components/chat-history-screen.tsx +0 -413
  129. package/src/components/chat-input-bar.tsx +0 -523
  130. package/src/components/clickable-title-box.tsx +0 -66
  131. package/src/components/clickable.tsx +0 -119
  132. package/src/components/collapse-button.tsx +0 -34
  133. package/src/components/copy-button.tsx +0 -203
  134. package/src/components/elapsed-timer.tsx +0 -55
  135. package/src/components/error-boundary.tsx +0 -55
  136. package/src/components/feedback-container.tsx +0 -181
  137. package/src/components/feedback-icon-button.tsx +0 -89
  138. package/src/components/feedback-input-mode.tsx +0 -344
  139. package/src/components/file-attachment-card.tsx +0 -98
  140. package/src/components/freebuff-active-session-summary.tsx +0 -63
  141. package/src/components/freebuff-landing-screen.tsx +0 -865
  142. package/src/components/freebuff-model-selector.tsx +0 -1087
  143. package/src/components/freebuff-referral-banner.tsx +0 -604
  144. package/src/components/freebuff-superseded-screen.tsx +0 -62
  145. package/src/components/grid-layout.tsx +0 -80
  146. package/src/components/help-banner.tsx +0 -127
  147. package/src/components/highlighted-text.tsx +0 -52
  148. package/src/components/image-card.tsx +0 -167
  149. package/src/components/image-thumbnail.tsx +0 -114
  150. package/src/components/input-cursor.tsx +0 -77
  151. package/src/components/input-mode-banner.tsx +0 -57
  152. package/src/components/load-previous-button.tsx +0 -48
  153. package/src/components/login-modal.tsx +0 -475
  154. package/src/components/message-block.tsx +0 -346
  155. package/src/components/message-footer.tsx +0 -258
  156. package/src/components/message-with-agents.tsx +0 -506
  157. package/src/components/mode-divider.tsx +0 -43
  158. package/src/components/multiline-input.tsx +0 -1241
  159. package/src/components/out-of-credits-banner.tsx +0 -160
  160. package/src/components/pending-attachments-banner.tsx +0 -116
  161. package/src/components/pending-bash-message.tsx +0 -59
  162. package/src/components/progress-bar.tsx +0 -81
  163. package/src/components/project-picker-screen.tsx +0 -485
  164. package/src/components/publish-confirmation.tsx +0 -493
  165. package/src/components/publish-container.tsx +0 -687
  166. package/src/components/queue-panel.tsx +0 -310
  167. package/src/components/raised-pill.tsx +0 -95
  168. package/src/components/renderers/plan-box.tsx +0 -59
  169. package/src/components/review-screen.tsx +0 -112
  170. package/src/components/scroll-to-bottom-button.tsx +0 -34
  171. package/src/components/segmented-control.tsx +0 -187
  172. package/src/components/selectable-list.tsx +0 -248
  173. package/src/components/selected-chips.tsx +0 -80
  174. package/src/components/separator.tsx +0 -40
  175. package/src/components/session-ended-banner.tsx +0 -226
  176. package/src/components/shimmer-text.tsx +0 -248
  177. package/src/components/status-bar.tsx +0 -313
  178. package/src/components/subscription-limit-banner.tsx +0 -206
  179. package/src/components/suggested-prompts.tsx +0 -184
  180. package/src/components/suggestion-menu.tsx +0 -215
  181. package/src/components/terminal-command-display.tsx +0 -151
  182. package/src/components/terminal-link.tsx +0 -97
  183. package/src/components/terminal-thinking-orb.tsx +0 -95
  184. package/src/components/text-attachment-card.tsx +0 -77
  185. package/src/components/thinking.tsx +0 -109
  186. package/src/components/tools/__tests__/apply-patch.test.tsx +0 -84
  187. package/src/components/tools/__tests__/code-search.test.tsx +0 -45
  188. package/src/components/tools/__tests__/gravity-index.test.ts +0 -76
  189. package/src/components/tools/__tests__/render-ui.test.tsx +0 -92
  190. package/src/components/tools/__tests__/run-terminal-command.test.ts +0 -233
  191. package/src/components/tools/apply-patch.tsx +0 -95
  192. package/src/components/tools/code-search.tsx +0 -45
  193. package/src/components/tools/composio.tsx +0 -152
  194. package/src/components/tools/diff-viewer.tsx +0 -76
  195. package/src/components/tools/glob.tsx +0 -61
  196. package/src/components/tools/gravity-index.tsx +0 -77
  197. package/src/components/tools/list-directory.tsx +0 -61
  198. package/src/components/tools/read-docs.tsx +0 -37
  199. package/src/components/tools/read-files.tsx +0 -91
  200. package/src/components/tools/read-subtree.tsx +0 -44
  201. package/src/components/tools/read-url.tsx +0 -33
  202. package/src/components/tools/registry.ts +0 -126
  203. package/src/components/tools/render-ui.tsx +0 -122
  204. package/src/components/tools/run-terminal-command.tsx +0 -79
  205. package/src/components/tools/skill.tsx +0 -29
  206. package/src/components/tools/str-replace.tsx +0 -77
  207. package/src/components/tools/suggest-followups.tsx +0 -369
  208. package/src/components/tools/task-completed.tsx +0 -16
  209. package/src/components/tools/tool-call-item.tsx +0 -273
  210. package/src/components/tools/types.ts +0 -55
  211. package/src/components/tools/web-search.tsx +0 -33
  212. package/src/components/tools/write-file.tsx +0 -16
  213. package/src/components/tools/write-todos.tsx +0 -95
  214. package/src/components/top-banner.tsx +0 -178
  215. package/src/components/usage-banner.tsx +0 -244
  216. package/src/components/user-error-banner.tsx +0 -56
  217. package/src/components/validation-error-popover.tsx +0 -192
  218. package/src/contexts/__tests__/chat-runtime-context.test.tsx +0 -149
  219. package/src/contexts/chat-runtime-context.tsx +0 -240
  220. package/src/data/slash-commands.test.ts +0 -24
  221. package/src/data/slash-commands.ts +0 -249
  222. package/src/entry.ts +0 -12
  223. package/src/hooks/__tests__/holds-live-freebuff-slot.test.ts +0 -49
  224. package/src/hooks/__tests__/session-fetch-signal.test.ts +0 -63
  225. package/src/hooks/__tests__/use-activity-query.test.ts +0 -1000
  226. package/src/hooks/__tests__/use-ask-user-bridge.test.ts +0 -176
  227. package/src/hooks/__tests__/use-auth-query.test.ts +0 -21
  228. package/src/hooks/__tests__/use-chat-input-remount.test.tsx +0 -66
  229. package/src/hooks/__tests__/use-clipboard.test.tsx +0 -73
  230. package/src/hooks/__tests__/use-connection-status.test.ts +0 -112
  231. package/src/hooks/__tests__/use-directory-browser.test.ts +0 -203
  232. package/src/hooks/__tests__/use-gravity-ad.test.ts +0 -73
  233. package/src/hooks/__tests__/use-grid-layout.test.ts +0 -349
  234. package/src/hooks/__tests__/use-input-history.test.ts +0 -699
  235. package/src/hooks/__tests__/use-message-queue-editing.test.tsx +0 -209
  236. package/src/hooks/__tests__/use-message-queue.test.tsx +0 -71
  237. package/src/hooks/__tests__/use-path-tab-completion.test.ts +0 -315
  238. package/src/hooks/__tests__/use-queue-controls.test.ts +0 -68
  239. package/src/hooks/__tests__/use-queue-ui.test.tsx +0 -83
  240. package/src/hooks/__tests__/use-searchable-list.test.ts +0 -359
  241. package/src/hooks/__tests__/use-send-message-timer.test.ts +0 -146
  242. package/src/hooks/__tests__/use-suggestion-engine-mention.test.ts +0 -361
  243. package/src/hooks/__tests__/use-suggestion-engine.test.ts +0 -485
  244. package/src/hooks/__tests__/use-terminal-focus.test.ts +0 -66
  245. package/src/hooks/__tests__/use-terminal-layout.test.ts +0 -675
  246. package/src/hooks/__tests__/use-timeout.test.ts +0 -330
  247. package/src/hooks/__tests__/use-usage-query.test.ts +0 -502
  248. package/src/hooks/__tests__/use-user-details-query.test.ts +0 -195
  249. package/src/hooks/helpers/__tests__/send-message.test.ts +0 -1918
  250. package/src/hooks/helpers/send-message.ts +0 -654
  251. package/src/hooks/stream-state.ts +0 -83
  252. package/src/hooks/use-activity-query.ts +0 -668
  253. package/src/hooks/use-agent-validation.ts +0 -74
  254. package/src/hooks/use-ask-user-bridge.ts +0 -92
  255. package/src/hooks/use-auth-query.ts +0 -253
  256. package/src/hooks/use-auth-state.ts +0 -152
  257. package/src/hooks/use-chat-input.ts +0 -105
  258. package/src/hooks/use-chat-keyboard.ts +0 -321
  259. package/src/hooks/use-chat-messages.ts +0 -254
  260. package/src/hooks/use-chat-state.ts +0 -165
  261. package/src/hooks/use-chat-streaming.ts +0 -180
  262. package/src/hooks/use-chat-ui.ts +0 -131
  263. package/src/hooks/use-clipboard.ts +0 -151
  264. package/src/hooks/use-connection-status.ts +0 -142
  265. package/src/hooks/use-directory-browser.ts +0 -88
  266. package/src/hooks/use-elapsed-time.ts +0 -116
  267. package/src/hooks/use-event.ts +0 -34
  268. package/src/hooks/use-exit-handler.ts +0 -66
  269. package/src/hooks/use-fetch-login-url.ts +0 -65
  270. package/src/hooks/use-fingerprint.ts +0 -61
  271. package/src/hooks/use-freebuff-ctrl-c-exit.ts +0 -23
  272. package/src/hooks/use-freebuff-session-progress.ts +0 -34
  273. package/src/hooks/use-freebuff-session.ts +0 -806
  274. package/src/hooks/use-freebuff-streak-query.ts +0 -61
  275. package/src/hooks/use-gravity-ad.ts +0 -656
  276. package/src/hooks/use-grid-layout.ts +0 -73
  277. package/src/hooks/use-input-history.ts +0 -173
  278. package/src/hooks/use-login-keyboard-handlers.ts +0 -75
  279. package/src/hooks/use-login-polling.ts +0 -114
  280. package/src/hooks/use-logo.tsx +0 -161
  281. package/src/hooks/use-message-queue.ts +0 -387
  282. package/src/hooks/use-now.ts +0 -20
  283. package/src/hooks/use-path-tab-completion.ts +0 -88
  284. package/src/hooks/use-publish-mutation.ts +0 -60
  285. package/src/hooks/use-queue-controls.ts +0 -68
  286. package/src/hooks/use-queue-ui.ts +0 -74
  287. package/src/hooks/use-scroll-management.ts +0 -184
  288. package/src/hooks/use-searchable-list.ts +0 -98
  289. package/src/hooks/use-send-message.ts +0 -773
  290. package/src/hooks/use-sheen-animation.tsx +0 -88
  291. package/src/hooks/use-subscription-query.ts +0 -71
  292. package/src/hooks/use-suggestion-engine.ts +0 -783
  293. package/src/hooks/use-terminal-breakpoints.ts +0 -77
  294. package/src/hooks/use-terminal-dimensions.ts +0 -46
  295. package/src/hooks/use-terminal-focus.ts +0 -29
  296. package/src/hooks/use-terminal-layout.ts +0 -189
  297. package/src/hooks/use-theme.tsx +0 -140
  298. package/src/hooks/use-timeout.ts +0 -85
  299. package/src/hooks/use-update-preference.ts +0 -66
  300. package/src/hooks/use-usage-monitor.ts +0 -55
  301. package/src/hooks/use-usage-query.ts +0 -124
  302. package/src/hooks/use-user-details-query.ts +0 -93
  303. package/src/hooks/use-why-did-you-update.ts +0 -177
  304. package/src/index.tsx +0 -441
  305. package/src/init/__tests__/init-direnv.test.ts +0 -526
  306. package/src/init/init-app.ts +0 -34
  307. package/src/init/init-direnv.ts +0 -133
  308. package/src/login/constants.ts +0 -60
  309. package/src/login/login-flow.ts +0 -204
  310. package/src/login/plain-login.ts +0 -108
  311. package/src/login/utils.ts +0 -183
  312. package/src/native/ripgrep.ts +0 -80
  313. package/src/polyfills/bun-strip-ansi.ts +0 -12
  314. package/src/pre-init/tree-sitter-wasm.ts +0 -96
  315. package/src/project-files.ts +0 -102
  316. package/src/smoke/terminal-command-broker.ts +0 -439
  317. package/src/state/__tests__/chat-store-focus.test.ts +0 -22
  318. package/src/state/__tests__/feedback-store.test.ts +0 -257
  319. package/src/state/chat-history-store.ts +0 -30
  320. package/src/state/chat-store.ts +0 -544
  321. package/src/state/feedback-store.ts +0 -160
  322. package/src/state/freebuff-model-store.ts +0 -42
  323. package/src/state/freebuff-session-store.ts +0 -53
  324. package/src/state/login-store.ts +0 -150
  325. package/src/state/message-block-store.ts +0 -149
  326. package/src/state/publish-store.ts +0 -146
  327. package/src/state/queue-panel-store.ts +0 -26
  328. package/src/state/review-store.ts +0 -24
  329. package/src/testing/env.ts +0 -46
  330. package/src/types/chat-state.ts +0 -15
  331. package/src/types/chat.ts +0 -241
  332. package/src/types/contracts/send-message.ts +0 -12
  333. package/src/types/env.ts +0 -98
  334. package/src/types/freebuff-session.ts +0 -17
  335. package/src/types/function-params.ts +0 -28
  336. package/src/types/react19-compat.d.ts +0 -19
  337. package/src/types/store.ts +0 -111
  338. package/src/types/theme-system.ts +0 -144
  339. package/src/types/utils.ts +0 -3
  340. package/src/utils/__tests__/active-run.test.ts +0 -140
  341. package/src/utils/__tests__/activity-tracker.test.ts +0 -440
  342. package/src/utils/__tests__/agent-display.test.ts +0 -139
  343. package/src/utils/__tests__/analytics-client.test.ts +0 -262
  344. package/src/utils/__tests__/anonymous-id.test.ts +0 -74
  345. package/src/utils/__tests__/anvil-api.test.ts +0 -578
  346. package/src/utils/__tests__/arrays.test.ts +0 -264
  347. package/src/utils/__tests__/bash-context-processor.test.ts +0 -38
  348. package/src/utils/__tests__/block-processor.test.ts +0 -810
  349. package/src/utils/__tests__/chat-history.test.ts +0 -203
  350. package/src/utils/__tests__/chat-input-key-intercept.test.ts +0 -40
  351. package/src/utils/__tests__/chat-meta.test.ts +0 -130
  352. package/src/utils/__tests__/clipboard-linux.test.ts +0 -359
  353. package/src/utils/__tests__/clipboard.test.ts +0 -910
  354. package/src/utils/__tests__/code-search-summary.test.ts +0 -84
  355. package/src/utils/__tests__/collapse-helpers.test.ts +0 -1109
  356. package/src/utils/__tests__/error-handling.test.ts +0 -658
  357. package/src/utils/__tests__/exit-cleanly.test.ts +0 -110
  358. package/src/utils/__tests__/feedback-helpers.test.ts +0 -444
  359. package/src/utils/__tests__/feedback-submission.test.ts +0 -26
  360. package/src/utils/__tests__/fetch-usage.test.ts +0 -355
  361. package/src/utils/__tests__/fingerprint.test.ts +0 -144
  362. package/src/utils/__tests__/fixtures/terminal-command-broker-child.ts +0 -7
  363. package/src/utils/__tests__/fixtures/terminal-command-broker-entry.ts +0 -3
  364. package/src/utils/__tests__/fixtures/terminal-command-broker-owner.ts +0 -33
  365. package/src/utils/__tests__/format-elapsed-time.test.ts +0 -103
  366. package/src/utils/__tests__/format-timeout.test.ts +0 -87
  367. package/src/utils/__tests__/freebuff-instance-owner.test.ts +0 -69
  368. package/src/utils/__tests__/freebuff-model-navigation.test.ts +0 -102
  369. package/src/utils/__tests__/freebuff-premium-reset.test.ts +0 -79
  370. package/src/utils/__tests__/freebuff-referral-cache.test.ts +0 -116
  371. package/src/utils/__tests__/freebuff-session-api.test.ts +0 -215
  372. package/src/utils/__tests__/freebuff-session-display.test.ts +0 -23
  373. package/src/utils/__tests__/freebuff-streak-line.test.ts +0 -217
  374. package/src/utils/__tests__/image-dimensions.test.ts +0 -249
  375. package/src/utils/__tests__/image-processor.test.ts +0 -209
  376. package/src/utils/__tests__/implementor-helpers.test.ts +0 -1458
  377. package/src/utils/__tests__/keyboard-actions.test.ts +0 -660
  378. package/src/utils/__tests__/layout-helpers.test.ts +0 -36
  379. package/src/utils/__tests__/lazy-response-ads.test.ts +0 -167
  380. package/src/utils/__tests__/log-shipper.test.ts +0 -53
  381. package/src/utils/__tests__/markdown-renderer.test.tsx +0 -421
  382. package/src/utils/__tests__/message-block-helpers.test.ts +0 -1263
  383. package/src/utils/__tests__/message-updater.test.ts +0 -645
  384. package/src/utils/__tests__/osc-timeout-scenarios.test.ts +0 -172
  385. package/src/utils/__tests__/pending-attachments.test.ts +0 -277
  386. package/src/utils/__tests__/polling-backoff.test.ts +0 -51
  387. package/src/utils/__tests__/queue-panel-actions.test.ts +0 -148
  388. package/src/utils/__tests__/run-state-storage.test.ts +0 -919
  389. package/src/utils/__tests__/safe-json.test.ts +0 -77
  390. package/src/utils/__tests__/sdk-event-handlers.test.ts +0 -685
  391. package/src/utils/__tests__/send-message-helpers.test.ts +0 -1898
  392. package/src/utils/__tests__/send-message-timer.test.ts +0 -64
  393. package/src/utils/__tests__/settings.test.ts +0 -99
  394. package/src/utils/__tests__/strings.test.ts +0 -192
  395. package/src/utils/__tests__/terminal-color-detection.test.ts +0 -425
  396. package/src/utils/__tests__/terminal-command-broker.test.ts +0 -528
  397. package/src/utils/__tests__/terminal-enter-detection.test.ts +0 -77
  398. package/src/utils/__tests__/terminal-io.test.ts +0 -137
  399. package/src/utils/__tests__/terminal-protocol-controller.test.ts +0 -119
  400. package/src/utils/__tests__/text-layout.test.ts +0 -82
  401. package/src/utils/__tests__/theme-platform-detection.test.ts +0 -125
  402. package/src/utils/__tests__/think-tag-parser.test.ts +0 -159
  403. package/src/utils/__tests__/trace-writer.test.ts +0 -223
  404. package/src/utils/__tests__/trim-chat-logs.test.ts +0 -78
  405. package/src/utils/__tests__/usage-banner-state.test.ts +0 -298
  406. package/src/utils/__tests__/validation-error-formatting.test.ts +0 -126
  407. package/src/utils/__tests__/windows-terminal-health.test.ts +0 -101
  408. package/src/utils/__tests__/write-file-atomic.test.ts +0 -127
  409. package/src/utils/active-run.ts +0 -131
  410. package/src/utils/activity-tracker.ts +0 -66
  411. package/src/utils/agent-display.ts +0 -87
  412. package/src/utils/agent-helpers.ts +0 -27
  413. package/src/utils/agent-id-utils.ts +0 -14
  414. package/src/utils/ai-message-id.ts +0 -12
  415. package/src/utils/analytics.ts +0 -361
  416. package/src/utils/anonymous-id.ts +0 -87
  417. package/src/utils/anvil-api.ts +0 -612
  418. package/src/utils/anvil-client.ts +0 -217
  419. package/src/utils/arrays.ts +0 -117
  420. package/src/utils/auth.ts +0 -258
  421. package/src/utils/bash-context-processor.ts +0 -47
  422. package/src/utils/bash-messages.ts +0 -108
  423. package/src/utils/block-margins.ts +0 -35
  424. package/src/utils/block-operations.ts +0 -523
  425. package/src/utils/block-processor.ts +0 -213
  426. package/src/utils/chat-history.ts +0 -253
  427. package/src/utils/chat-input-key-intercept.ts +0 -52
  428. package/src/utils/chat-meta.ts +0 -90
  429. package/src/utils/chat-scroll-accel.ts +0 -151
  430. package/src/utils/clipboard-image.ts +0 -588
  431. package/src/utils/clipboard.ts +0 -397
  432. package/src/utils/code-search-summary.ts +0 -70
  433. package/src/utils/collapse-helpers.ts +0 -256
  434. package/src/utils/config-dir.ts +0 -24
  435. package/src/utils/constants.ts +0 -190
  436. package/src/utils/create-event-handler-state.ts +0 -73
  437. package/src/utils/create-run-config.ts +0 -121
  438. package/src/utils/detect-shell.ts +0 -116
  439. package/src/utils/directory-browser.ts +0 -72
  440. package/src/utils/engagement.ts +0 -55
  441. package/src/utils/env.ts +0 -92
  442. package/src/utils/error-handling.ts +0 -255
  443. package/src/utils/error-messages.ts +0 -62
  444. package/src/utils/exit-cleanly.ts +0 -86
  445. package/src/utils/feedback-helpers.ts +0 -103
  446. package/src/utils/feedback-submission.ts +0 -22
  447. package/src/utils/fetch-usage.ts +0 -76
  448. package/src/utils/fingerprint.ts +0 -245
  449. package/src/utils/format-elapsed-time.ts +0 -33
  450. package/src/utils/format-session-units.ts +0 -6
  451. package/src/utils/format-timeout.ts +0 -28
  452. package/src/utils/format-validation-errors-for-message.ts +0 -84
  453. package/src/utils/freebuff-agent-selection.ts +0 -33
  454. package/src/utils/freebuff-instance-owner.ts +0 -66
  455. package/src/utils/freebuff-model-navigation.ts +0 -50
  456. package/src/utils/freebuff-premium-reset.ts +0 -55
  457. package/src/utils/freebuff-referral-cache.ts +0 -51
  458. package/src/utils/freebuff-session-api.ts +0 -243
  459. package/src/utils/freebuff-session-display.ts +0 -21
  460. package/src/utils/freebuff-streak-line.ts +0 -93
  461. package/src/utils/git.ts +0 -17
  462. package/src/utils/helpers.ts +0 -47
  463. package/src/utils/image-display.ts +0 -67
  464. package/src/utils/image-handler.ts +0 -325
  465. package/src/utils/image-processor.ts +0 -133
  466. package/src/utils/image-thumbnail.ts +0 -78
  467. package/src/utils/implementor-helpers.ts +0 -787
  468. package/src/utils/input-modes.ts +0 -174
  469. package/src/utils/keyboard-actions.ts +0 -392
  470. package/src/utils/keypad-keys.ts +0 -47
  471. package/src/utils/layout-helpers.ts +0 -33
  472. package/src/utils/lazy-response-ads.ts +0 -1
  473. package/src/utils/local-agent-registry.ts +0 -474
  474. package/src/utils/log-shipper.ts +0 -126
  475. package/src/utils/logger.ts +0 -327
  476. package/src/utils/markdown-renderer.tsx +0 -1090
  477. package/src/utils/math.ts +0 -3
  478. package/src/utils/message-block-helpers.ts +0 -684
  479. package/src/utils/message-history.ts +0 -143
  480. package/src/utils/message-tree-utils.ts +0 -67
  481. package/src/utils/message-updater.ts +0 -279
  482. package/src/utils/open-file.ts +0 -146
  483. package/src/utils/open-url.ts +0 -63
  484. package/src/utils/path-completion.ts +0 -111
  485. package/src/utils/path-helpers.ts +0 -38
  486. package/src/utils/pending-attachments.ts +0 -360
  487. package/src/utils/polling-backoff.ts +0 -59
  488. package/src/utils/project-picker.ts +0 -12
  489. package/src/utils/queue-panel-actions.ts +0 -70
  490. package/src/utils/recent-projects.ts +0 -156
  491. package/src/utils/renderer-cleanup.ts +0 -233
  492. package/src/utils/response-ad-positions.ts +0 -1
  493. package/src/utils/run-state-storage.ts +0 -603
  494. package/src/utils/safe-json.ts +0 -153
  495. package/src/utils/sdk-event-handlers.ts +0 -571
  496. package/src/utils/send-message-helpers.ts +0 -210
  497. package/src/utils/send-message-timer.ts +0 -110
  498. package/src/utils/settings.ts +0 -226
  499. package/src/utils/skill-registry.ts +0 -94
  500. package/src/utils/spawn-agent-matcher.ts +0 -55
  501. package/src/utils/status-indicator-state.ts +0 -107
  502. package/src/utils/stream-chunk-processor.ts +0 -57
  503. package/src/utils/strings.ts +0 -271
  504. package/src/utils/subscription.ts +0 -31
  505. package/src/utils/syntax-highlighter.tsx +0 -19
  506. package/src/utils/terminal-color-detection.ts +0 -474
  507. package/src/utils/terminal-command-broker.ts +0 -467
  508. package/src/utils/terminal-enter-detection.ts +0 -63
  509. package/src/utils/terminal-images.ts +0 -229
  510. package/src/utils/terminal-io.ts +0 -85
  511. package/src/utils/terminal-protocol-controller.ts +0 -173
  512. package/src/utils/terminal-reset-sequences.ts +0 -33
  513. package/src/utils/terminal-title.ts +0 -84
  514. package/src/utils/terminal-watchdog.ts +0 -366
  515. package/src/utils/text-layout.ts +0 -149
  516. package/src/utils/theme-config.ts +0 -141
  517. package/src/utils/theme-system.ts +0 -1206
  518. package/src/utils/think-tag-parser.ts +0 -95
  519. package/src/utils/time-format.ts +0 -21
  520. package/src/utils/trace-writer.ts +0 -162
  521. package/src/utils/ui-constants.ts +0 -69
  522. package/src/utils/update-checker.ts +0 -110
  523. package/src/utils/usage-banner-state.ts +0 -146
  524. package/src/utils/validation-error-formatting.ts +0 -86
  525. package/src/utils/validation-error-helpers.ts +0 -19
  526. package/src/utils/windows-terminal-health.ts +0 -124
  527. package/src/utils/word-wrap-utils.ts +0 -53
  528. package/src/utils/write-file-atomic.ts +0 -54
  529. package/src/utils/yield-to-event-loop.ts +0 -9
@@ -1,33 +0,0 @@
1
- import {
2
- getFreebuffBase3RootAgentIdForModel,
3
- getFreebuffRootAgentIdForModel,
4
- } from '@anvil/common/constants/free-agents'
5
-
6
- import { getSelectedFreebuffModel } from '../state/freebuff-model-store'
7
- import {
8
- AGENT_MODE_TO_ID,
9
- CLI_HARNESS,
10
- IS_FREEBUFF,
11
- type AgentMode,
12
- } from './constants'
13
-
14
- /**
15
- * Freebuff is locked to LITE (chat-store's setAgentMode is a no-op when
16
- * IS_FREEBUFF), so this is effectively "which root does the selected model
17
- * run". Both harnesses have a root per picker model; CLI_HARNESS picks the
18
- * family. It is currently base3; keeping both branches live preserves the
19
- * release-based rollback path for the CLI.
20
- */
21
- export function getFreebuffCliAgentIdForModel(model: string): string {
22
- return CLI_HARNESS === 'base3'
23
- ? getFreebuffBase3RootAgentIdForModel(model)
24
- : getFreebuffRootAgentIdForModel(model)
25
- }
26
-
27
- export function getAgentIdForMode(agentMode: AgentMode): string {
28
- if (IS_FREEBUFF && agentMode === 'LITE') {
29
- return getFreebuffCliAgentIdForModel(getSelectedFreebuffModel())
30
- }
31
-
32
- return AGENT_MODE_TO_ID[agentMode]
33
- }
@@ -1,66 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
-
4
- import { getConfigDir } from './auth'
5
- import { logger } from './logger'
6
-
7
- interface FreebuffInstanceOwner {
8
- instanceId: string
9
- pid: number
10
- }
11
-
12
- const OWNER_FILE = 'freebuff-instance-owner.json'
13
-
14
- const getOwnerPath = (): string => path.join(getConfigDir(), OWNER_FILE)
15
-
16
- function readOwner(): FreebuffInstanceOwner | null {
17
- try {
18
- const raw = fs.readFileSync(getOwnerPath(), 'utf8')
19
- const parsed = JSON.parse(raw) as Partial<FreebuffInstanceOwner>
20
- if (
21
- typeof parsed.instanceId !== 'string' ||
22
- typeof parsed.pid !== 'number'
23
- ) {
24
- return null
25
- }
26
- return {
27
- instanceId: parsed.instanceId,
28
- pid: parsed.pid,
29
- }
30
- } catch {
31
- return null
32
- }
33
- }
34
-
35
- function isProcessRunning(pid: number): boolean {
36
- if (!Number.isInteger(pid) || pid <= 0) return false
37
- try {
38
- process.kill(pid, 0)
39
- return true
40
- } catch (error) {
41
- return (error as NodeJS.ErrnoException).code === 'EPERM'
42
- }
43
- }
44
-
45
- export function recordFreebuffInstanceOwner(instanceId: string): void {
46
- try {
47
- fs.mkdirSync(getConfigDir(), { recursive: true })
48
- fs.writeFileSync(
49
- getOwnerPath(),
50
- JSON.stringify({ instanceId, pid: process.pid }, null, 2),
51
- )
52
- } catch (error) {
53
- logger.debug(
54
- { error: error instanceof Error ? error.message : String(error) },
55
- '[freebuff-session] Failed to record local owner',
56
- )
57
- }
58
- }
59
-
60
- export function isFreebuffInstanceOwnedByDeadLocalProcess(
61
- instanceId: string,
62
- ): boolean {
63
- const owner = readOwner()
64
- if (!owner || owner.instanceId !== instanceId) return false
65
- return !isProcessRunning(owner.pid)
66
- }
@@ -1,50 +0,0 @@
1
- export type FreebuffModelNavigationDirection = 'forward' | 'backward'
2
-
3
- const FORWARD_KEY_NAMES = new Set(['right', 'down'])
4
- const BACKWARD_KEY_NAMES = new Set(['left', 'up'])
5
- const FORWARD_TAB_SEQUENCES = new Set(['\t', '\x1b[9u'])
6
- const BACKWARD_TAB_SEQUENCES = new Set([
7
- '\x1b[Z',
8
- '\x1b[9;2u',
9
- '\x1b[27;2;9~',
10
- ])
11
-
12
- export function nextFreebuffModelId(params: {
13
- modelIds: readonly string[]
14
- focusedId: string
15
- direction: FreebuffModelNavigationDirection
16
- }): string | null {
17
- const { modelIds, focusedId, direction } = params
18
- if (modelIds.length === 0) return null
19
-
20
- const currentIdx = modelIds.indexOf(focusedId)
21
- if (currentIdx === -1) return modelIds[0] ?? null
22
-
23
- const step = direction === 'forward' ? 1 : -1
24
- return modelIds[(currentIdx + step + modelIds.length) % modelIds.length]
25
- }
26
-
27
- export function freebuffModelNavigationDirectionForKey(key: {
28
- name?: string
29
- shift?: boolean
30
- sequence?: string
31
- raw?: string
32
- }): FreebuffModelNavigationDirection | null {
33
- const name = (key.name ?? '').toLowerCase()
34
- const sequence = key.sequence ?? key.raw ?? ''
35
-
36
- if (FORWARD_KEY_NAMES.has(name)) return 'forward'
37
- if (BACKWARD_KEY_NAMES.has(name)) return 'backward'
38
-
39
- if (
40
- (name === 'tab' && Boolean(key.shift)) ||
41
- BACKWARD_TAB_SEQUENCES.has(sequence)
42
- ) {
43
- return 'backward'
44
- }
45
- if (name === 'tab' || FORWARD_TAB_SEQUENCES.has(sequence)) {
46
- return 'forward'
47
- }
48
-
49
- return null
50
- }
@@ -1,55 +0,0 @@
1
- import { FREEBUFF_PREMIUM_SESSION_RESET_TIMEZONE } from '@anvil/common/constants/freebuff-models'
2
- import { getZonedDayBounds } from '@anvil/common/util/zoned-time'
3
-
4
- import type { FreebuffSessionRateLimitByModel } from '@anvil/common/types/freebuff-session'
5
-
6
- export function getFreebuffPremiumResetAt(params: {
7
- rateLimitsByModel?: FreebuffSessionRateLimitByModel
8
- nowMs: number
9
- }): Date {
10
- const { rateLimitsByModel, nowMs } = params
11
- const serverResetAt = rateLimitsByModel
12
- ? Object.values(rateLimitsByModel)[0]?.resetAt
13
- : undefined
14
- const parsedServerResetAt = serverResetAt ? new Date(serverResetAt) : null
15
-
16
- if (
17
- parsedServerResetAt &&
18
- Number.isFinite(parsedServerResetAt.getTime())
19
- ) {
20
- return parsedServerResetAt
21
- }
22
-
23
- return getZonedDayBounds(
24
- new Date(nowMs),
25
- FREEBUFF_PREMIUM_SESSION_RESET_TIMEZONE,
26
- ).resetsAt
27
- }
28
-
29
- /**
30
- * Human "resets in …" countdown. Daily pools stop at hours (`withDays` off);
31
- * a multi-day window (e.g. a lapsed reset) sets `withDays` so it reads as "2d 5h"
32
- * instead of a 100-hour figure.
33
- */
34
- export function formatFreebuffPremiumResetCountdown(
35
- resetAt: Date,
36
- nowMs: number,
37
- { withDays = false }: { withDays?: boolean } = {},
38
- ): string {
39
- const diffMs = resetAt.getTime() - nowMs
40
- if (!Number.isFinite(diffMs) || diffMs <= 0) return 'now'
41
-
42
- const totalMinutes = Math.max(1, Math.floor(diffMs / 60_000))
43
- if (withDays) {
44
- const days = Math.floor(totalMinutes / (60 * 24))
45
- if (days > 0) {
46
- const hours = Math.floor((totalMinutes % (60 * 24)) / 60)
47
- return hours === 0 ? `${days}d` : `${days}d ${hours}h`
48
- }
49
- }
50
- const hours = Math.floor(totalMinutes / 60)
51
- const minutes = totalMinutes % 60
52
-
53
- if (hours === 0) return `${minutes}m`
54
- return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}m`
55
- }
@@ -1,51 +0,0 @@
1
- import { getReferralInfo } from '@anvil/common/types/freebuff-session'
2
-
3
- import type { FreebuffAccessTier } from '@anvil/common/constants/freebuff-models'
4
- import type { FreebuffReferralInfo } from '@anvil/common/types/freebuff-session'
5
- import type { FreebuffSessionResponse } from '../types/freebuff-session'
6
-
7
- /**
8
- * Process-wide cache of the most recent referral block the server sent for
9
- * each access tier.
10
- *
11
- * The server only attaches `referral` to `none` (landing) responses — once the
12
- * user joins (queued/active) or ends a session (ended) it's dropped from the
13
- * payload. That breaks the return-to-landing flow: after a session ends the
14
- * slot DELETE leaves an `ended` row, so the landing GET sees `ended` (no
15
- * referral) until that row is swept, which would otherwise blank the GLM
16
- * referral banner for the whole visit. Caching the last-known block lets the
17
- * picker re-render it immediately; a later clean `none` GET refreshes it.
18
- */
19
- let referralByAccessTier: Partial<
20
- Record<FreebuffAccessTier, FreebuffReferralInfo>
21
- > = {}
22
-
23
- /** Remember the referral block whenever a response includes one, so it can be
24
- * carried across the join → end → return-to-landing round-trip. Active/ended
25
- * responses intentionally omit it and keep the prior value; an authoritative
26
- * `none` response without it clears stale metadata for that tier. */
27
- export function rememberReferral(session: FreebuffSessionResponse | null): void {
28
- const referral = getReferralInfo(session)
29
- const accessTier =
30
- session && 'accessTier' in session ? session.accessTier : undefined
31
- // Full- and limited-tier referral blocks have different meanings. Never
32
- // cache one without the tier needed to interpret it safely.
33
- if (!accessTier) return
34
- if (referral) {
35
- referralByAccessTier[accessTier] = referral
36
- } else if (session?.status === 'none') {
37
- delete referralByAccessTier[accessTier]
38
- }
39
- }
40
-
41
- /** The last referral block seen for this tier, if any. */
42
- export function getCachedReferral(
43
- accessTier: FreebuffAccessTier | undefined,
44
- ): FreebuffReferralInfo | undefined {
45
- return accessTier ? referralByAccessTier[accessTier] : undefined
46
- }
47
-
48
- /** Clear account-scoped referral metadata when its session owner unmounts. */
49
- export function clearReferralCache(): void {
50
- referralByAccessTier = {}
51
- }
@@ -1,243 +0,0 @@
1
- import { env } from '@anvil/common/env'
2
- import {
3
- FREEBUFF_COMPACT_SESSION_HEADER,
4
- FREEBUFF_INSTANCE_HEADER,
5
- FREEBUFF_MODEL_HEADER,
6
- } from '@anvil/common/constants/freebuff-models'
7
-
8
- import { useFreebuffSessionStore } from '../state/freebuff-session-store'
9
- import { getAuthTokenDetails } from './auth'
10
- import { IS_FREEBUFF } from './constants'
11
-
12
- import type { FreebuffSessionResponse } from '../types/freebuff-session'
13
- import type { FreebuffSessionServerResponse } from '@anvil/common/types/freebuff-session'
14
-
15
- const SESSION_FETCH_TIMEOUT_MS = 20_000
16
- export type FreebuffSessionMethod = 'POST' | 'GET' | 'DELETE'
17
-
18
- export class FreebuffSessionRequestError extends Error {
19
- constructor(
20
- message: string,
21
- readonly statusCode: number,
22
- readonly retryAfterMs?: number,
23
- readonly errorCode?: string,
24
- ) {
25
- super(message)
26
- this.name = 'FreebuffSessionRequestError'
27
- }
28
- }
29
-
30
- export function isFreebuffSessionTimeoutError(error: unknown): boolean {
31
- return (
32
- error instanceof Error &&
33
- (error.name === 'TimeoutError' || /timeout|timed out/i.test(error.message))
34
- )
35
- }
36
-
37
- export type FreebuffSessionFailureDisposition = 'retry' | 'stop' | 'unknown'
38
-
39
- /** How the poll loop should handle a failed request.
40
- *
41
- * A POST without a response may already have rotated the active instance, so
42
- * repeating it is unsafe without protocol-level idempotency. HTTP 408, 429,
43
- * and 503 responses are the exception: edge rejection or admission shedding
44
- * produces them before the session mutation can commit. GET is read-only and
45
- * can retry transient failures normally. */
46
- export function classifyFreebuffSessionRequestFailure(
47
- method: Extract<FreebuffSessionMethod, 'POST' | 'GET'>,
48
- error: unknown,
49
- ): FreebuffSessionFailureDisposition {
50
- if (method === 'POST') {
51
- if (!(error instanceof FreebuffSessionRequestError)) return 'unknown'
52
- // These responses are produced before the session mutation can commit:
53
- // 408/429 come from an edge or unparsed response (the endpoint's typed
54
- // rate-limit responses are returned above), and a 503 means no handler was
55
- // available or admission shed the request. Retrying them cannot repeat a
56
- // successful takeover.
57
- if ([408, 429, 503].includes(error.statusCode)) {
58
- return 'retry'
59
- }
60
- return error.statusCode >= 400 && error.statusCode < 500
61
- ? 'stop'
62
- : 'unknown'
63
- }
64
-
65
- if (!(error instanceof FreebuffSessionRequestError)) return 'retry'
66
- return error.statusCode === 408 ||
67
- error.statusCode === 429 ||
68
- error.statusCode >= 500
69
- ? 'retry'
70
- : 'stop'
71
- }
72
-
73
- export function parseRetryAfterMs(
74
- value: string | null,
75
- nowMs = Date.now(),
76
- ): number | undefined {
77
- if (!value) return undefined
78
- const seconds = Number(value)
79
- if (Number.isFinite(seconds) && seconds >= 0) {
80
- const milliseconds = seconds * 1_000
81
- return Number.isFinite(milliseconds) ? Math.ceil(milliseconds) : undefined
82
- }
83
- const dateMs = Date.parse(value)
84
- return Number.isFinite(dateMs) ? Math.max(0, dateMs - nowMs) : undefined
85
- }
86
-
87
- /** Combine the caller's abort signal with a per-request timeout. */
88
- export function sessionFetchSignal(
89
- signal: AbortSignal | undefined,
90
- timeoutMs: number = SESSION_FETCH_TIMEOUT_MS,
91
- ): AbortSignal {
92
- const timeout = AbortSignal.timeout(timeoutMs)
93
- return signal ? AbortSignal.any([signal, timeout]) : timeout
94
- }
95
-
96
- function sessionEndpoint(): string {
97
- const base = (
98
- env.NEXT_PUBLIC_ANVIL_APP_URL || 'https://codebuff.com'
99
- ).replace(/\/$/, '')
100
- return `${base}/api/v1/freebuff/session`
101
- }
102
-
103
- export async function callFreebuffSession(
104
- method: FreebuffSessionMethod,
105
- token: string,
106
- opts: {
107
- instanceId?: string
108
- model?: string
109
- signal?: AbortSignal
110
- compact?: boolean
111
- } = {},
112
- ): Promise<FreebuffSessionServerResponse> {
113
- const headers: Record<string, string> = { Authorization: `Bearer ${token}` }
114
- if (method === 'GET' && opts.instanceId) {
115
- headers[FREEBUFF_INSTANCE_HEADER] = opts.instanceId
116
- }
117
- if (method === 'GET' && opts.compact) {
118
- headers[FREEBUFF_COMPACT_SESSION_HEADER] = '1'
119
- }
120
- if (method === 'POST' && opts.model) {
121
- headers[FREEBUFF_MODEL_HEADER] = opts.model
122
- }
123
-
124
- const response = await fetch(sessionEndpoint(), {
125
- method,
126
- headers,
127
- signal: sessionFetchSignal(opts.signal),
128
- })
129
-
130
- if (response.status === 404) {
131
- return { status: 'none' }
132
- }
133
-
134
- if (response.status === 403) {
135
- const body = (await response
136
- .json()
137
- .catch(() => null)) as FreebuffSessionServerResponse | null
138
- if (
139
- body &&
140
- (body.status === 'country_blocked' || body.status === 'banned')
141
- ) {
142
- return body
143
- }
144
- }
145
-
146
- if (response.status === 409 && method === 'POST') {
147
- const body = (await response
148
- .json()
149
- .catch(() => null)) as FreebuffSessionServerResponse | null
150
- if (
151
- body &&
152
- (body.status === 'model_locked' || body.status === 'model_unavailable')
153
- ) {
154
- return body
155
- }
156
- }
157
-
158
- if (response.status === 429 && method === 'POST') {
159
- const body = (await response
160
- .json()
161
- .catch(() => null)) as FreebuffSessionServerResponse | null
162
- if (
163
- body &&
164
- (body.status === 'rate_limited' ||
165
- body.status === 'spend_limited' ||
166
- body.status === 'ip_capped')
167
- ) {
168
- return body
169
- }
170
- }
171
-
172
- if (!response.ok) {
173
- const text = await response.text().catch(() => '')
174
- let errorCode: string | undefined
175
- try {
176
- const body = JSON.parse(text) as { error?: unknown }
177
- if (typeof body.error === 'string') errorCode = body.error
178
- } catch {
179
- // Non-JSON errors have no machine-readable code.
180
- }
181
- throw new FreebuffSessionRequestError(
182
- `freebuff session ${method} failed: ${response.status} ${text.slice(0, 200)}`,
183
- response.status,
184
- parseRetryAfterMs(response.headers.get('retry-after')),
185
- errorCode,
186
- )
187
- }
188
-
189
- return (await response.json()) as FreebuffSessionServerResponse
190
- }
191
-
192
- /** A compact poll omits quota fields that were already returned by admission.
193
- * Keep that snapshot only for the same active session; null tells the poller
194
- * to fetch one full response before compacting again. */
195
- export function mergeCompactActiveSession(
196
- current: FreebuffSessionResponse | null,
197
- next: FreebuffSessionServerResponse,
198
- ): FreebuffSessionServerResponse | null {
199
- if (
200
- current?.status !== 'active' ||
201
- next.status !== 'active' ||
202
- current.instanceId !== next.instanceId ||
203
- current.model !== next.model
204
- ) {
205
- return null
206
- }
207
- return {
208
- ...next,
209
- rateLimit: next.rateLimit ?? current.rateLimit,
210
- rateLimitsByModel: next.rateLimitsByModel ?? current.rateLimitsByModel,
211
- }
212
- }
213
-
214
- export function holdsLiveFreebuffSlot(
215
- current: FreebuffSessionResponse | null,
216
- ): boolean {
217
- if (!current) return false
218
- return (
219
- current.status === 'active' ||
220
- (current.status === 'ended' && Boolean(current.instanceId))
221
- )
222
- }
223
-
224
- /** Best-effort DELETE of the caller's session row when it holds a live slot. */
225
- export async function releaseFreebuffSlot(): Promise<void> {
226
- const current = useFreebuffSessionStore.getState().session
227
- if (!holdsLiveFreebuffSlot(current)) return
228
-
229
- const { token } = getAuthTokenDetails()
230
- if (!token) return
231
-
232
- try {
233
- await callFreebuffSession('DELETE', token)
234
- } catch {
235
- // The server-side sweep is the backstop.
236
- }
237
- }
238
-
239
- /** Release the Freebuff slot on exit paths that skip React unmount. */
240
- export async function endFreebuffSessionBestEffort(): Promise<void> {
241
- if (!IS_FREEBUFF) return
242
- await releaseFreebuffSlot()
243
- }
@@ -1,21 +0,0 @@
1
- export const FREEBUFF_COUNTDOWN_VISIBLE_MS = 5 * 60_000
2
-
3
- export const formatFreebuffSessionCountdown = (ms: number): string => {
4
- if (ms <= 0) return 'expiring…'
5
- const totalSeconds = Math.ceil(ms / 1000)
6
- const m = Math.floor(totalSeconds / 60)
7
- const s = totalSeconds % 60
8
- return `${m}:${s.toString().padStart(2, '0')}`
9
- }
10
-
11
- export const formatFreebuffSessionRemaining = (ms: number): string => {
12
- if (ms <= 0) return 'expiring…'
13
- if (ms < FREEBUFF_COUNTDOWN_VISIBLE_MS) {
14
- return `${formatFreebuffSessionCountdown(ms)} left`
15
- }
16
- const totalMinutes = Math.ceil(ms / 60_000)
17
- if (totalMinutes < 60) return `${totalMinutes}m left`
18
- const hours = Math.floor(totalMinutes / 60)
19
- const minutes = totalMinutes % 60
20
- return minutes === 0 ? `${hours}h left` : `${hours}h ${minutes}m left`
21
- }
@@ -1,93 +0,0 @@
1
- // The label/dots/perk-note logic is shared with Freebuff Desktop and lives in
2
- // common; this module re-exports it and adds the terminal rendering and layout
3
- // gating only the CLI needs.
4
- export {
5
- FREEBUFF_STREAK_WEEK,
6
- getFreebuffStreakBonusNote,
7
- } from '@anvil/common/util/freebuff-streak-line'
8
- export type { FreebuffStreakLine } from '@anvil/common/util/freebuff-streak-line'
9
-
10
- import {
11
- FREEBUFF_STREAK_WEEK,
12
- getFreebuffStreakBonusNote,
13
- getFreebuffStreakLine as getSharedFreebuffStreakLine,
14
- } from '@anvil/common/util/freebuff-streak-line'
15
-
16
- import type { FreebuffStreakLine } from '@anvil/common/util/freebuff-streak-line'
17
-
18
- const FREEBUFF_STREAK_BONUS_MIN_HEIGHT = 30
19
-
20
- /** Columns between the count label and its progress dots. */
21
- export const FREEBUFF_STREAK_LABEL_GAP = 2
22
-
23
- /** Columns kept clear between the heading and the streak when they share a
24
- * row. The heading row is laid out space-between inside a shrink-to-fit
25
- * column, so when the row is the widest child there is no free space to
26
- * distribute and the two would otherwise render flush against each other
27
- * ("Start coding for free18 day streak"). This is the floor, and the same
28
- * number decides whether they may share a row at all. */
29
- export const FREEBUFF_STREAK_INLINE_GAP = 3
30
-
31
- /** Progress glyphs for a terminal — the same ●/○ pair the shared module and
32
- * the desktop app use. Bullet and middle dot were tried here because U+25CF
33
- * is missing from a few terminal fonts and lands as a tofu box, but • and ·
34
- * differ only in size: at a glance a partial week and a full one look alike,
35
- * which is the whole point of the row. Filled-vs-hollow reads instantly, and
36
- * the CLI already bets on ●/○ for its agent status indicators, so a font that
37
- * can't draw them is already visibly broken elsewhere.
38
- *
39
- * If a font ever fails these, █/░ (Block Elements) is the fallback pair: the
40
- * ASCII logo and the progress bar are built from them, so anything that
41
- * renders the CLI at all renders those. */
42
- const TERMINAL_DOT_CHARS = { filled: '●', empty: '○' }
43
-
44
- /** The streak line as the CLI draws it. */
45
- export function getFreebuffStreakLine(
46
- streak: number,
47
- ): FreebuffStreakLine | null {
48
- return getSharedFreebuffStreakLine(streak, TERMINAL_DOT_CHARS)
49
- }
50
-
51
- /** Rendered width of the streak, e.g. "18 day streak ●●●●●●●+". */
52
- export function getFreebuffStreakInlineWidth(line: FreebuffStreakLine): number {
53
- return line.label.length + FREEBUFF_STREAK_LABEL_GAP + line.dots.length
54
- }
55
-
56
- /** What a user with no streak yet is about to earn. The empty slot is measured
57
- * against it so the row doesn't move on day one. */
58
- const DAY_ONE_LINE = getFreebuffStreakLine(1)!
59
-
60
- /** Whether the heading and the streak can share a row with the inline gap left
61
- * clear between them. A streak long enough to widen its own label (or a
62
- * narrow terminal) pushes the streak onto its own line instead of letting the
63
- * two collide. */
64
- export function fitsFreebuffStreakOnHeadingRow(params: {
65
- /** null when the user has no streak yet — measured as day one. */
66
- line: FreebuffStreakLine | null
67
- headingWidth: number
68
- availableWidth: number
69
- }): boolean {
70
- return (
71
- params.headingWidth +
72
- FREEBUFF_STREAK_INLINE_GAP +
73
- getFreebuffStreakInlineWidth(params.line ?? DAY_ONE_LINE) <=
74
- params.availableWidth
75
- )
76
- }
77
-
78
- /** Returns the earned perk note only when the landing layout can show it
79
- * without crowding the picker or wrapping onto additional rows. */
80
- export function getFreebuffStreakBonusNoteForLayout(params: {
81
- streak: number
82
- accessTier: 'full' | 'limited'
83
- terminalHeight: number
84
- availableWidth: number
85
- }): string | null {
86
- if (params.streak < FREEBUFF_STREAK_WEEK) return null
87
- if (params.terminalHeight < FREEBUFF_STREAK_BONUS_MIN_HEIGHT) return null
88
-
89
- const note = getFreebuffStreakBonusNote(params)
90
- if (!note || note.length > params.availableWidth) return null
91
-
92
- return note
93
- }
package/src/utils/git.ts DELETED
@@ -1,17 +0,0 @@
1
- import { existsSync } from 'fs'
2
- import { dirname, join } from 'path'
3
-
4
- export function findGitRoot(params: { cwd: string }): string | null {
5
- const { cwd } = params
6
-
7
- let currentDir = cwd
8
-
9
- while (currentDir !== dirname(currentDir)) {
10
- if (existsSync(join(currentDir, '.git'))) {
11
- return currentDir
12
- }
13
- currentDir = dirname(currentDir)
14
- }
15
-
16
- return null
17
- }
@@ -1,47 +0,0 @@
1
- let timestampFormatter: Intl.DateTimeFormat | null = null
2
- export function initTimestampFormatter() {
3
- if (timestampFormatter) return
4
- try {
5
- timestampFormatter = new Intl.DateTimeFormat(undefined, {
6
- hour: '2-digit',
7
- minute: '2-digit',
8
- })
9
- } catch {
10
- timestampFormatter = null
11
- }
12
- }
13
-
14
- export function formatTimestamp(date = new Date()): string {
15
- if (timestampFormatter) {
16
- return timestampFormatter.format(date)
17
- }
18
- return date.toLocaleTimeString([], {
19
- hour: '2-digit',
20
- minute: '2-digit',
21
- })
22
- }
23
-
24
- export function formatQueuedPreview(
25
- messages: Array<{ content: string }>,
26
- maxChars: number = 60,
27
- ): string {
28
- if (messages.length === 0) return ''
29
-
30
- const latestMessage = messages[messages.length - 1].content
31
- const singleLine = latestMessage.replace(/\s+/g, ' ').trim()
32
- if (!singleLine) return ''
33
-
34
- const countSuffix = messages.length > 1 ? ` (+ ${messages.length - 1})` : ''
35
- const prefix = '↑ '
36
- const suffix = ' ↑'
37
- const availableChars =
38
- maxChars - prefix.length - suffix.length - countSuffix.length
39
-
40
- let messagePreview = singleLine
41
- if (singleLine.length > availableChars) {
42
- messagePreview =
43
- singleLine.slice(0, Math.max(0, availableChars - 3)) + '...'
44
- }
45
-
46
- return `${prefix}${messagePreview}${countSuffix}${suffix}`
47
- }