@alumbwe/anvil 1.0.20 → 1.0.22

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 +74 -70
  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,38 @@
1
+ export const DEFAULT_ORG_PREFIX = 'anvil/'
2
+
3
+ /**
4
+ * Resolves an agent ID by trying multiple strategies:
5
+ * 1. Direct lookup in registry
6
+ * 2. Try with DEFAULT_ORG_PREFIX for spawnable agents
7
+ * 3. Return null if not found
8
+ *
9
+ * This provides a more robust alternative to string concatenation
10
+ * and handles the common case where users reference spawnable agents
11
+ * without the org prefix.
12
+ */
13
+ export function resolveAgentId(
14
+ agentId: string,
15
+ agentRegistry: Record<string, any>,
16
+ ): string | null {
17
+ // Handle empty or invalid input
18
+ if (!agentId || typeof agentId !== 'string') {
19
+ return null
20
+ }
21
+
22
+ // Try direct lookup first
23
+ if (agentId in agentRegistry) {
24
+ return agentId
25
+ }
26
+
27
+ // Try with DEFAULT_ORG_PREFIX for spawnable agents
28
+ // Only add prefix if the agent ID doesn't already contain a slash
29
+ // (to avoid double-prefixing or interfering with other org prefixes)
30
+ if (!agentId.includes('/')) {
31
+ const prefixedAgentId = `${DEFAULT_ORG_PREFIX}${agentId}`
32
+ if (prefixedAgentId in agentRegistry) {
33
+ return prefixedAgentId
34
+ }
35
+ }
36
+
37
+ return null
38
+ }
@@ -0,0 +1,86 @@
1
+ import { AGENT_PERSONAS } from '../constants/agents'
2
+
3
+ export interface AgentInfo {
4
+ id: string
5
+ displayName: string
6
+ purpose?: string
7
+ isBuiltIn: boolean
8
+ }
9
+
10
+ /**
11
+ * Get all built-in agents (excluding hidden ones)
12
+ */
13
+ export function getBuiltInAgents(): AgentInfo[] {
14
+ return Object.entries(AGENT_PERSONAS)
15
+ .filter(([, persona]) => !('hidden' in persona) || !persona.hidden)
16
+ .map(([agentId, persona]) => ({
17
+ id: agentId,
18
+ displayName: persona.displayName,
19
+ purpose: persona.purpose,
20
+ isBuiltIn: true,
21
+ }))
22
+ }
23
+
24
+ /**
25
+ * Convert local agent configs to AgentInfo array
26
+ */
27
+ export function getLocalAgents(
28
+ localAgents: Record<string, { displayName: string; purpose?: string }>,
29
+ ): AgentInfo[] {
30
+ return Object.entries(localAgents).map(([agentId, config]) => ({
31
+ id: agentId,
32
+ displayName: config.displayName,
33
+ purpose: config.purpose,
34
+ isBuiltIn: false,
35
+ }))
36
+ }
37
+
38
+ /**
39
+ * Get all agents (built-in + local)
40
+ */
41
+ export function getAllAgents(
42
+ localAgents: Record<string, { displayName: string; purpose?: string }> = {},
43
+ ): AgentInfo[] {
44
+ return [...getBuiltInAgents(), ...getLocalAgents(localAgents)]
45
+ }
46
+
47
+ /**
48
+ * Resolve display name to agent ID
49
+ */
50
+ export function resolveNameToId(
51
+ displayName: string,
52
+ localAgents: Record<string, { displayName: string; purpose?: string }> = {},
53
+ ): string | null {
54
+ const agents = getAllAgents(localAgents)
55
+ const agent = agents.find(
56
+ (a) => a.displayName.toLowerCase() === displayName.toLowerCase(),
57
+ )
58
+ return agent?.id || null
59
+ }
60
+
61
+ /**
62
+ * Resolve agent ID to display name
63
+ */
64
+ function resolveIdToName(
65
+ agentId: string,
66
+ localAgents: Record<string, { displayName: string; purpose?: string }> = {},
67
+ ): string | null {
68
+ const agents = getAllAgents(localAgents)
69
+ const agent = agents.find((a) => a.id === agentId)
70
+ return agent?.displayName || null
71
+ }
72
+
73
+ /**
74
+ * Get agent display name from ID or name, with fallback
75
+ */
76
+ export function getAgentDisplayName(
77
+ agentIdOrName: string,
78
+ localAgents: Record<string, { displayName: string; purpose?: string }> = {},
79
+ ): string {
80
+ return (
81
+ resolveIdToName(agentIdOrName, localAgents) ||
82
+ (resolveNameToId(agentIdOrName, localAgents)
83
+ ? agentIdOrName
84
+ : agentIdOrName)
85
+ )
86
+ }
@@ -0,0 +1,82 @@
1
+
2
+ import {
3
+ getAnalyticsEventId,
4
+ toTrackableAnalyticsPayload,
5
+ type AnalyticsLogData,
6
+ type TrackableAnalyticsPayload,
7
+ } from './analytics-log'
8
+
9
+ type EnvName = 'dev' | 'test' | 'prod' | string
10
+
11
+ export type AnalyticsDispatchInput = {
12
+ data: unknown
13
+ level: string
14
+ msg: string
15
+ fallbackUserId?: string
16
+ }
17
+
18
+ export type AnalyticsDispatchPayload = TrackableAnalyticsPayload
19
+
20
+ /**
21
+ * Minimal, runtime-agnostic router for analytics events.
22
+ * Handles:
23
+ * - Dev gating (no-op in dev)
24
+ * - Optional buffering until a userId is available
25
+ * - Reusing the shared payload builder for consistency
26
+ */
27
+ export function createAnalyticsDispatcher({
28
+ envName,
29
+ bufferWhenNoUser = false,
30
+ }: {
31
+ envName: EnvName
32
+ bufferWhenNoUser?: boolean
33
+ }) {
34
+ const buffered: AnalyticsDispatchInput[] = []
35
+ const isDevEnv = envName === 'dev'
36
+
37
+ function flushBufferWithUser(
38
+ userId: string,
39
+ ): AnalyticsDispatchPayload[] {
40
+ if (!buffered.length) {
41
+ return []
42
+ }
43
+
44
+ const toSend: AnalyticsDispatchPayload[] = []
45
+ for (const item of buffered.splice(0)) {
46
+ const rebuilt = toTrackableAnalyticsPayload({
47
+ ...item,
48
+ fallbackUserId: userId,
49
+ })
50
+ if (rebuilt) {
51
+ toSend.push(rebuilt)
52
+ }
53
+ }
54
+ return toSend
55
+ }
56
+
57
+ function process(
58
+ input: AnalyticsDispatchInput,
59
+ ): AnalyticsDispatchPayload[] {
60
+ if (isDevEnv) {
61
+ return []
62
+ }
63
+
64
+ const payload = toTrackableAnalyticsPayload(input)
65
+ if (payload) {
66
+ const toSend = flushBufferWithUser(payload.userId)
67
+ toSend.push(payload)
68
+ return toSend
69
+ }
70
+
71
+ if (
72
+ bufferWhenNoUser &&
73
+ getAnalyticsEventId(input.data as AnalyticsLogData)
74
+ ) {
75
+ buffered.push(input)
76
+ }
77
+
78
+ return []
79
+ }
80
+
81
+ return { process }
82
+ }
@@ -0,0 +1,78 @@
1
+ import { AnalyticsEvent } from '@anvil/common/constants/analytics-events'
2
+
3
+ // Build PostHog payloads from log data in a single, shared place
4
+ export type AnalyticsLogData = {
5
+ eventId?: unknown
6
+ userId?: unknown
7
+ user_id?: unknown
8
+ user?: { id?: unknown }
9
+ [key: string]: unknown
10
+ }
11
+
12
+ export type TrackableAnalyticsPayload = {
13
+ event: AnalyticsEvent
14
+ userId: string
15
+ properties: Record<string, unknown>
16
+ }
17
+
18
+ const analyticsEvents = new Set<AnalyticsEvent>(Object.values(AnalyticsEvent))
19
+
20
+ const toStringOrNull = (value: unknown): string | null =>
21
+ typeof value === 'string' ? value : null
22
+
23
+ const getUserId = (
24
+ record: AnalyticsLogData,
25
+ fallbackUserId?: string,
26
+ ): string | null =>
27
+ toStringOrNull(record.userId) ??
28
+ toStringOrNull(record.user_id) ??
29
+ toStringOrNull(record.user?.id) ??
30
+ toStringOrNull(fallbackUserId)
31
+
32
+ export function getAnalyticsEventId(data: unknown): AnalyticsEvent | null {
33
+ if (!data || typeof data !== 'object') {
34
+ return null
35
+ }
36
+ const eventId = (data as AnalyticsLogData).eventId
37
+ return analyticsEvents.has(eventId as AnalyticsEvent)
38
+ ? (eventId as AnalyticsEvent)
39
+ : null
40
+ }
41
+
42
+ export function toTrackableAnalyticsPayload({
43
+ data,
44
+ level,
45
+ msg,
46
+ fallbackUserId,
47
+ }: {
48
+ data: unknown
49
+ level: string
50
+ msg: string
51
+ fallbackUserId?: string
52
+ }): TrackableAnalyticsPayload | null {
53
+ if (!data || typeof data !== 'object') {
54
+ return null
55
+ }
56
+
57
+ const record = data as AnalyticsLogData
58
+ const eventId = getAnalyticsEventId(record)
59
+ if (!eventId) {
60
+ return null
61
+ }
62
+
63
+ const userId = getUserId(record, fallbackUserId)
64
+
65
+ if (!userId) {
66
+ return null
67
+ }
68
+
69
+ return {
70
+ event: eventId,
71
+ userId,
72
+ properties: {
73
+ ...record,
74
+ level,
75
+ msg,
76
+ },
77
+ }
78
+ }
@@ -0,0 +1,255 @@
1
+ import { AnalyticsEvent } from '../constants/analytics-events'
2
+
3
+ const DEFAULT_SAMPLED_RATE = 0.01
4
+
5
+ const SAMPLED_EVENT_RATES: Partial<Record<AnalyticsEvent, number>> = {
6
+ [AnalyticsEvent.AGENT_STEP]: DEFAULT_SAMPLED_RATE,
7
+ [AnalyticsEvent.CLI_LOG]: DEFAULT_SAMPLED_RATE,
8
+ [AnalyticsEvent.FEEDBACK_BUTTON_HOVERED]: DEFAULT_SAMPLED_RATE,
9
+ [AnalyticsEvent.FOLLOWUP_CLICKED]: DEFAULT_SAMPLED_RATE,
10
+ [AnalyticsEvent.CLI_INLINE_AD_SLOT_ELIGIBLE]: DEFAULT_SAMPLED_RATE,
11
+ [AnalyticsEvent.SLASH_COMMAND_USED]: DEFAULT_SAMPLED_RATE,
12
+ [AnalyticsEvent.SLASH_MENU_ACTIVATED]: DEFAULT_SAMPLED_RATE,
13
+ [AnalyticsEvent.TOOL_USE]: DEFAULT_SAMPLED_RATE,
14
+ }
15
+
16
+ const ALWAYS_TRACK_EVENTS = new Set<AnalyticsEvent>([
17
+ // DAU is measured from MESSAGE_SENT, so it must never be sampled.
18
+ AnalyticsEvent.MESSAGE_SENT,
19
+ // Engaged-time is summed from event counts, so it must never be sampled.
20
+ AnalyticsEvent.PRODUCT_ACTIVE_MINUTE,
21
+ AnalyticsEvent.APP_LAUNCHED,
22
+ AnalyticsEvent.CHANGE_DIRECTORY,
23
+ AnalyticsEvent.FINGERPRINT_GENERATED,
24
+ AnalyticsEvent.INVALID_COMMAND,
25
+ AnalyticsEvent.KNOWLEDGE_FILE_UPDATED,
26
+ AnalyticsEvent.LOGIN,
27
+ AnalyticsEvent.LOGIN_STARTED,
28
+ AnalyticsEvent.LOGIN_FAILED,
29
+ AnalyticsEvent.LOGIN_TIMEOUT,
30
+ AnalyticsEvent.LOGIN_ABORTED,
31
+ // Desktop surface events are low-volume; keep them whole so the app's launch /
32
+ // login / activity funnels aren't decimated by the 1% default sample.
33
+ AnalyticsEvent.DESKTOP_APP_LAUNCHED,
34
+ // Both halves of the sign-in funnel, or its conversion rate is a ratio of two
35
+ // differently-sampled numbers.
36
+ AnalyticsEvent.DESKTOP_LOGIN_STARTED,
37
+ AnalyticsEvent.DESKTOP_LOGIN,
38
+ // Rare, and the only evidence a sign-in failed at all — a sampled one is a
39
+ // support ticket with nothing behind it.
40
+ AnalyticsEvent.DESKTOP_LOGIN_FAILED,
41
+ AnalyticsEvent.DESKTOP_LOGOUT,
42
+ AnalyticsEvent.DESKTOP_THREAD_CREATED,
43
+ AnalyticsEvent.DESKTOP_PROJECT_OPENED,
44
+ AnalyticsEvent.DESKTOP_TURN_COMPLETED,
45
+ // Low-volume recovery funnel. Sampling any stage independently would make
46
+ // creation-to-success and repeated-failure rates impossible to measure.
47
+ AnalyticsEvent.DESKTOP_FAILED_TURN_RECOVERY,
48
+ // Rare reliability signal — every stalled turn must be counted, never sampled.
49
+ AnalyticsEvent.DESKTOP_TURN_STALLED,
50
+ // Its counterpart (an explained silence). Same reasoning: rare, and only
51
+ // useful if every one is counted.
52
+ AnalyticsEvent.DESKTOP_TURN_BACKGROUND_WAIT,
53
+ // Feature adoption is measured as UNIQUE USERS per feature. At desktop's
54
+ // ~1-2k DAU a 1% sample would leave a feature used by 2% of users with
55
+ // roughly zero sampled users — the number is unrecoverable from a sample, so
56
+ // this one is never sampled. Volume is controlled at the emit site instead
57
+ // (intent-only actions + per-session dedupe), not by throwing away users.
58
+ AnalyticsEvent.DESKTOP_FEATURE_USED,
59
+ AnalyticsEvent.DESKTOP_HARNESS_CHANGED,
60
+ AnalyticsEvent.DESKTOP_MODEL_CHANGED,
61
+ AnalyticsEvent.DESKTOP_SKILL_RUN,
62
+ AnalyticsEvent.DESKTOP_CODEX_RESOLUTION,
63
+ // Rare operational signal. Sampling would make per-version failure rates
64
+ // misleading precisely when a Windows-only regression affects few installs.
65
+ AnalyticsEvent.TERMINAL_BROKER_SPAWN_FAILED,
66
+ AnalyticsEvent.TERMINAL_WATCHDOG_FAILED,
67
+ AnalyticsEvent.TERMINAL_COMMAND_COMPLETED,
68
+ AnalyticsEvent.UPDATE_ANVIL_FAILED,
69
+ AnalyticsEvent.USER_INPUT,
70
+ AnalyticsEvent.USER_INPUT_COMPLETE,
71
+ ])
72
+
73
+ type AnalyticsProperties = Record<string, unknown> | undefined
74
+
75
+ function getStringProperty(
76
+ properties: AnalyticsProperties,
77
+ key: string,
78
+ ): string | undefined {
79
+ const value = properties?.[key]
80
+ return typeof value === 'string' && value.trim() ? value : undefined
81
+ }
82
+
83
+ function getPropertyUserId(
84
+ properties: AnalyticsProperties,
85
+ ): string | undefined {
86
+ const direct =
87
+ getStringProperty(properties, 'userId') ??
88
+ getStringProperty(properties, 'user_id') ??
89
+ getStringProperty(properties, 'distinct_id')
90
+ if (direct) {
91
+ return direct
92
+ }
93
+
94
+ const user = properties?.user
95
+ if (user && typeof user === 'object') {
96
+ const id = (user as { id?: unknown }).id
97
+ return typeof id === 'string' && id.trim() ? id : undefined
98
+ }
99
+
100
+ return undefined
101
+ }
102
+
103
+ function splitEnvList(value: string | undefined): Set<string> {
104
+ return new Set(
105
+ (value ?? '')
106
+ .split(',')
107
+ .map((item) => item.trim())
108
+ .filter(Boolean),
109
+ )
110
+ }
111
+
112
+ function isTruthyEnv(value: string | undefined): boolean {
113
+ return value === '1' || value === 'true' || value === 'yes'
114
+ }
115
+
116
+ export function isFullTelemetryEnabled(params: {
117
+ distinctId?: string
118
+ properties?: AnalyticsProperties
119
+ }): boolean {
120
+ if (isTruthyEnv(process.env.ANVIL_FULL_TELEMETRY)) {
121
+ return true
122
+ }
123
+
124
+ const ids = splitEnvList(
125
+ process.env.ANVIL_FULL_TELEMETRY_IDS ??
126
+ process.env.ANVIL_FULL_TELEMETRY_USER_IDS,
127
+ )
128
+ if (ids.size === 0) {
129
+ return false
130
+ }
131
+
132
+ const candidates = [
133
+ params.distinctId,
134
+ getPropertyUserId(params.properties),
135
+ getStringProperty(params.properties, 'userEmail'),
136
+ getStringProperty(params.properties, 'email'),
137
+ ].filter(
138
+ (value): value is string => typeof value === 'string' && value.length > 0,
139
+ )
140
+
141
+ return candidates.some((candidate) => ids.has(candidate))
142
+ }
143
+
144
+ function getEventSampleRate(
145
+ event: AnalyticsEvent,
146
+ properties: AnalyticsProperties,
147
+ ): number {
148
+ const level = getStringProperty(properties, 'level')?.toLowerCase()
149
+ if (
150
+ event === AnalyticsEvent.CLI_LOG &&
151
+ (level === 'error' || level === 'fatal')
152
+ ) {
153
+ return 1
154
+ }
155
+
156
+ if (ALWAYS_TRACK_EVENTS.has(event)) {
157
+ return 1
158
+ }
159
+
160
+ return SAMPLED_EVENT_RATES[event] ?? 1
161
+ }
162
+
163
+ /**
164
+ * Deterministic sampling for high-volume logs/events: hashes a stable key
165
+ * (typically a userId) so the same key is always in or out of the sample and
166
+ * per-key funnels stay coherent. Callers should record the rate on sampled
167
+ * rows (e.g. `sampleRate: 0.02`) so counts can be re-inflated in queries.
168
+ */
169
+ export function shouldSampleByKey(key: string, rate: number): boolean {
170
+ if (rate >= 1) return true
171
+ if (rate <= 0) return false
172
+ return hashString(key) / 0xffffffff < rate
173
+ }
174
+
175
+ function hashString(input: string): number {
176
+ let hash = 2166136261
177
+ for (let i = 0; i < input.length; i++) {
178
+ hash ^= input.charCodeAt(i)
179
+ hash = Math.imul(hash, 16777619)
180
+ }
181
+ return hash >>> 0
182
+ }
183
+
184
+ function getSamplingKey(params: {
185
+ event: AnalyticsEvent
186
+ distinctId?: string
187
+ properties?: AnalyticsProperties
188
+ }): string {
189
+ return (
190
+ params.distinctId ??
191
+ getPropertyUserId(params.properties) ??
192
+ getStringProperty(params.properties, 'clientSessionId') ??
193
+ getStringProperty(params.properties, 'userInputId') ??
194
+ params.event
195
+ )
196
+ }
197
+
198
+ export function shouldTrackAnalyticsEvent(params: {
199
+ event: AnalyticsEvent
200
+ distinctId?: string
201
+ properties?: AnalyticsProperties
202
+ }): boolean {
203
+ if (isFullTelemetryEnabled(params)) {
204
+ return true
205
+ }
206
+
207
+ const rate = getEventSampleRate(params.event, params.properties)
208
+ if (rate >= 1) {
209
+ return true
210
+ }
211
+ if (rate <= 0) {
212
+ return false
213
+ }
214
+
215
+ const bucket =
216
+ hashString(`${params.event}:${getSamplingKey(params)}`) / 0xffffffff
217
+ return bucket < rate
218
+ }
219
+
220
+ function valueKind(value: unknown): string {
221
+ if (Array.isArray(value)) {
222
+ return 'array'
223
+ }
224
+ if (value === null) {
225
+ return 'null'
226
+ }
227
+ return typeof value
228
+ }
229
+
230
+ export function summarizeAnalyticsValue(
231
+ value: unknown,
232
+ ): Record<string, unknown> {
233
+ if (value === null || value === undefined) {
234
+ return { kind: valueKind(value) }
235
+ }
236
+
237
+ if (typeof value === 'string') {
238
+ return { kind: 'string', length: value.length }
239
+ }
240
+
241
+ if (Array.isArray(value)) {
242
+ return { kind: 'array', length: value.length }
243
+ }
244
+
245
+ if (typeof value === 'object') {
246
+ const keys = Object.keys(value as Record<string, unknown>)
247
+ return {
248
+ kind: 'object',
249
+ keyCount: keys.length,
250
+ keys: keys.slice(0, 25),
251
+ }
252
+ }
253
+
254
+ return { kind: valueKind(value) }
255
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * One line answering "why these models?" for a user whose account resolved to
3
+ * the reduced catalog.
4
+ *
5
+ * Tone matters here: this is shown to users who, through no fault of their own,
6
+ * get the smaller model set. Frame it as model *availability* ("aren't
7
+ * available in BR yet"), never as restricted *access* ("limited mode",
8
+ * "blocked") — clear enough to answer the question for someone who goes
9
+ * looking, quiet enough to ignore for someone who doesn't. The VPN case is the
10
+ * one the user can act on, so it leads with the action.
11
+ *
12
+ * Shared by the CLI landing picker and the Desktop model menu so the two
13
+ * surfaces cannot drift — a user who reads it in one and asks support about the
14
+ * other should be told the same thing.
15
+ */
16
+
17
+ import type {
18
+ AnvilIpPrivacySignal,
19
+ AnvilLimitedModeReason,
20
+ } from '../types/anvil-session'
21
+
22
+ const PRIVACY_SIGNAL_LABELS: Partial<Record<AnvilIpPrivacySignal, string>> = {
23
+ anonymous: 'anonymized network',
24
+ proxy: 'proxy',
25
+ relay: 'relay',
26
+ res_proxy: 'residential proxy',
27
+ tor: 'Tor',
28
+ vpn: 'VPN',
29
+ hosting: 'hosting network',
30
+ service: 'privacy service',
31
+ }
32
+
33
+ export function formatAnvilPrivacySignalList(
34
+ signals: readonly AnvilIpPrivacySignal[] | null | undefined,
35
+ ): string {
36
+ const labels = Array.from(
37
+ new Set(
38
+ signals
39
+ ?.map((signal) => PRIVACY_SIGNAL_LABELS[signal])
40
+ .filter((label): label is string => Boolean(label)) ?? [],
41
+ ),
42
+ )
43
+
44
+ if (labels.length === 0) {
45
+ return 'VPN, Tor, proxy, relay, or anonymized network'
46
+ }
47
+ if (labels.length === 1) return labels[0]
48
+ if (labels.length === 2) return `${labels[0]} or ${labels[1]}`
49
+ return `${labels.slice(0, -1).join(', ')}, or ${labels[labels.length - 1]}`
50
+ }
51
+
52
+ /** "BR" → "Brazil". Falls back to the raw code when the runtime can't
53
+ * resolve it (malformed code, missing ICU data). */
54
+ export function formatAnvilCountryName(countryCode: string): string {
55
+ try {
56
+ return (
57
+ new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode) ??
58
+ countryCode
59
+ )
60
+ } catch {
61
+ return countryCode
62
+ }
63
+ }
64
+
65
+ /**
66
+ * The one line to render next to the model list. Callers gate on the access
67
+ * tier: a full-access account has the whole catalog and needs no explanation.
68
+ *
69
+ * A missing/unknown reason still returns a line — the reduced catalog is
70
+ * visible either way, so saying nothing is the one option that leaves the
71
+ * question unanswered.
72
+ */
73
+ export function getAnvilModelAvailabilityNotice(
74
+ reason: AnvilLimitedModeReason | null | undefined,
75
+ ): string {
76
+ const generic = "Some models aren't available on this connection"
77
+ if (!reason) return generic
78
+
79
+ const countryCode =
80
+ reason.countryCode && reason.countryCode !== 'UNKNOWN'
81
+ ? reason.countryCode
82
+ : null
83
+
84
+ switch (reason.countryBlockReason) {
85
+ case 'anonymous_network':
86
+ return `Using a ${formatAnvilPrivacySignalList(
87
+ reason.ipPrivacySignals,
88
+ )}? More models are available on a direct connection`
89
+ case 'country_not_allowed':
90
+ return `Some models aren't available in ${
91
+ countryCode ? formatAnvilCountryName(countryCode) : 'your region'
92
+ } yet`
93
+ case 'anonymized_or_unknown_country':
94
+ case 'missing_client_ip':
95
+ case 'unresolved_client_ip':
96
+ return "We couldn't confirm your region, so we're showing models available everywhere"
97
+ case 'ip_privacy_lookup_failed':
98
+ return "We couldn't finish a network check, so we're showing models available everywhere"
99
+ default:
100
+ return generic
101
+ }
102
+ }