@alumbwe/anvil 1.0.20 → 1.0.21

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 (328) hide show
  1. package/package.json +6 -2
  2. package/src/agents/bundled-agents.generated.ts +4 -4
  3. package/src/chat.tsx +1703 -1698
  4. package/src/cli-args.ts +134 -134
  5. package/src/components/status-bar.tsx +331 -313
  6. package/src/hooks/helpers/send-message.ts +663 -654
  7. package/src/hooks/use-send-message.ts +806 -773
  8. package/src/index.tsx +473 -473
  9. package/src/state/chat-store.ts +553 -544
  10. package/src/utils/create-run-config.ts +121 -121
  11. package/src/utils/format-compact-number.ts +37 -0
  12. package/vendor/@anvil/common/package.json +27 -0
  13. package/vendor/@anvil/common/src/__tests__/agent-validation.test.ts +846 -0
  14. package/vendor/@anvil/common/src/__tests__/anvil-model-availability.test.ts +101 -0
  15. package/vendor/@anvil/common/src/__tests__/anvil-models.test.ts +1408 -0
  16. package/vendor/@anvil/common/src/__tests__/anvil-public-data-use-copy.test.ts +258 -0
  17. package/vendor/@anvil/common/src/__tests__/anvil-referral-tiers.test.ts +48 -0
  18. package/vendor/@anvil/common/src/__tests__/anvil-spend-ceilings.test.ts +282 -0
  19. package/vendor/@anvil/common/src/__tests__/anvil-trust.test.ts +526 -0
  20. package/vendor/@anvil/common/src/__tests__/deepseek-direct.test.ts +68 -0
  21. package/vendor/@anvil/common/src/__tests__/disposable-email.test.ts +132 -0
  22. package/vendor/@anvil/common/src/__tests__/dynamic-agent-template-schema.test.ts +422 -0
  23. package/vendor/@anvil/common/src/__tests__/env-ci.test.ts +167 -0
  24. package/vendor/@anvil/common/src/__tests__/env-process.test.ts +145 -0
  25. package/vendor/@anvil/common/src/__tests__/foreign-client-shipped-agents.test.ts +234 -0
  26. package/vendor/@anvil/common/src/__tests__/foreign-client-signals.test.ts +379 -0
  27. package/vendor/@anvil/common/src/__tests__/free-agents.test.ts +807 -0
  28. package/vendor/@anvil/common/src/__tests__/gravity-capi.test.ts +154 -0
  29. package/vendor/@anvil/common/src/__tests__/handlesteps-parsing.test.ts +246 -0
  30. package/vendor/@anvil/common/src/__tests__/kimi-k3-god-only.test.ts +77 -0
  31. package/vendor/@anvil/common/src/__tests__/model-config.test.ts +89 -0
  32. package/vendor/@anvil/common/src/__tests__/project-file-tree.test.ts +298 -0
  33. package/vendor/@anvil/common/src/__tests__/provisioned-model-tiers.test.ts +116 -0
  34. package/vendor/@anvil/common/src/__tests__/reasoning-effort.test.ts +167 -0
  35. package/vendor/@anvil/common/src/__tests__/reddit-capi.test.ts +132 -0
  36. package/vendor/@anvil/common/src/__tests__/response-ad-positions.test.ts +72 -0
  37. package/vendor/@anvil/common/src/__tests__/user-state.test.ts +30 -0
  38. package/vendor/@anvil/common/src/actions.ts +215 -0
  39. package/vendor/@anvil/common/src/analytics-core.ts +69 -0
  40. package/vendor/@anvil/common/src/analytics.ts +93 -0
  41. package/vendor/@anvil/common/src/api-keys/constants.ts +26 -0
  42. package/vendor/@anvil/common/src/browser-actions.ts +413 -0
  43. package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding-gate.test.ts +63 -0
  44. package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding.test.ts +246 -0
  45. package/vendor/@anvil/common/src/constants/__tests__/cf-worker-signals.test.ts +106 -0
  46. package/vendor/@anvil/common/src/constants/agents.ts +99 -0
  47. package/vendor/@anvil/common/src/constants/analytics-events.ts +435 -0
  48. package/vendor/@anvil/common/src/constants/anthropic.ts +73 -0
  49. package/vendor/@anvil/common/src/constants/anvil-data-use.ts +81 -0
  50. package/vendor/@anvil/common/src/constants/anvil-errors.ts +7 -0
  51. package/vendor/@anvil/common/src/constants/anvil-gemini-thinker.ts +21 -0
  52. package/vendor/@anvil/common/src/constants/anvil-model-ids.ts +11 -0
  53. package/vendor/@anvil/common/src/constants/anvil-models.ts +2130 -0
  54. package/vendor/@anvil/common/src/constants/anvil-onboarding-gate.ts +55 -0
  55. package/vendor/@anvil/common/src/constants/anvil-onboarding.ts +307 -0
  56. package/vendor/@anvil/common/src/constants/anvil-referral-tiers.ts +87 -0
  57. package/vendor/@anvil/common/src/constants/anvil-signup-block.ts +68 -0
  58. package/vendor/@anvil/common/src/constants/anvil-spend-ceilings.ts +450 -0
  59. package/vendor/@anvil/common/src/constants/anvil-trust.ts +976 -0
  60. package/vendor/@anvil/common/src/constants/auth.ts +18 -0
  61. package/vendor/@anvil/common/src/constants/byok.ts +2 -0
  62. package/vendor/@anvil/common/src/constants/cf-worker-signals.ts +132 -0
  63. package/vendor/@anvil/common/src/constants/composio.ts +34 -0
  64. package/vendor/@anvil/common/src/constants/deepseek-direct.ts +55 -0
  65. package/vendor/@anvil/common/src/constants/feedback.ts +13 -0
  66. package/vendor/@anvil/common/src/constants/foreign-client-signals.ts +272 -0
  67. package/vendor/@anvil/common/src/constants/free-agents.ts +777 -0
  68. package/vendor/@anvil/common/src/constants/gemini.ts +15 -0
  69. package/vendor/@anvil/common/src/constants/grant-priorities.ts +13 -0
  70. package/vendor/@anvil/common/src/constants/hosts.ts +6 -0
  71. package/vendor/@anvil/common/src/constants/images.ts +51 -0
  72. package/vendor/@anvil/common/src/constants/index.ts +7 -0
  73. package/vendor/@anvil/common/src/constants/knowledge.ts +35 -0
  74. package/vendor/@anvil/common/src/constants/limits.ts +23 -0
  75. package/vendor/@anvil/common/src/constants/model-config.ts +277 -0
  76. package/vendor/@anvil/common/src/constants/openrouter-attribution.ts +8 -0
  77. package/vendor/@anvil/common/src/constants/paths.ts +69 -0
  78. package/vendor/@anvil/common/src/constants/provider-routes.ts +317 -0
  79. package/vendor/@anvil/common/src/constants/reasoning-effort.ts +79 -0
  80. package/vendor/@anvil/common/src/constants/skills.ts +60 -0
  81. package/vendor/@anvil/common/src/constants/subscription-plans.ts +49 -0
  82. package/vendor/@anvil/common/src/constants/ui.ts +25 -0
  83. package/vendor/@anvil/common/src/env-ci.ts +36 -0
  84. package/vendor/@anvil/common/src/env-process.ts +95 -0
  85. package/vendor/@anvil/common/src/env-schema.ts +95 -0
  86. package/vendor/@anvil/common/src/env.ts +24 -0
  87. package/vendor/@anvil/common/src/gravity-capi.ts +207 -0
  88. package/vendor/@anvil/common/src/mcp/client.ts +233 -0
  89. package/vendor/@anvil/common/src/old-constants.ts +10 -0
  90. package/vendor/@anvil/common/src/project-file-tree.ts +355 -0
  91. package/vendor/@anvil/common/src/reddit-capi.ts +254 -0
  92. package/vendor/@anvil/common/src/schemas/feedback.ts +52 -0
  93. package/vendor/@anvil/common/src/schemas/logs.ts +66 -0
  94. package/vendor/@anvil/common/src/templates/agent-validation.ts +392 -0
  95. package/vendor/@anvil/common/src/templates/initial-agents-dir/LICENSE +202 -0
  96. package/vendor/@anvil/common/src/templates/initial-agents-dir/README.md +294 -0
  97. package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/01-basic-diff-reviewer.ts +17 -0
  98. package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/02-intermediate-git-committer.ts +78 -0
  99. package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/03-advanced-file-explorer.ts +73 -0
  100. package/vendor/@anvil/common/src/templates/initial-agents-dir/my-custom-agent.ts +40 -0
  101. package/vendor/@anvil/common/src/templates/initial-agents-dir/package.json +6 -0
  102. package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/README.md +65 -0
  103. package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/example-skill/SKILL.md +29 -0
  104. package/vendor/@anvil/common/src/templates/initial-agents-dir/types/agent-definition.ts +497 -0
  105. package/vendor/@anvil/common/src/templates/initial-agents-dir/types/tools.ts +444 -0
  106. package/vendor/@anvil/common/src/templates/initial-agents-dir/types/util-types.ts +178 -0
  107. package/vendor/@anvil/common/src/testing/TESTING_PATTERNS.md +351 -0
  108. package/vendor/@anvil/common/src/testing/anvil-offer-invariants.ts +169 -0
  109. package/vendor/@anvil/common/src/testing/errors.ts +33 -0
  110. package/vendor/@anvil/common/src/testing/fixtures/agent-runtime.ts +334 -0
  111. package/vendor/@anvil/common/src/testing/impl/agent-runtime.ts +6 -0
  112. package/vendor/@anvil/common/src/testing/index.ts +84 -0
  113. package/vendor/@anvil/common/src/testing/mock-modules.ts +53 -0
  114. package/vendor/@anvil/common/src/testing/mock-types.ts +123 -0
  115. package/vendor/@anvil/common/src/testing/mocks/analytics.ts +261 -0
  116. package/vendor/@anvil/common/src/testing/mocks/child-process.ts +93 -0
  117. package/vendor/@anvil/common/src/testing/mocks/crypto.ts +218 -0
  118. package/vendor/@anvil/common/src/testing/mocks/database.ts +337 -0
  119. package/vendor/@anvil/common/src/testing/mocks/fetch.ts +219 -0
  120. package/vendor/@anvil/common/src/testing/mocks/filesystem.ts +166 -0
  121. package/vendor/@anvil/common/src/testing/mocks/index.ts +101 -0
  122. package/vendor/@anvil/common/src/testing/mocks/logger.ts +135 -0
  123. package/vendor/@anvil/common/src/testing/mocks/stream.ts +313 -0
  124. package/vendor/@anvil/common/src/testing/mocks/timers.ts +132 -0
  125. package/vendor/@anvil/common/src/testing/mocks/tree-sitter.ts +127 -0
  126. package/vendor/@anvil/common/src/testing/setup.ts +282 -0
  127. package/vendor/@anvil/common/src/testing-env-ci.ts +15 -0
  128. package/vendor/@anvil/common/src/testing-env-process.ts +78 -0
  129. package/vendor/@anvil/common/src/tools/__tests__/compile-tool-definitions.test.ts +34 -0
  130. package/vendor/@anvil/common/src/tools/compile-tool-definitions.ts +157 -0
  131. package/vendor/@anvil/common/src/tools/constants.ts +117 -0
  132. package/vendor/@anvil/common/src/tools/list.ts +190 -0
  133. package/vendor/@anvil/common/src/tools/params/__tests__/coerce-to-array.test.ts +213 -0
  134. package/vendor/@anvil/common/src/tools/params/__tests__/read-docs.test.ts +47 -0
  135. package/vendor/@anvil/common/src/tools/params/__tests__/render-ui.test.ts +65 -0
  136. package/vendor/@anvil/common/src/tools/params/tool/__tests__/run-terminal-command-timeout.test.ts +49 -0
  137. package/vendor/@anvil/common/src/tools/params/tool/add-message.ts +39 -0
  138. package/vendor/@anvil/common/src/tools/params/tool/add-subgoal.ts +57 -0
  139. package/vendor/@anvil/common/src/tools/params/tool/apply-patch.ts +110 -0
  140. package/vendor/@anvil/common/src/tools/params/tool/ask-user.ts +181 -0
  141. package/vendor/@anvil/common/src/tools/params/tool/browser-logs.ts +85 -0
  142. package/vendor/@anvil/common/src/tools/params/tool/cloud-plan-ready.ts +94 -0
  143. package/vendor/@anvil/common/src/tools/params/tool/code-search.ts +159 -0
  144. package/vendor/@anvil/common/src/tools/params/tool/composio.ts +131 -0
  145. package/vendor/@anvil/common/src/tools/params/tool/create-plan.ts +80 -0
  146. package/vendor/@anvil/common/src/tools/params/tool/end-turn.ts +57 -0
  147. package/vendor/@anvil/common/src/tools/params/tool/find-files.ts +60 -0
  148. package/vendor/@anvil/common/src/tools/params/tool/glob.ts +80 -0
  149. package/vendor/@anvil/common/src/tools/params/tool/gravity-index.ts +93 -0
  150. package/vendor/@anvil/common/src/tools/params/tool/list-directory.ts +58 -0
  151. package/vendor/@anvil/common/src/tools/params/tool/lookup-agent-info.ts +37 -0
  152. package/vendor/@anvil/common/src/tools/params/tool/propose-str-replace.ts +103 -0
  153. package/vendor/@anvil/common/src/tools/params/tool/propose-write-file.ts +71 -0
  154. package/vendor/@anvil/common/src/tools/params/tool/read-docs.ts +90 -0
  155. package/vendor/@anvil/common/src/tools/params/tool/read-files.ts +109 -0
  156. package/vendor/@anvil/common/src/tools/params/tool/read-subtree.ts +79 -0
  157. package/vendor/@anvil/common/src/tools/params/tool/read-url.ts +81 -0
  158. package/vendor/@anvil/common/src/tools/params/tool/render-ui.ts +168 -0
  159. package/vendor/@anvil/common/src/tools/params/tool/run-file-change-hooks.ts +57 -0
  160. package/vendor/@anvil/common/src/tools/params/tool/run-terminal-command.ts +211 -0
  161. package/vendor/@anvil/common/src/tools/params/tool/screenshot.ts +97 -0
  162. package/vendor/@anvil/common/src/tools/params/tool/set-messages.ts +44 -0
  163. package/vendor/@anvil/common/src/tools/params/tool/set-output.ts +61 -0
  164. package/vendor/@anvil/common/src/tools/params/tool/skill.ts +59 -0
  165. package/vendor/@anvil/common/src/tools/params/tool/spawn-agent-inline.ts +56 -0
  166. package/vendor/@anvil/common/src/tools/params/tool/spawn-agents.ts +154 -0
  167. package/vendor/@anvil/common/src/tools/params/tool/str-replace.ts +107 -0
  168. package/vendor/@anvil/common/src/tools/params/tool/suggest-followups.ts +97 -0
  169. package/vendor/@anvil/common/src/tools/params/tool/task-completed.ts +61 -0
  170. package/vendor/@anvil/common/src/tools/params/tool/think-deeply.ts +56 -0
  171. package/vendor/@anvil/common/src/tools/params/tool/update-subgoal.ts +89 -0
  172. package/vendor/@anvil/common/src/tools/params/tool/vision-analyze.ts +82 -0
  173. package/vendor/@anvil/common/src/tools/params/tool/web-search.ts +73 -0
  174. package/vendor/@anvil/common/src/tools/params/tool/write-file.ts +71 -0
  175. package/vendor/@anvil/common/src/tools/params/tool/write-todos.ts +67 -0
  176. package/vendor/@anvil/common/src/tools/params/utils.ts +150 -0
  177. package/vendor/@anvil/common/src/tools/utils.ts +24 -0
  178. package/vendor/@anvil/common/src/types/__tests__/dynamic-agent-template.test.ts +20 -0
  179. package/vendor/@anvil/common/src/types/agent-template.ts +215 -0
  180. package/vendor/@anvil/common/src/types/anvil-session.ts +535 -0
  181. package/vendor/@anvil/common/src/types/anvil-streak.ts +6 -0
  182. package/vendor/@anvil/common/src/types/anvil-usage.ts +64 -0
  183. package/vendor/@anvil/common/src/types/api/agents/publish.ts +61 -0
  184. package/vendor/@anvil/common/src/types/bun-test.d.ts +5 -0
  185. package/vendor/@anvil/common/src/types/contracts/agent-runtime.ts +75 -0
  186. package/vendor/@anvil/common/src/types/contracts/analytics.ts +9 -0
  187. package/vendor/@anvil/common/src/types/contracts/bigquery.ts +55 -0
  188. package/vendor/@anvil/common/src/types/contracts/billing.ts +46 -0
  189. package/vendor/@anvil/common/src/types/contracts/client.ts +53 -0
  190. package/vendor/@anvil/common/src/types/contracts/database.ts +112 -0
  191. package/vendor/@anvil/common/src/types/contracts/env.ts +203 -0
  192. package/vendor/@anvil/common/src/types/contracts/llm.ts +191 -0
  193. package/vendor/@anvil/common/src/types/contracts/logger.ts +14 -0
  194. package/vendor/@anvil/common/src/types/contracts/logs.ts +34 -0
  195. package/vendor/@anvil/common/src/types/contracts/trace.ts +21 -0
  196. package/vendor/@anvil/common/src/types/dynamic-agent-template.ts +328 -0
  197. package/vendor/@anvil/common/src/types/filesystem.ts +10 -0
  198. package/vendor/@anvil/common/src/types/function-params.ts +33 -0
  199. package/vendor/@anvil/common/src/types/grant.ts +20 -0
  200. package/vendor/@anvil/common/src/types/gravity-index.ts +170 -0
  201. package/vendor/@anvil/common/src/types/json.ts +29 -0
  202. package/vendor/@anvil/common/src/types/mcp.ts +24 -0
  203. package/vendor/@anvil/common/src/types/messages/anvil-message.ts +58 -0
  204. package/vendor/@anvil/common/src/types/messages/content-part.ts +59 -0
  205. package/vendor/@anvil/common/src/types/messages/data-content.ts +14 -0
  206. package/vendor/@anvil/common/src/types/messages/provider-metadata.ts +13 -0
  207. package/vendor/@anvil/common/src/types/organization.ts +118 -0
  208. package/vendor/@anvil/common/src/types/print-mode.ts +121 -0
  209. package/vendor/@anvil/common/src/types/publisher.ts +67 -0
  210. package/vendor/@anvil/common/src/types/session-state.ts +149 -0
  211. package/vendor/@anvil/common/src/types/skill.ts +86 -0
  212. package/vendor/@anvil/common/src/types/source.ts +11 -0
  213. package/vendor/@anvil/common/src/types/spawn.ts +13 -0
  214. package/vendor/@anvil/common/src/types/subscription.ts +67 -0
  215. package/vendor/@anvil/common/src/types/usage.ts +16 -0
  216. package/vendor/@anvil/common/src/types/util.ts +3 -0
  217. package/vendor/@anvil/common/src/util/__tests__/ad-user-agent.test.ts +26 -0
  218. package/vendor/@anvil/common/src/util/__tests__/analytics-dispatcher.test.ts +122 -0
  219. package/vendor/@anvil/common/src/util/__tests__/analytics-log.test.ts +102 -0
  220. package/vendor/@anvil/common/src/util/__tests__/analytics-sampling.test.ts +143 -0
  221. package/vendor/@anvil/common/src/util/__tests__/anvil-streak.test.ts +202 -0
  222. package/vendor/@anvil/common/src/util/__tests__/anvil-usage-summary.test.ts +193 -0
  223. package/vendor/@anvil/common/src/util/__tests__/axiom-only-log.test.ts +140 -0
  224. package/vendor/@anvil/common/src/util/__tests__/client-user-agent.test.ts +148 -0
  225. package/vendor/@anvil/common/src/util/__tests__/engagement-tracker.test.ts +115 -0
  226. package/vendor/@anvil/common/src/util/__tests__/env-file-path.test.ts +57 -0
  227. package/vendor/@anvil/common/src/util/__tests__/error-abort.test.ts +774 -0
  228. package/vendor/@anvil/common/src/util/__tests__/error-api-details.test.ts +206 -0
  229. package/vendor/@anvil/common/src/util/__tests__/file-read-limits.test.ts +173 -0
  230. package/vendor/@anvil/common/src/util/__tests__/format-code-search.test.ts +60 -0
  231. package/vendor/@anvil/common/src/util/__tests__/log-mirror.test.ts +31 -0
  232. package/vendor/@anvil/common/src/util/__tests__/messages.test.ts +1252 -0
  233. package/vendor/@anvil/common/src/util/__tests__/partial-json-delta.test.ts +505 -0
  234. package/vendor/@anvil/common/src/util/__tests__/path.test.ts +22 -0
  235. package/vendor/@anvil/common/src/util/__tests__/project-ignore.test.ts +90 -0
  236. package/vendor/@anvil/common/src/util/__tests__/promise.test.ts +325 -0
  237. package/vendor/@anvil/common/src/util/__tests__/rate-limit.test.ts +28 -0
  238. package/vendor/@anvil/common/src/util/__tests__/reddit-anvil-retention.test.ts +130 -0
  239. package/vendor/@anvil/common/src/util/__tests__/saxy.test.ts +1008 -0
  240. package/vendor/@anvil/common/src/util/__tests__/split-data.test.ts +289 -0
  241. package/vendor/@anvil/common/src/util/__tests__/string.test.ts +239 -0
  242. package/vendor/@anvil/common/src/util/__tests__/thread-title.test.ts +70 -0
  243. package/vendor/@anvil/common/src/util/__tests__/tool-result-media-order.test.ts +108 -0
  244. package/vendor/@anvil/common/src/util/__tests__/ttft-histogram.test.ts +180 -0
  245. package/vendor/@anvil/common/src/util/__tests__/with-timeout.test.ts +24 -0
  246. package/vendor/@anvil/common/src/util/__tests__/zoned-time.test.ts +88 -0
  247. package/vendor/@anvil/common/src/util/ad-user-agent.ts +25 -0
  248. package/vendor/@anvil/common/src/util/agent-file-utils.ts +110 -0
  249. package/vendor/@anvil/common/src/util/agent-id-parsing.ts +136 -0
  250. package/vendor/@anvil/common/src/util/agent-name-normalization.ts +38 -0
  251. package/vendor/@anvil/common/src/util/agent-name-resolver.ts +86 -0
  252. package/vendor/@anvil/common/src/util/analytics-dispatcher.ts +82 -0
  253. package/vendor/@anvil/common/src/util/analytics-log.ts +78 -0
  254. package/vendor/@anvil/common/src/util/analytics-sampling.ts +255 -0
  255. package/vendor/@anvil/common/src/util/anvil-model-availability.ts +102 -0
  256. package/vendor/@anvil/common/src/util/anvil-privacy.ts +82 -0
  257. package/vendor/@anvil/common/src/util/anvil-streak-line.ts +103 -0
  258. package/vendor/@anvil/common/src/util/anvil-streak.ts +156 -0
  259. package/vendor/@anvil/common/src/util/anvil-usage-summary.ts +125 -0
  260. package/vendor/@anvil/common/src/util/array.ts +31 -0
  261. package/vendor/@anvil/common/src/util/axiom-only-log.ts +124 -0
  262. package/vendor/@anvil/common/src/util/cache-debug.ts +171 -0
  263. package/vendor/@anvil/common/src/util/client-user-agent.ts +114 -0
  264. package/vendor/@anvil/common/src/util/credentials.ts +26 -0
  265. package/vendor/@anvil/common/src/util/currency.ts +25 -0
  266. package/vendor/@anvil/common/src/util/dates.ts +81 -0
  267. package/vendor/@anvil/common/src/util/disposable-email.ts +277 -0
  268. package/vendor/@anvil/common/src/util/engagement-tracker.ts +129 -0
  269. package/vendor/@anvil/common/src/util/env-file-path.ts +40 -0
  270. package/vendor/@anvil/common/src/util/error.ts +562 -0
  271. package/vendor/@anvil/common/src/util/file-read-limits.ts +236 -0
  272. package/vendor/@anvil/common/src/util/file.ts +339 -0
  273. package/vendor/@anvil/common/src/util/format-code-search.ts +115 -0
  274. package/vendor/@anvil/common/src/util/lazy-response-ads.ts +92 -0
  275. package/vendor/@anvil/common/src/util/log-data.ts +57 -0
  276. package/vendor/@anvil/common/src/util/log-ingest.ts +58 -0
  277. package/vendor/@anvil/common/src/util/log-mirror.ts +34 -0
  278. package/vendor/@anvil/common/src/util/lru-cache.ts +67 -0
  279. package/vendor/@anvil/common/src/util/messages.ts +685 -0
  280. package/vendor/@anvil/common/src/util/min-heap.ts +87 -0
  281. package/vendor/@anvil/common/src/util/model-utils.ts +4 -0
  282. package/vendor/@anvil/common/src/util/object.ts +128 -0
  283. package/vendor/@anvil/common/src/util/partial-json-delta.ts +89 -0
  284. package/vendor/@anvil/common/src/util/path.ts +15 -0
  285. package/vendor/@anvil/common/src/util/project-ignore.ts +119 -0
  286. package/vendor/@anvil/common/src/util/promise.ts +73 -0
  287. package/vendor/@anvil/common/src/util/random.ts +15 -0
  288. package/vendor/@anvil/common/src/util/rate-limit.ts +56 -0
  289. package/vendor/@anvil/common/src/util/reddit-anvil-retention.ts +60 -0
  290. package/vendor/@anvil/common/src/util/reddit-capi-events.ts +36 -0
  291. package/vendor/@anvil/common/src/util/response-ad-positions.ts +54 -0
  292. package/vendor/@anvil/common/src/util/saxy.ts +741 -0
  293. package/vendor/@anvil/common/src/util/skills.test.ts +44 -0
  294. package/vendor/@anvil/common/src/util/skills.ts +36 -0
  295. package/vendor/@anvil/common/src/util/split-data.ts +259 -0
  296. package/vendor/@anvil/common/src/util/stop-sequence.ts +61 -0
  297. package/vendor/@anvil/common/src/util/string.ts +426 -0
  298. package/vendor/@anvil/common/src/util/system-info.ts +53 -0
  299. package/vendor/@anvil/common/src/util/thread-title.ts +46 -0
  300. package/vendor/@anvil/common/src/util/ttft-histogram.ts +73 -0
  301. package/vendor/@anvil/common/src/util/xml-parser.ts +27 -0
  302. package/vendor/@anvil/common/src/util/xml.ts +17 -0
  303. package/vendor/@anvil/common/src/util/zod-schema.ts +25 -0
  304. package/vendor/@anvil/common/src/util/zoned-time.ts +136 -0
  305. package/vendor/@anvil/common/src/utils/ask-user-bridge.ts +44 -0
  306. package/vendor/@anvil/sdk/dist/index.cjs +52297 -0
  307. package/vendor/@anvil/sdk/dist/index.cjs.map +440 -0
  308. package/vendor/@anvil/sdk/dist/index.d.ts +4277 -0
  309. package/vendor/@anvil/sdk/dist/index.mjs +52290 -0
  310. package/vendor/@anvil/sdk/dist/index.mjs.map +440 -0
  311. package/vendor/@anvil/sdk/dist/vendor/ai.cjs +30886 -0
  312. package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-darwin/rg +0 -0
  313. package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-linux/rg +0 -0
  314. package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-darwin/rg +0 -0
  315. package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-linux/rg +0 -0
  316. package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
  317. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-c-sharp.wasm +0 -0
  318. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-cpp.wasm +0 -0
  319. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-go.wasm +0 -0
  320. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-java.wasm +0 -0
  321. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-javascript.wasm +0 -0
  322. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-python.wasm +0 -0
  323. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-ruby.wasm +0 -0
  324. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-rust.wasm +0 -0
  325. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-tsx.wasm +0 -0
  326. package/vendor/@anvil/sdk/dist/wasm/tree-sitter-typescript.wasm +0 -0
  327. package/vendor/@anvil/sdk/dist/wasm/tree-sitter.wasm +0 -0
  328. package/vendor/@anvil/sdk/package.json +21 -0
@@ -0,0 +1,317 @@
1
+ export const PROVIDER_ROUTE_IDS = [
2
+ 'fireworks/deployment',
3
+ 'fireworks/serverless',
4
+ 'minimax/official',
5
+ 'xiaomi/official',
6
+ 'openrouter/novita/fp8',
7
+ 'mimo/openrouter',
8
+ 'infron/makora',
9
+ 'deepseek/openrouter',
10
+ 'deepseek/crof',
11
+ 'deepseek/official',
12
+ ] as const
13
+
14
+ export type ProviderRouteId = (typeof PROVIDER_ROUTE_IDS)[number]
15
+
16
+ export const FIREWORKS_DEPLOYMENT_PROVIDER_ROUTE =
17
+ 'fireworks/deployment' satisfies ProviderRouteId
18
+ export const FIREWORKS_SERVERLESS_PROVIDER_ROUTE =
19
+ 'fireworks/serverless' satisfies ProviderRouteId
20
+ export const MINIMAX_OFFICIAL_PROVIDER_ROUTE =
21
+ 'minimax/official' satisfies ProviderRouteId
22
+ /**
23
+ * Marks a MiMo session as diverted off Xiaomi's direct API to the OpenRouter
24
+ * lane. Like {@link DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE} it says *that* the
25
+ * session is on the fallback, NOT which upstream serves it — that is
26
+ * {@link MIMO_OPENROUTER_UPSTREAM} below, so repointing it also moves every
27
+ * session already pinned here, with no migration.
28
+ *
29
+ * Named generically on purpose. Its predecessor
30
+ * {@link MIMO_NOVITA_PROVIDER_ROUTE} baked the upstream into a value that gets
31
+ * persisted in `free_session.provider_route` and read back unvalidated, so
32
+ * changing upstreams meant either a migration or a name that lies.
33
+ */
34
+ export const MIMO_OPENROUTER_PROVIDER_ROUTE =
35
+ 'mimo/openrouter' satisfies ProviderRouteId
36
+ /**
37
+ * The upstreams that serve {@link MIMO_OPENROUTER_PROVIDER_ROUTE}, preferred
38
+ * first: Xiaomi's OWN endpoint, reached through OpenRouter's account rather
39
+ * than our direct API key, with Novita behind it purely as depth.
40
+ *
41
+ * It lives next to the route id because the two are meant to be read together —
42
+ * the id says which lane a session is pinned to, this says who serves it — and
43
+ * in `common/` rather than in mimo-router.ts so `scripts/mimo-smoke.ts` can
44
+ * assert against the REAL value without importing the billing chain. A smoke
45
+ * test that restates this config would keep passing after the upstream moved,
46
+ * reporting a lane it no longer covers.
47
+ *
48
+ * Novita served the lane until 2026-08-01, which was most of what made the
49
+ * fallback expensive. Measured over 6h of prod that day, attributing rows by
50
+ * whether their cost reproduces our Xiaomi formula:
51
+ *
52
+ * openrouter/novita 18,268 reqs (42.6%) 19.2% cache $364.11 $0.138/M in
53
+ * xiaomi direct 24,631 reqs (57.4%) 90.5% cache $63.76 $0.018/M in
54
+ *
55
+ * Novita is also 20% dearer per token before caching ($0.168/$0.336 against
56
+ * Xiaomi's $0.14/$0.28) and prices cache reads at $0.0034/M against $0.0028/M.
57
+ * Xiaomi's OpenRouter endpoint is priced identically to our direct rate, so the
58
+ * lane costs the same as the primary and differs only in whose rate limit and
59
+ * prompt cache it draws on — which is the entire point of having it.
60
+ */
61
+ export const MIMO_OPENROUTER_UPSTREAM_ORDER = [
62
+ 'xiaomi/fp8',
63
+ 'novita/fp8',
64
+ ] as const
65
+
66
+ /**
67
+ * Fresh OpenRouter `provider` block for the MiMo lane.
68
+ *
69
+ * TWO ENTRIES DELIBERATELY, and it must never go back to one. A pinned session
70
+ * has no health check and no un-pin path — `routeWithStickyFallback` short
71
+ * -circuits straight to the fallback — so if the lane's only upstream is down,
72
+ * one transient Xiaomi blip wedges every remaining request in that session
73
+ * rather than degrading a single one. That is not hypothetical: a one-deep pin
74
+ * on DeepSeek's Infron lane took out 1,160 requests across 191 users for ~32h
75
+ * when `makora` went offline (2026-07-26/27, fixed in #1045).
76
+ *
77
+ * Verified live on this lane 2026-08-01: within an `allow_fallbacks:false`
78
+ * order list, an unroutable first entry is SKIPPED rather than failing the
79
+ * request — `order:['nosuchprovider','xiaomi/fp8']` returned 200 from Xiaomi —
80
+ * while `order:['xiaomi/fp8','novita/fp8']` still serves from Xiaomi when it is
81
+ * healthy. So the depth costs nothing in the normal case and is the difference
82
+ * between a degraded session and a wedged one in the bad case. Novita is second
83
+ * because it is the best-understood host for this model: it served ~43% of MiMo
84
+ * traffic through late July, so its compatibility with our request shape is
85
+ * proven, and it only ever serves when Xiaomi cannot.
86
+ *
87
+ * Returns a NEW object with a NEW array every call. These arrays get aliased
88
+ * into an outgoing request body, and this file's peer
89
+ * `INFRON_PROVIDER_ORDER` was made copy-on-assignment in #1045 for exactly that
90
+ * reason — one downstream mutation would corrupt routing process-wide.
91
+ */
92
+ export function mimoOpenRouterProvider(): Record<string, unknown> {
93
+ return {
94
+ order: [...MIMO_OPENROUTER_UPSTREAM_ORDER],
95
+ allow_fallbacks: false,
96
+ }
97
+ }
98
+ /**
99
+ * LEGACY MiMo fallback pin, written while the OpenRouter lane was hardcoded to
100
+ * Novita FP8. Still recognized on READ so sessions pinned before
101
+ * {@link MIMO_OPENROUTER_PROVIDER_ROUTE} shipped keep serving from the fallback
102
+ * instead of silently reverting to a Xiaomi-direct attempt they already failed.
103
+ * Never written anymore; expires with its session.
104
+ */
105
+ export const MIMO_NOVITA_PROVIDER_ROUTE =
106
+ 'openrouter/novita/fp8' satisfies ProviderRouteId
107
+ /**
108
+ * DeepSeek V4 Flash's CrofAI lane — and, since the 2026-08-15 cutover, the
109
+ * COHORT MARK that says a session belongs on it.
110
+ *
111
+ * This id now carries two meanings that deliberately coincide. Written at
112
+ * ADMISSION it means "this session was admitted after the cutover, so it enters
113
+ * the cascade on CrofAI". Written by the CASCADE it means "this session
114
+ * diverted onto CrofAI". Both want the same thing — enter on CrofAI — which is
115
+ * why pins written by the pre-cutover code needed no migration when the
116
+ * cutover shipped, and why nothing has to distinguish them on read.
117
+ *
118
+ * A session with NO pin is, by construction, one admitted before the cutover
119
+ * shipped: it runs the pre-cutover order and keeps the prompt cache it has
120
+ * already paid to warm. See `deepseekEntryLane` and
121
+ * docs/anvil-deepseek-provider-cutover.md.
122
+ *
123
+ * Reference prices, from live billing 2026-08-04, per M:
124
+ *
125
+ * input cache read output
126
+ * CrofAI 0731 0.1200 0.0030 0.2100
127
+ * Infron alibaba 0.0690 0.0144 0.1375
128
+ * OpenRouter 0.0881 0.0176 0.1761
129
+ * DeepSeek direct 0.1400 0.0028 0.2800
130
+ *
131
+ * CrofAI is DEARER on fresh input and output and cheaper than everything except
132
+ * DeepSeek direct on cache reads — but a coding turn re-sends its whole prefix
133
+ * every step, so cache reads are most of the tokens and that is the term that
134
+ * decides the bill. Against Infron, 0.0030 vs 0.0144 is a 4.8x cut on the
135
+ * dominant term; break-even is around an 82% cache-hit rate, which a
136
+ * sticky-pinned session clears comfortably and a single cold turn does not.
137
+ * That is the trade this ordering makes, and it is why the ordering would be
138
+ * wrong if these lanes were not sticky.
139
+ *
140
+ * It also serves `deepseek-v4-flash-0731` — the GA build, the same one
141
+ * DeepSeek's own API serves — where Infron's undated slug is a frozen preview
142
+ * snapshot. So this lane matches the DeepSeek-direct lane behind it in
143
+ * behaviour as well as price.
144
+ */
145
+ export const DEEPSEEK_CROF_PROVIDER_ROUTE =
146
+ 'deepseek/crof' satisfies ProviderRouteId
147
+ /**
148
+ * DeepSeek's own API — the lane a cutover session diverts to, and the lane
149
+ * every PRE-cutover session still enters on.
150
+ *
151
+ * It was the unpinned default until 2026-08-15, which is why it had no route id
152
+ * before: a lane nothing ever moves to needs no name. Now that a cutover
153
+ * session can divert here, it has to be able to say so, and to stay — its
154
+ * prompt cache is warm on this upstream, and sending the next turn back to a
155
+ * CrofAI that just failed would pay a cold prefill to reach a lane we already
156
+ * know is unhealthy. The pin skips CrofAI as an ENTRY point only: it stays in
157
+ * the order behind this lane, because by the next turn the blip has usually
158
+ * cleared and CrofAI is still far cheaper than Infron.
159
+ *
160
+ * Behind CrofAI for cutover sessions despite the marginally better cache-read
161
+ * price ($0.0028/M against $0.0030/M) because DeepSeek is the side that
162
+ * repriced, and because of the
163
+ * failure record that made this a cascade at all: on 2026-08-03/04 it shed peak
164
+ * load with 3,934 x 503 "Service is too busy" and diverted 4,997 sessions at
165
+ * once, and on 2026-08-11 it accepted 650 requests in six hours and then sent
166
+ * nothing, tripping the four-minute first-token watchdog. Note that the
167
+ * watchdog is DeepSeek-direct-only (see `handleDeepSeekStream`); no equivalent
168
+ * guards the CrofAI lane now serving in front of it.
169
+ */
170
+ export const DEEPSEEK_OFFICIAL_PROVIDER_ROUTE =
171
+ 'deepseek/official' satisfies ProviderRouteId
172
+ /**
173
+ * DeepSeek V4 Flash's LAST resort: the Infron lane, tier 3 of THREE.
174
+ *
175
+ * It gets ONE attempt and leaves no resumable pin (see `asDeepSeekLane`): its
176
+ * cache reads are 4.8x CrofAI's, so a session must never settle here.
177
+ *
178
+ * Ordering is deliberate and was arrived at the hard way. Infron is the
179
+ * cheapest route we have for this model — measured live 2026-08-04 on a
180
+ * 45,008-token prompt, $0.069/M input and ~$0.0144/M cache read against the
181
+ * OpenRouter lane's $0.0881 and $0.0176, so ~22% cheaper cold and ~13% warm.
182
+ * But it is a single aggregator account behind one Alibaba provider group, and
183
+ * when 4,997 sessions diverted onto it in one window it returned 13,286
184
+ * saturation 429s and then ran out of credits entirely.
185
+ *
186
+ * So it sits behind {@link DEEPSEEK_CROF_PROVIDER_ROUTE} and {@link
187
+ * DEEPSEEK_OFFICIAL_PROVIDER_ROUTE}: cheapest on FRESH input, which is what a
188
+ * cold session pays, while the two lanes ahead of it win the warm case on cache
189
+ * reads, and it must never be the lane a session settles on. This only works
190
+ * because the cascade RE-PINS on each hop — a session that finds Infron
191
+ * saturated does not pay a doomed Infron attempt on every later turn.
192
+ *
193
+ * The `makora` in the name is historical (that upstream went offline in
194
+ * 2026-07). The id says only *that* a session is on this lane, never which
195
+ * upstream serves it — that is INFRON_PROVIDER_ORDER, keyed by model — so
196
+ * repointing the upstream also moves sessions already pinned here. Renaming the
197
+ * value itself would need a migration; it is persisted in
198
+ * `free_session.provider_route` and read back unvalidated.
199
+ */
200
+ export const DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE =
201
+ 'infron/makora' satisfies ProviderRouteId
202
+ /**
203
+ * RETIRED as a DeepSeek lane on 2026-08-11. Kept as a recognized id because it
204
+ * is persisted in `free_session.provider_route` and read back unvalidated —
205
+ * sessions still carrying the pin must not crash; they simply start from the
206
+ * primary again, which is the right answer for a lane that no longer exists.
207
+ *
208
+ * Why it went: it prices cache reads at $0.0176/M against CrofAI's $0.0030,
209
+ * and an agent turn re-sends its whole prefix every step, so ~98% of the
210
+ * tokens land on exactly that term. Being "last resort" did not bound the
211
+ * damage — the pin only moved forward, so one transient 429 on the lane above
212
+ * parked a session here for the rest of its hour. It was reached 1,205 times
213
+ * in 24h, more often than the lane ahead of it, and DeepSeek's daily bill went
214
+ * from $9k to $39.7k over four days while volume rose only 41%. Depth that
215
+ * costs 5.9x on the dominant token class is not depth.
216
+ *
217
+ * The replacement for that depth is retries: the two cheap lanes are attempted
218
+ * three times each before anything diverts.
219
+ *
220
+ * (Historical, for the MiMo lane which still uses OpenRouter:)
221
+ * DeepSeek V4 Flash's LAST resort: the OpenRouter lane, tier 4 of four.
222
+ *
223
+ * Reached when DeepSeek direct and then {@link
224
+ * DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE} have both failed retryably. Dearer per
225
+ * token than Infron but backed by many independent upstreams and a balance that
226
+ * is not one account's, which is exactly what a divert storm needs — see the
227
+ * Infron route's doc for why the cheap lane cannot be the last one.
228
+ *
229
+ * Like its MiMo peer it names the LANE, not the upstream — that is {@link
230
+ * DEEPSEEK_OPENROUTER_UPSTREAM_ORDER} below, so repointing the order also moves
231
+ * every session already pinned here, with no migration.
232
+ */
233
+ export const DEEPSEEK_OPENROUTER_PROVIDER_ROUTE =
234
+ 'deepseek/openrouter' satisfies ProviderRouteId
235
+ /**
236
+ * The upstreams that serve {@link DEEPSEEK_OPENROUTER_PROVIDER_ROUTE},
237
+ * preferred first.
238
+ *
239
+ * Chosen as *cheapest that still preserves the prompt cache*, which for an
240
+ * agent workload are not the same axis. Cache-read price is what actually
241
+ * drives this bill — a coding turn re-sends a long prefix every step, so most
242
+ * input tokens are cache reads — and the OpenRouter catalog splits cleanly on
243
+ * it (checked live 2026-08-04, per M):
244
+ *
245
+ * streamlake/fp8 $0.0881 in $0.0176 cache $0.1761 out fp8 384k max out
246
+ * baidu/fp8 $0.0882 in $0.0176 cache $0.1764 out fp8 131k max out
247
+ * gmicloud/fp8 $0.0938 in $0.0188 cache $0.1876 out fp8 no stated cap
248
+ * ── everything below is >=1.5x the cache-read price ──
249
+ * most of the tail $0.14 in $0.0280 cache $0.2800 out
250
+ * parasail/coreweave/phala $0.0700 cache (4x)
251
+ * morph, mancer/fp4 NO cache read at all
252
+ *
253
+ * So the three cheapest on input are also the three cheapest on cache read;
254
+ * there is no tradeoff to make here, which is why the list is short.
255
+ *
256
+ * DELIBERATELY NOT `deepseek` (OpenRouter's DeepSeek-first-party endpoint).
257
+ * It has by far the best cache read ($0.0028/M) and is tempting for that alone,
258
+ * but it is the same upstream whose failure triggers this fallback, reached
259
+ * through a middleman — pointing the lane there would divert an outage onto
260
+ * itself. The Infron lane can use the 0731 model without this problem because
261
+ * it pins independent Alibaba upstreams.
262
+ *
263
+ * `deepinfra/fp4` is skipped despite sitting third on price: fp4 quantization,
264
+ * and a 65,536-token output cap that would truncate long agent turns. fp8 is
265
+ * the floor for this lane.
266
+ *
267
+ * THREE ENTRIES, and it must never go to one — see the identical warning on
268
+ * {@link mimoOpenRouterProvider}. A pinned session has no health check and no
269
+ * un-pin path, so a one-deep lane turns a single upstream blip into a wedged
270
+ * session. That is not hypothetical here: this model's previous fallback was
271
+ * pinned one-deep to `makora` and took out 1,160 requests across 191 users for
272
+ * ~32h when it went offline (2026-07-26/27, #1045).
273
+ *
274
+ * Caveat on the third entry: `gmicloud/fp8` does not list `stop` in its
275
+ * supported parameters. Without `require_parameters` OpenRouter drops the
276
+ * unsupported field rather than refusing to route, so a turn served there does
277
+ * not honor the global stop sequence. Accepted for depth — it only serves when
278
+ * both fp8 upstreams above it are unavailable — but do not promote it.
279
+ */
280
+ export const DEEPSEEK_OPENROUTER_UPSTREAM_ORDER = [
281
+ 'streamlake/fp8',
282
+ 'baidu/fp8',
283
+ 'gmicloud/fp8',
284
+ ] as const
285
+
286
+ /**
287
+ * The OpenRouter output cap this lane requests.
288
+ *
289
+ * Matches `streamlake/fp8`'s 384,000-token ceiling — the first upstream in the
290
+ * order — so a caller's explicit budget can never make the preferred endpoint
291
+ * ineligible. Slightly under DeepSeek direct's 393,216, same as the Infron lane
292
+ * this replaces: keep fallback requests inside the contract of the route that
293
+ * will actually serve them.
294
+ */
295
+ export const DEEPSEEK_OPENROUTER_MAX_TOKENS = 384_000
296
+
297
+ /**
298
+ * Fresh OpenRouter `provider` block for the DeepSeek V4 Flash lane.
299
+ *
300
+ * Returns a NEW object with a NEW array every call — these arrays get aliased
301
+ * into an outgoing request body, and one downstream mutation would corrupt
302
+ * routing process-wide (the bug `INFRON_PROVIDER_ORDER` was made
303
+ * copy-on-assignment for in #1045).
304
+ *
305
+ * `allow_fallbacks: false` is what preserves the prompt cache: it holds the
306
+ * session to this order instead of letting OpenRouter spread turns across
307
+ * twenty endpoints that each keep their own cache. Cache fragmentation is the
308
+ * expensive failure mode, not a slightly dearer per-token rate — measured on
309
+ * the MiMo lane, a scattered fallback averaged 27.6k cache_read against ~150k
310
+ * prompts, paying a full cold prefill per divert.
311
+ */
312
+ export function deepseekOpenRouterProvider(): Record<string, unknown> {
313
+ return {
314
+ order: [...DEEPSEEK_OPENROUTER_UPSTREAM_ORDER],
315
+ allow_fallbacks: false,
316
+ }
317
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The one reasoning-effort vocabulary, shared by every surface.
3
+ *
4
+ * This list started in `anvil-desktop/src/shared/types.ts`, where it drives
5
+ * the Claude Code and Codex effort pickers. It lives here now so the Anvil
6
+ * model catalog and Desktop speak the same words: Desktop re-exports these,
7
+ * so a value persisted on a Desktop thread and a value on a Anvil catalog
8
+ * row are the same strings, comparable without a translation table.
9
+ *
10
+ * ORDERED, ascending, and that order is load-bearing — `clampReasoningEffort`
11
+ * does index arithmetic on it to answer "the most effort this model allows,
12
+ * but no more than was asked for". Keep it strictly ascending.
13
+ *
14
+ * Not every rung reaches every provider. `ultra` exists only for local CLI
15
+ * harnesses; Meta tops out at `xhigh`, while both DeepSeek V4 models expose
16
+ * `low`/`high`/`max` and nothing between. What a given model actually offers is
17
+ * its own `efforts` array, and the clamp stops one model's rung reaching
18
+ * another's API.
19
+ */
20
+ export const REASONING_EFFORTS = [
21
+ 'minimal',
22
+ 'low',
23
+ 'medium',
24
+ 'high',
25
+ 'xhigh',
26
+ 'max',
27
+ 'ultra',
28
+ ] as const
29
+
30
+ export type ReasoningEffort = (typeof REASONING_EFFORTS)[number]
31
+
32
+ /** Kept explicit so a picker and a turn agree, rather than each deferring to
33
+ * some CLI's own default. */
34
+ export const DEFAULT_REASONING_EFFORT: ReasoningEffort = 'high'
35
+
36
+ export function isReasoningEffort(value: unknown): value is ReasoningEffort {
37
+ return REASONING_EFFORTS.includes(value as ReasoningEffort)
38
+ }
39
+
40
+ /** Position on the shared ladder, or -1. Exported for tests that assert one
41
+ * rung sits below another without hard-coding the list. */
42
+ export function reasoningEffortRank(value: unknown): number {
43
+ return REASONING_EFFORTS.indexOf(value as ReasoningEffort)
44
+ }
45
+
46
+ /**
47
+ * The highest rung `allowed` offers that is no higher than `requested`.
48
+ *
49
+ * Clamp-DOWN, not "reject and fall back", and the difference matters. A user on
50
+ * Muse Spark's `xhigh` whose request is rerouted to a model topping out at
51
+ * `high` should land on `high` — the closest thing to what they asked for —
52
+ * rather than snapping back to that model's default, which could be lower.
53
+ * When `requested` is below everything on offer, the lowest rung wins; when it
54
+ * is absent or unrecognized, the caller's fallback does.
55
+ */
56
+ export function clampReasoningEffort(
57
+ requested: unknown,
58
+ allowed: readonly ReasoningEffort[],
59
+ fallback: ReasoningEffort,
60
+ ): ReasoningEffort {
61
+ if (allowed.length === 0) return fallback
62
+ if (!isReasoningEffort(requested)) return fallback
63
+
64
+ const wanted = reasoningEffortRank(requested)
65
+ let best: ReasoningEffort | undefined
66
+ for (const candidate of allowed) {
67
+ const rank = reasoningEffortRank(candidate)
68
+ if (rank > wanted) continue
69
+ if (best === undefined || rank > reasoningEffortRank(best)) best = candidate
70
+ }
71
+ if (best !== undefined) return best
72
+
73
+ // Everything on offer is above what was asked for: give the least of them.
74
+ return allowed.reduce((lowest, candidate) =>
75
+ reasoningEffortRank(candidate) < reasoningEffortRank(lowest)
76
+ ? candidate
77
+ : lowest,
78
+ )
79
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Skills constants and validation rules.
3
+ *
4
+ * Skills are SKILL.md files with YAML frontmatter that define reusable
5
+ * instructions that agents can load on-demand via the skill tool.
6
+ */
7
+
8
+ /**
9
+ * The directory name where skills are stored (within .agents/).
10
+ */
11
+ export const SKILLS_DIR_NAME = 'skills'
12
+
13
+ /**
14
+ * The file name for skill definitions.
15
+ */
16
+ export const SKILL_FILE_NAME = 'SKILL.md'
17
+
18
+ /**
19
+ * Validation regex for skill names.
20
+ * - 1-64 characters
21
+ * - Lowercase alphanumeric with single hyphen separators
22
+ * - Cannot start or end with hyphen
23
+ * - No consecutive hyphens
24
+ */
25
+ export const SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/
26
+
27
+ /**
28
+ * Maximum length for skill name.
29
+ */
30
+ export const SKILL_NAME_MAX_LENGTH = 64
31
+
32
+ /**
33
+ * Maximum length for skill description.
34
+ */
35
+ export const SKILL_DESCRIPTION_MAX_LENGTH = 1024
36
+
37
+ /**
38
+ * Validates a skill name according to the naming rules.
39
+ * @param name - The skill name to validate
40
+ * @returns true if valid, false otherwise
41
+ */
42
+ export function isValidSkillName(name: string): boolean {
43
+ if (!name || name.length > SKILL_NAME_MAX_LENGTH) {
44
+ return false
45
+ }
46
+ return SKILL_NAME_REGEX.test(name)
47
+ }
48
+
49
+ /**
50
+ * Validates a skill description according to length rules.
51
+ * @param description - The skill description to validate
52
+ * @returns true if valid, false otherwise
53
+ */
54
+ export function isValidSkillDescription(description: string): boolean {
55
+ return (
56
+ typeof description === 'string' &&
57
+ description.length >= 1 &&
58
+ description.length <= SKILL_DESCRIPTION_MAX_LENGTH
59
+ )
60
+ }
@@ -0,0 +1,49 @@
1
+ export const SUBSCRIPTION_DISPLAY_NAME = 'Strong' as const
2
+
3
+ export interface TierConfig {
4
+ monthlyPrice: number
5
+ creditsPerBlock: number
6
+ blockDurationHours: number
7
+ weeklyCreditsLimit: number
8
+ }
9
+
10
+ export const SUBSCRIPTION_TIERS = {
11
+ 100: {
12
+ monthlyPrice: 100,
13
+ creditsPerBlock: 420,
14
+ blockDurationHours: 5,
15
+ weeklyCreditsLimit: 4200,
16
+ },
17
+ 200: {
18
+ monthlyPrice: 200,
19
+ creditsPerBlock: 1050,
20
+ blockDurationHours: 5,
21
+ weeklyCreditsLimit: 10500,
22
+ },
23
+ 500: {
24
+ monthlyPrice: 500,
25
+ creditsPerBlock: 2940,
26
+ blockDurationHours: 5,
27
+ weeklyCreditsLimit: 29400,
28
+ },
29
+ } as const satisfies Record<number, TierConfig>
30
+
31
+ export type SubscriptionTierPrice = keyof typeof SUBSCRIPTION_TIERS
32
+
33
+ export const DEFAULT_TIER = SUBSCRIPTION_TIERS[200]
34
+
35
+ export function createSubscriptionPriceMappings(priceIds: Record<SubscriptionTierPrice, string>) {
36
+ const priceToTier = Object.fromEntries(
37
+ Object.entries(priceIds).map(([tier, priceId]) => [priceId, Number(tier) as SubscriptionTierPrice]),
38
+ ) as Record<string, SubscriptionTierPrice>
39
+
40
+ function getTierFromPriceId(priceId: string): SubscriptionTierPrice | null {
41
+ return priceToTier[priceId] ?? null
42
+ }
43
+
44
+ function getPriceIdFromTier(tier: SubscriptionTierPrice): string | null {
45
+ return priceIds[tier] ?? null
46
+ }
47
+
48
+ return { getTierFromPriceId, getPriceIdFromTier }
49
+ }
@@ -0,0 +1,25 @@
1
+ export const AuthState = {
2
+ LOGGED_OUT: 'LOGGED_OUT',
3
+ LOGGED_IN: 'LOGGED_IN',
4
+ } as const
5
+
6
+ export type AuthState = (typeof AuthState)[keyof typeof AuthState]
7
+
8
+ export const UserState = {
9
+ LOGGED_OUT: 'LOGGED_OUT',
10
+ GOOD_STANDING: 'GOOD_STANDING', // >= 100 credits
11
+ ATTENTION_NEEDED: 'ATTENTION_NEEDED', // 20-99 credits
12
+ CRITICAL: 'CRITICAL', // 1-19 credits
13
+ DEPLETED: 'DEPLETED', // <= 0 credits
14
+ } as const
15
+
16
+ export type UserState = (typeof UserState)[keyof typeof UserState]
17
+
18
+ export function getUserState(isLoggedIn: boolean, credits: number): UserState {
19
+ if (!isLoggedIn) return UserState.LOGGED_OUT
20
+
21
+ if (credits >= 100) return UserState.GOOD_STANDING
22
+ if (credits >= 20) return UserState.ATTENTION_NEEDED
23
+ if (credits >= 1) return UserState.CRITICAL
24
+ return UserState.DEPLETED
25
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CI environment helper for dependency injection.
3
+ *
4
+ * This module provides a typed interface to CI-specific environment variables.
5
+ * These are used in CI/CD pipelines and eval contexts.
6
+ * In tests, use `@anvil/common/testing-env-ci`.
7
+ */
8
+
9
+ import type { CiEnv } from './types/contracts/env'
10
+
11
+ /**
12
+ * Get CI environment values.
13
+ * Returns a snapshot of the current process.env values for CI-specific vars.
14
+ */
15
+ export const getCiEnv = (): CiEnv => ({
16
+ CI: process.env.CI,
17
+ GITHUB_ACTIONS: process.env.GITHUB_ACTIONS,
18
+ RENDER: process.env.RENDER,
19
+ IS_PULL_REQUEST: process.env.IS_PULL_REQUEST,
20
+ ANVIL_GITHUB_TOKEN: process.env.ANVIL_GITHUB_TOKEN,
21
+ ANVIL_API_KEY: process.env.ANVIL_API_KEY,
22
+ })
23
+
24
+ /**
25
+ * Default CI env instance.
26
+ * Use this for production code, inject mocks in tests.
27
+ */
28
+ export const ciEnv: CiEnv = getCiEnv()
29
+
30
+ /**
31
+ * Check if running in CI environment
32
+ */
33
+ export const isCI = (): boolean => {
34
+ const env = getCiEnv()
35
+ return env.CI === 'true' || env.CI === '1' || env.GITHUB_ACTIONS === 'true'
36
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Process environment helper for dependency injection.
3
+ *
4
+ * This module provides a typed interface to process.env values that aren't
5
+ * part of our validated schemas (ClientEnv/ServerEnv). These are runtime
6
+ * environment variables like SHELL, HOME, TERM, etc.
7
+ *
8
+ * Usage:
9
+ * - Import `getBaseEnv` for base OS-level vars only
10
+ * - Import `getProcessEnv` for the full ProcessEnv (base + extensions)
11
+ * - In tests, use `@anvil/common/testing-env-process`
12
+ */
13
+
14
+ import type { BaseEnv, ProcessEnv } from './types/contracts/env'
15
+
16
+ /**
17
+ * Get base environment values (OS-level vars only).
18
+ * This is the foundation that package-specific helpers should spread into.
19
+ */
20
+ export const getBaseEnv = (): BaseEnv => ({
21
+ SHELL: process.env.SHELL,
22
+ COMSPEC: process.env.COMSPEC,
23
+ HOME: process.env.HOME,
24
+ USERPROFILE: process.env.USERPROFILE,
25
+ APPDATA: process.env.APPDATA,
26
+ XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,
27
+ TERM: process.env.TERM,
28
+ TERM_PROGRAM: process.env.TERM_PROGRAM,
29
+ TERM_BACKGROUND: process.env.TERM_BACKGROUND,
30
+ TERMINAL_EMULATOR: process.env.TERMINAL_EMULATOR,
31
+ COLORFGBG: process.env.COLORFGBG,
32
+ NODE_ENV: process.env.NODE_ENV,
33
+ NODE_PATH: process.env.NODE_PATH,
34
+ PATH: process.env.PATH,
35
+ })
36
+
37
+ /**
38
+ * Get full process environment values (base + all extensions).
39
+ * Returns a snapshot of the current process.env values for the ProcessEnv type.
40
+ */
41
+ export const getProcessEnv = (): ProcessEnv => ({
42
+ ...getBaseEnv(),
43
+
44
+ // Terminal-specific
45
+ KITTY_WINDOW_ID: process.env.KITTY_WINDOW_ID,
46
+ SIXEL_SUPPORT: process.env.SIXEL_SUPPORT,
47
+ ZED_NODE_ENV: process.env.ZED_NODE_ENV,
48
+
49
+ // VS Code family detection
50
+ VSCODE_THEME_KIND: process.env.VSCODE_THEME_KIND,
51
+ VSCODE_COLOR_THEME_KIND: process.env.VSCODE_COLOR_THEME_KIND,
52
+ VSCODE_GIT_IPC_HANDLE: process.env.VSCODE_GIT_IPC_HANDLE,
53
+ VSCODE_PID: process.env.VSCODE_PID,
54
+ VSCODE_CWD: process.env.VSCODE_CWD,
55
+ VSCODE_NLS_CONFIG: process.env.VSCODE_NLS_CONFIG,
56
+
57
+ // Cursor editor detection
58
+ CURSOR_PORT: process.env.CURSOR_PORT,
59
+ CURSOR: process.env.CURSOR,
60
+
61
+ // JetBrains IDE detection
62
+ JETBRAINS_REMOTE_RUN: process.env.JETBRAINS_REMOTE_RUN,
63
+ IDEA_INITIAL_DIRECTORY: process.env.IDEA_INITIAL_DIRECTORY,
64
+ IDE_CONFIG_DIR: process.env.IDE_CONFIG_DIR,
65
+ JB_IDE_CONFIG_DIR: process.env.JB_IDE_CONFIG_DIR,
66
+
67
+ // Editor preferences
68
+ VISUAL: process.env.VISUAL,
69
+ EDITOR: process.env.EDITOR,
70
+ ANVIL_CLI_EDITOR: process.env.ANVIL_CLI_EDITOR,
71
+ ANVIL_EDITOR: process.env.ANVIL_EDITOR,
72
+
73
+ // Theme preferences
74
+ OPEN_TUI_THEME: process.env.OPEN_TUI_THEME,
75
+ OPENTUI_THEME: process.env.OPENTUI_THEME,
76
+
77
+ // Anvil CLI-specific
78
+ ANVIL_IS_BINARY: process.env.ANVIL_IS_BINARY,
79
+ ANVIL_CLI_VERSION: process.env.ANVIL_CLI_VERSION,
80
+ ANVIL_CLI_TARGET: process.env.ANVIL_CLI_TARGET,
81
+ ANVIL_RG_PATH: process.env.ANVIL_RG_PATH,
82
+ ANVIL_WASM_DIR: process.env.ANVIL_WASM_DIR,
83
+
84
+ // Build/CI flags
85
+ VERBOSE: process.env.VERBOSE,
86
+ OVERRIDE_TARGET: process.env.OVERRIDE_TARGET,
87
+ OVERRIDE_PLATFORM: process.env.OVERRIDE_PLATFORM,
88
+ OVERRIDE_ARCH: process.env.OVERRIDE_ARCH,
89
+ })
90
+
91
+ /**
92
+ * Default process env instance.
93
+ * Use this for production code, inject mocks in tests.
94
+ */
95
+ export const processEnv: ProcessEnv = getProcessEnv()