@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.
- package/package.json +6 -2
- package/src/agents/bundled-agents.generated.ts +4 -4
- package/src/chat.tsx +1703 -1698
- package/src/cli-args.ts +134 -134
- package/src/components/status-bar.tsx +331 -313
- package/src/hooks/helpers/send-message.ts +663 -654
- package/src/hooks/use-send-message.ts +806 -773
- package/src/index.tsx +473 -473
- package/src/state/chat-store.ts +553 -544
- package/src/utils/create-run-config.ts +121 -121
- package/src/utils/format-compact-number.ts +37 -0
- package/vendor/@anvil/common/package.json +27 -0
- package/vendor/@anvil/common/src/__tests__/agent-validation.test.ts +846 -0
- package/vendor/@anvil/common/src/__tests__/anvil-model-availability.test.ts +101 -0
- package/vendor/@anvil/common/src/__tests__/anvil-models.test.ts +1408 -0
- package/vendor/@anvil/common/src/__tests__/anvil-public-data-use-copy.test.ts +258 -0
- package/vendor/@anvil/common/src/__tests__/anvil-referral-tiers.test.ts +48 -0
- package/vendor/@anvil/common/src/__tests__/anvil-spend-ceilings.test.ts +282 -0
- package/vendor/@anvil/common/src/__tests__/anvil-trust.test.ts +526 -0
- package/vendor/@anvil/common/src/__tests__/deepseek-direct.test.ts +68 -0
- package/vendor/@anvil/common/src/__tests__/disposable-email.test.ts +132 -0
- package/vendor/@anvil/common/src/__tests__/dynamic-agent-template-schema.test.ts +422 -0
- package/vendor/@anvil/common/src/__tests__/env-ci.test.ts +167 -0
- package/vendor/@anvil/common/src/__tests__/env-process.test.ts +145 -0
- package/vendor/@anvil/common/src/__tests__/foreign-client-shipped-agents.test.ts +234 -0
- package/vendor/@anvil/common/src/__tests__/foreign-client-signals.test.ts +379 -0
- package/vendor/@anvil/common/src/__tests__/free-agents.test.ts +807 -0
- package/vendor/@anvil/common/src/__tests__/gravity-capi.test.ts +154 -0
- package/vendor/@anvil/common/src/__tests__/handlesteps-parsing.test.ts +246 -0
- package/vendor/@anvil/common/src/__tests__/kimi-k3-god-only.test.ts +77 -0
- package/vendor/@anvil/common/src/__tests__/model-config.test.ts +89 -0
- package/vendor/@anvil/common/src/__tests__/project-file-tree.test.ts +298 -0
- package/vendor/@anvil/common/src/__tests__/provisioned-model-tiers.test.ts +116 -0
- package/vendor/@anvil/common/src/__tests__/reasoning-effort.test.ts +167 -0
- package/vendor/@anvil/common/src/__tests__/reddit-capi.test.ts +132 -0
- package/vendor/@anvil/common/src/__tests__/response-ad-positions.test.ts +72 -0
- package/vendor/@anvil/common/src/__tests__/user-state.test.ts +30 -0
- package/vendor/@anvil/common/src/actions.ts +215 -0
- package/vendor/@anvil/common/src/analytics-core.ts +69 -0
- package/vendor/@anvil/common/src/analytics.ts +93 -0
- package/vendor/@anvil/common/src/api-keys/constants.ts +26 -0
- package/vendor/@anvil/common/src/browser-actions.ts +413 -0
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding-gate.test.ts +63 -0
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding.test.ts +246 -0
- package/vendor/@anvil/common/src/constants/__tests__/cf-worker-signals.test.ts +106 -0
- package/vendor/@anvil/common/src/constants/agents.ts +99 -0
- package/vendor/@anvil/common/src/constants/analytics-events.ts +435 -0
- package/vendor/@anvil/common/src/constants/anthropic.ts +73 -0
- package/vendor/@anvil/common/src/constants/anvil-data-use.ts +81 -0
- package/vendor/@anvil/common/src/constants/anvil-errors.ts +7 -0
- package/vendor/@anvil/common/src/constants/anvil-gemini-thinker.ts +21 -0
- package/vendor/@anvil/common/src/constants/anvil-model-ids.ts +11 -0
- package/vendor/@anvil/common/src/constants/anvil-models.ts +2130 -0
- package/vendor/@anvil/common/src/constants/anvil-onboarding-gate.ts +55 -0
- package/vendor/@anvil/common/src/constants/anvil-onboarding.ts +307 -0
- package/vendor/@anvil/common/src/constants/anvil-referral-tiers.ts +87 -0
- package/vendor/@anvil/common/src/constants/anvil-signup-block.ts +68 -0
- package/vendor/@anvil/common/src/constants/anvil-spend-ceilings.ts +450 -0
- package/vendor/@anvil/common/src/constants/anvil-trust.ts +976 -0
- package/vendor/@anvil/common/src/constants/auth.ts +18 -0
- package/vendor/@anvil/common/src/constants/byok.ts +2 -0
- package/vendor/@anvil/common/src/constants/cf-worker-signals.ts +132 -0
- package/vendor/@anvil/common/src/constants/composio.ts +34 -0
- package/vendor/@anvil/common/src/constants/deepseek-direct.ts +55 -0
- package/vendor/@anvil/common/src/constants/feedback.ts +13 -0
- package/vendor/@anvil/common/src/constants/foreign-client-signals.ts +272 -0
- package/vendor/@anvil/common/src/constants/free-agents.ts +777 -0
- package/vendor/@anvil/common/src/constants/gemini.ts +15 -0
- package/vendor/@anvil/common/src/constants/grant-priorities.ts +13 -0
- package/vendor/@anvil/common/src/constants/hosts.ts +6 -0
- package/vendor/@anvil/common/src/constants/images.ts +51 -0
- package/vendor/@anvil/common/src/constants/index.ts +7 -0
- package/vendor/@anvil/common/src/constants/knowledge.ts +35 -0
- package/vendor/@anvil/common/src/constants/limits.ts +23 -0
- package/vendor/@anvil/common/src/constants/model-config.ts +277 -0
- package/vendor/@anvil/common/src/constants/openrouter-attribution.ts +8 -0
- package/vendor/@anvil/common/src/constants/paths.ts +69 -0
- package/vendor/@anvil/common/src/constants/provider-routes.ts +317 -0
- package/vendor/@anvil/common/src/constants/reasoning-effort.ts +79 -0
- package/vendor/@anvil/common/src/constants/skills.ts +60 -0
- package/vendor/@anvil/common/src/constants/subscription-plans.ts +49 -0
- package/vendor/@anvil/common/src/constants/ui.ts +25 -0
- package/vendor/@anvil/common/src/env-ci.ts +36 -0
- package/vendor/@anvil/common/src/env-process.ts +95 -0
- package/vendor/@anvil/common/src/env-schema.ts +95 -0
- package/vendor/@anvil/common/src/env.ts +24 -0
- package/vendor/@anvil/common/src/gravity-capi.ts +207 -0
- package/vendor/@anvil/common/src/mcp/client.ts +233 -0
- package/vendor/@anvil/common/src/old-constants.ts +10 -0
- package/vendor/@anvil/common/src/project-file-tree.ts +355 -0
- package/vendor/@anvil/common/src/reddit-capi.ts +254 -0
- package/vendor/@anvil/common/src/schemas/feedback.ts +52 -0
- package/vendor/@anvil/common/src/schemas/logs.ts +66 -0
- package/vendor/@anvil/common/src/templates/agent-validation.ts +392 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/LICENSE +202 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/README.md +294 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/01-basic-diff-reviewer.ts +17 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/02-intermediate-git-committer.ts +78 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/03-advanced-file-explorer.ts +73 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/my-custom-agent.ts +40 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/package.json +6 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/README.md +65 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/example-skill/SKILL.md +29 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/agent-definition.ts +497 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/tools.ts +444 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/util-types.ts +178 -0
- package/vendor/@anvil/common/src/testing/TESTING_PATTERNS.md +351 -0
- package/vendor/@anvil/common/src/testing/anvil-offer-invariants.ts +169 -0
- package/vendor/@anvil/common/src/testing/errors.ts +33 -0
- package/vendor/@anvil/common/src/testing/fixtures/agent-runtime.ts +334 -0
- package/vendor/@anvil/common/src/testing/impl/agent-runtime.ts +6 -0
- package/vendor/@anvil/common/src/testing/index.ts +84 -0
- package/vendor/@anvil/common/src/testing/mock-modules.ts +53 -0
- package/vendor/@anvil/common/src/testing/mock-types.ts +123 -0
- package/vendor/@anvil/common/src/testing/mocks/analytics.ts +261 -0
- package/vendor/@anvil/common/src/testing/mocks/child-process.ts +93 -0
- package/vendor/@anvil/common/src/testing/mocks/crypto.ts +218 -0
- package/vendor/@anvil/common/src/testing/mocks/database.ts +337 -0
- package/vendor/@anvil/common/src/testing/mocks/fetch.ts +219 -0
- package/vendor/@anvil/common/src/testing/mocks/filesystem.ts +166 -0
- package/vendor/@anvil/common/src/testing/mocks/index.ts +101 -0
- package/vendor/@anvil/common/src/testing/mocks/logger.ts +135 -0
- package/vendor/@anvil/common/src/testing/mocks/stream.ts +313 -0
- package/vendor/@anvil/common/src/testing/mocks/timers.ts +132 -0
- package/vendor/@anvil/common/src/testing/mocks/tree-sitter.ts +127 -0
- package/vendor/@anvil/common/src/testing/setup.ts +282 -0
- package/vendor/@anvil/common/src/testing-env-ci.ts +15 -0
- package/vendor/@anvil/common/src/testing-env-process.ts +78 -0
- package/vendor/@anvil/common/src/tools/__tests__/compile-tool-definitions.test.ts +34 -0
- package/vendor/@anvil/common/src/tools/compile-tool-definitions.ts +157 -0
- package/vendor/@anvil/common/src/tools/constants.ts +117 -0
- package/vendor/@anvil/common/src/tools/list.ts +190 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/coerce-to-array.test.ts +213 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/read-docs.test.ts +47 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/render-ui.test.ts +65 -0
- package/vendor/@anvil/common/src/tools/params/tool/__tests__/run-terminal-command-timeout.test.ts +49 -0
- package/vendor/@anvil/common/src/tools/params/tool/add-message.ts +39 -0
- package/vendor/@anvil/common/src/tools/params/tool/add-subgoal.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/apply-patch.ts +110 -0
- package/vendor/@anvil/common/src/tools/params/tool/ask-user.ts +181 -0
- package/vendor/@anvil/common/src/tools/params/tool/browser-logs.ts +85 -0
- package/vendor/@anvil/common/src/tools/params/tool/cloud-plan-ready.ts +94 -0
- package/vendor/@anvil/common/src/tools/params/tool/code-search.ts +159 -0
- package/vendor/@anvil/common/src/tools/params/tool/composio.ts +131 -0
- package/vendor/@anvil/common/src/tools/params/tool/create-plan.ts +80 -0
- package/vendor/@anvil/common/src/tools/params/tool/end-turn.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/find-files.ts +60 -0
- package/vendor/@anvil/common/src/tools/params/tool/glob.ts +80 -0
- package/vendor/@anvil/common/src/tools/params/tool/gravity-index.ts +93 -0
- package/vendor/@anvil/common/src/tools/params/tool/list-directory.ts +58 -0
- package/vendor/@anvil/common/src/tools/params/tool/lookup-agent-info.ts +37 -0
- package/vendor/@anvil/common/src/tools/params/tool/propose-str-replace.ts +103 -0
- package/vendor/@anvil/common/src/tools/params/tool/propose-write-file.ts +71 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-docs.ts +90 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-files.ts +109 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-subtree.ts +79 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-url.ts +81 -0
- package/vendor/@anvil/common/src/tools/params/tool/render-ui.ts +168 -0
- package/vendor/@anvil/common/src/tools/params/tool/run-file-change-hooks.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/run-terminal-command.ts +211 -0
- package/vendor/@anvil/common/src/tools/params/tool/screenshot.ts +97 -0
- package/vendor/@anvil/common/src/tools/params/tool/set-messages.ts +44 -0
- package/vendor/@anvil/common/src/tools/params/tool/set-output.ts +61 -0
- package/vendor/@anvil/common/src/tools/params/tool/skill.ts +59 -0
- package/vendor/@anvil/common/src/tools/params/tool/spawn-agent-inline.ts +56 -0
- package/vendor/@anvil/common/src/tools/params/tool/spawn-agents.ts +154 -0
- package/vendor/@anvil/common/src/tools/params/tool/str-replace.ts +107 -0
- package/vendor/@anvil/common/src/tools/params/tool/suggest-followups.ts +97 -0
- package/vendor/@anvil/common/src/tools/params/tool/task-completed.ts +61 -0
- package/vendor/@anvil/common/src/tools/params/tool/think-deeply.ts +56 -0
- package/vendor/@anvil/common/src/tools/params/tool/update-subgoal.ts +89 -0
- package/vendor/@anvil/common/src/tools/params/tool/vision-analyze.ts +82 -0
- package/vendor/@anvil/common/src/tools/params/tool/web-search.ts +73 -0
- package/vendor/@anvil/common/src/tools/params/tool/write-file.ts +71 -0
- package/vendor/@anvil/common/src/tools/params/tool/write-todos.ts +67 -0
- package/vendor/@anvil/common/src/tools/params/utils.ts +150 -0
- package/vendor/@anvil/common/src/tools/utils.ts +24 -0
- package/vendor/@anvil/common/src/types/__tests__/dynamic-agent-template.test.ts +20 -0
- package/vendor/@anvil/common/src/types/agent-template.ts +215 -0
- package/vendor/@anvil/common/src/types/anvil-session.ts +535 -0
- package/vendor/@anvil/common/src/types/anvil-streak.ts +6 -0
- package/vendor/@anvil/common/src/types/anvil-usage.ts +64 -0
- package/vendor/@anvil/common/src/types/api/agents/publish.ts +61 -0
- package/vendor/@anvil/common/src/types/bun-test.d.ts +5 -0
- package/vendor/@anvil/common/src/types/contracts/agent-runtime.ts +75 -0
- package/vendor/@anvil/common/src/types/contracts/analytics.ts +9 -0
- package/vendor/@anvil/common/src/types/contracts/bigquery.ts +55 -0
- package/vendor/@anvil/common/src/types/contracts/billing.ts +46 -0
- package/vendor/@anvil/common/src/types/contracts/client.ts +53 -0
- package/vendor/@anvil/common/src/types/contracts/database.ts +112 -0
- package/vendor/@anvil/common/src/types/contracts/env.ts +203 -0
- package/vendor/@anvil/common/src/types/contracts/llm.ts +191 -0
- package/vendor/@anvil/common/src/types/contracts/logger.ts +14 -0
- package/vendor/@anvil/common/src/types/contracts/logs.ts +34 -0
- package/vendor/@anvil/common/src/types/contracts/trace.ts +21 -0
- package/vendor/@anvil/common/src/types/dynamic-agent-template.ts +328 -0
- package/vendor/@anvil/common/src/types/filesystem.ts +10 -0
- package/vendor/@anvil/common/src/types/function-params.ts +33 -0
- package/vendor/@anvil/common/src/types/grant.ts +20 -0
- package/vendor/@anvil/common/src/types/gravity-index.ts +170 -0
- package/vendor/@anvil/common/src/types/json.ts +29 -0
- package/vendor/@anvil/common/src/types/mcp.ts +24 -0
- package/vendor/@anvil/common/src/types/messages/anvil-message.ts +58 -0
- package/vendor/@anvil/common/src/types/messages/content-part.ts +59 -0
- package/vendor/@anvil/common/src/types/messages/data-content.ts +14 -0
- package/vendor/@anvil/common/src/types/messages/provider-metadata.ts +13 -0
- package/vendor/@anvil/common/src/types/organization.ts +118 -0
- package/vendor/@anvil/common/src/types/print-mode.ts +121 -0
- package/vendor/@anvil/common/src/types/publisher.ts +67 -0
- package/vendor/@anvil/common/src/types/session-state.ts +149 -0
- package/vendor/@anvil/common/src/types/skill.ts +86 -0
- package/vendor/@anvil/common/src/types/source.ts +11 -0
- package/vendor/@anvil/common/src/types/spawn.ts +13 -0
- package/vendor/@anvil/common/src/types/subscription.ts +67 -0
- package/vendor/@anvil/common/src/types/usage.ts +16 -0
- package/vendor/@anvil/common/src/types/util.ts +3 -0
- package/vendor/@anvil/common/src/util/__tests__/ad-user-agent.test.ts +26 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-dispatcher.test.ts +122 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-log.test.ts +102 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-sampling.test.ts +143 -0
- package/vendor/@anvil/common/src/util/__tests__/anvil-streak.test.ts +202 -0
- package/vendor/@anvil/common/src/util/__tests__/anvil-usage-summary.test.ts +193 -0
- package/vendor/@anvil/common/src/util/__tests__/axiom-only-log.test.ts +140 -0
- package/vendor/@anvil/common/src/util/__tests__/client-user-agent.test.ts +148 -0
- package/vendor/@anvil/common/src/util/__tests__/engagement-tracker.test.ts +115 -0
- package/vendor/@anvil/common/src/util/__tests__/env-file-path.test.ts +57 -0
- package/vendor/@anvil/common/src/util/__tests__/error-abort.test.ts +774 -0
- package/vendor/@anvil/common/src/util/__tests__/error-api-details.test.ts +206 -0
- package/vendor/@anvil/common/src/util/__tests__/file-read-limits.test.ts +173 -0
- package/vendor/@anvil/common/src/util/__tests__/format-code-search.test.ts +60 -0
- package/vendor/@anvil/common/src/util/__tests__/log-mirror.test.ts +31 -0
- package/vendor/@anvil/common/src/util/__tests__/messages.test.ts +1252 -0
- package/vendor/@anvil/common/src/util/__tests__/partial-json-delta.test.ts +505 -0
- package/vendor/@anvil/common/src/util/__tests__/path.test.ts +22 -0
- package/vendor/@anvil/common/src/util/__tests__/project-ignore.test.ts +90 -0
- package/vendor/@anvil/common/src/util/__tests__/promise.test.ts +325 -0
- package/vendor/@anvil/common/src/util/__tests__/rate-limit.test.ts +28 -0
- package/vendor/@anvil/common/src/util/__tests__/reddit-anvil-retention.test.ts +130 -0
- package/vendor/@anvil/common/src/util/__tests__/saxy.test.ts +1008 -0
- package/vendor/@anvil/common/src/util/__tests__/split-data.test.ts +289 -0
- package/vendor/@anvil/common/src/util/__tests__/string.test.ts +239 -0
- package/vendor/@anvil/common/src/util/__tests__/thread-title.test.ts +70 -0
- package/vendor/@anvil/common/src/util/__tests__/tool-result-media-order.test.ts +108 -0
- package/vendor/@anvil/common/src/util/__tests__/ttft-histogram.test.ts +180 -0
- package/vendor/@anvil/common/src/util/__tests__/with-timeout.test.ts +24 -0
- package/vendor/@anvil/common/src/util/__tests__/zoned-time.test.ts +88 -0
- package/vendor/@anvil/common/src/util/ad-user-agent.ts +25 -0
- package/vendor/@anvil/common/src/util/agent-file-utils.ts +110 -0
- package/vendor/@anvil/common/src/util/agent-id-parsing.ts +136 -0
- package/vendor/@anvil/common/src/util/agent-name-normalization.ts +38 -0
- package/vendor/@anvil/common/src/util/agent-name-resolver.ts +86 -0
- package/vendor/@anvil/common/src/util/analytics-dispatcher.ts +82 -0
- package/vendor/@anvil/common/src/util/analytics-log.ts +78 -0
- package/vendor/@anvil/common/src/util/analytics-sampling.ts +255 -0
- package/vendor/@anvil/common/src/util/anvil-model-availability.ts +102 -0
- package/vendor/@anvil/common/src/util/anvil-privacy.ts +82 -0
- package/vendor/@anvil/common/src/util/anvil-streak-line.ts +103 -0
- package/vendor/@anvil/common/src/util/anvil-streak.ts +156 -0
- package/vendor/@anvil/common/src/util/anvil-usage-summary.ts +125 -0
- package/vendor/@anvil/common/src/util/array.ts +31 -0
- package/vendor/@anvil/common/src/util/axiom-only-log.ts +124 -0
- package/vendor/@anvil/common/src/util/cache-debug.ts +171 -0
- package/vendor/@anvil/common/src/util/client-user-agent.ts +114 -0
- package/vendor/@anvil/common/src/util/credentials.ts +26 -0
- package/vendor/@anvil/common/src/util/currency.ts +25 -0
- package/vendor/@anvil/common/src/util/dates.ts +81 -0
- package/vendor/@anvil/common/src/util/disposable-email.ts +277 -0
- package/vendor/@anvil/common/src/util/engagement-tracker.ts +129 -0
- package/vendor/@anvil/common/src/util/env-file-path.ts +40 -0
- package/vendor/@anvil/common/src/util/error.ts +562 -0
- package/vendor/@anvil/common/src/util/file-read-limits.ts +236 -0
- package/vendor/@anvil/common/src/util/file.ts +339 -0
- package/vendor/@anvil/common/src/util/format-code-search.ts +115 -0
- package/vendor/@anvil/common/src/util/lazy-response-ads.ts +92 -0
- package/vendor/@anvil/common/src/util/log-data.ts +57 -0
- package/vendor/@anvil/common/src/util/log-ingest.ts +58 -0
- package/vendor/@anvil/common/src/util/log-mirror.ts +34 -0
- package/vendor/@anvil/common/src/util/lru-cache.ts +67 -0
- package/vendor/@anvil/common/src/util/messages.ts +685 -0
- package/vendor/@anvil/common/src/util/min-heap.ts +87 -0
- package/vendor/@anvil/common/src/util/model-utils.ts +4 -0
- package/vendor/@anvil/common/src/util/object.ts +128 -0
- package/vendor/@anvil/common/src/util/partial-json-delta.ts +89 -0
- package/vendor/@anvil/common/src/util/path.ts +15 -0
- package/vendor/@anvil/common/src/util/project-ignore.ts +119 -0
- package/vendor/@anvil/common/src/util/promise.ts +73 -0
- package/vendor/@anvil/common/src/util/random.ts +15 -0
- package/vendor/@anvil/common/src/util/rate-limit.ts +56 -0
- package/vendor/@anvil/common/src/util/reddit-anvil-retention.ts +60 -0
- package/vendor/@anvil/common/src/util/reddit-capi-events.ts +36 -0
- package/vendor/@anvil/common/src/util/response-ad-positions.ts +54 -0
- package/vendor/@anvil/common/src/util/saxy.ts +741 -0
- package/vendor/@anvil/common/src/util/skills.test.ts +44 -0
- package/vendor/@anvil/common/src/util/skills.ts +36 -0
- package/vendor/@anvil/common/src/util/split-data.ts +259 -0
- package/vendor/@anvil/common/src/util/stop-sequence.ts +61 -0
- package/vendor/@anvil/common/src/util/string.ts +426 -0
- package/vendor/@anvil/common/src/util/system-info.ts +53 -0
- package/vendor/@anvil/common/src/util/thread-title.ts +46 -0
- package/vendor/@anvil/common/src/util/ttft-histogram.ts +73 -0
- package/vendor/@anvil/common/src/util/xml-parser.ts +27 -0
- package/vendor/@anvil/common/src/util/xml.ts +17 -0
- package/vendor/@anvil/common/src/util/zod-schema.ts +25 -0
- package/vendor/@anvil/common/src/util/zoned-time.ts +136 -0
- package/vendor/@anvil/common/src/utils/ask-user-bridge.ts +44 -0
- package/vendor/@anvil/sdk/dist/index.cjs +52297 -0
- package/vendor/@anvil/sdk/dist/index.cjs.map +440 -0
- package/vendor/@anvil/sdk/dist/index.d.ts +4277 -0
- package/vendor/@anvil/sdk/dist/index.mjs +52290 -0
- package/vendor/@anvil/sdk/dist/index.mjs.map +440 -0
- package/vendor/@anvil/sdk/dist/vendor/ai.cjs +30886 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-linux/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-darwin/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-linux/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-c-sharp.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-cpp.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-go.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-java.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-python.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-ruby.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-rust.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter.wasm +0 -0
- package/vendor/@anvil/sdk/package.json +21 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
import { MAX_AGENT_STEPS_DEFAULT } from '../constants/agents'
|
|
4
|
+
|
|
5
|
+
import type { Message } from './messages/anvil-message'
|
|
6
|
+
import type { ProjectFileContext } from '../util/file'
|
|
7
|
+
|
|
8
|
+
export const toolCallSchema = z.object({
|
|
9
|
+
toolName: z.string(),
|
|
10
|
+
toolCallId: z.string(),
|
|
11
|
+
input: z.record(z.string(), z.any()),
|
|
12
|
+
})
|
|
13
|
+
export type ToolCall = z.infer<typeof toolCallSchema>
|
|
14
|
+
|
|
15
|
+
export const subgoalSchema = z.object({
|
|
16
|
+
objective: z.string().optional(),
|
|
17
|
+
status: z
|
|
18
|
+
.enum(['NOT_STARTED', 'IN_PROGRESS', 'COMPLETE', 'ABORTED'])
|
|
19
|
+
.optional(),
|
|
20
|
+
plan: z.string().optional(),
|
|
21
|
+
logs: z.string().array(),
|
|
22
|
+
})
|
|
23
|
+
export type Subgoal = z.infer<typeof subgoalSchema>
|
|
24
|
+
|
|
25
|
+
export type AgentState = {
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated agentId is replaced by runId
|
|
28
|
+
*/
|
|
29
|
+
agentId: string
|
|
30
|
+
agentType: AgentTemplateType | null
|
|
31
|
+
agentContext: Record<string, Subgoal>
|
|
32
|
+
ancestorRunIds: string[]
|
|
33
|
+
runId?: string
|
|
34
|
+
subagents: AgentState[]
|
|
35
|
+
childRunIds: string[]
|
|
36
|
+
messageHistory: Message[]
|
|
37
|
+
stepsRemaining: number
|
|
38
|
+
creditsUsed: number
|
|
39
|
+
directCreditsUsed: number
|
|
40
|
+
output?: Record<string, any>
|
|
41
|
+
parentId?: string
|
|
42
|
+
systemPrompt: string
|
|
43
|
+
toolDefinitions: Record<
|
|
44
|
+
string,
|
|
45
|
+
{ description: string | undefined; inputSchema: {} }
|
|
46
|
+
>
|
|
47
|
+
/**
|
|
48
|
+
* The accurate token count from the Anthropic API.
|
|
49
|
+
* This is updated on every agent step via the /api/v1/token-count endpoint.
|
|
50
|
+
*/
|
|
51
|
+
contextTokenCount: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const AgentOutputSchema = z.discriminatedUnion('type', [
|
|
55
|
+
z.object({
|
|
56
|
+
type: z.literal('structuredOutput'),
|
|
57
|
+
value: z.record(z.string(), z.any()).or(z.null()),
|
|
58
|
+
}),
|
|
59
|
+
z.object({
|
|
60
|
+
type: z.literal('lastMessage'),
|
|
61
|
+
value: z.array(z.any()), // Array of assistant and tool messages from the last turn, including tool results
|
|
62
|
+
}),
|
|
63
|
+
z.object({
|
|
64
|
+
type: z.literal('allMessages'),
|
|
65
|
+
value: z.array(z.any()),
|
|
66
|
+
}),
|
|
67
|
+
z.object({
|
|
68
|
+
type: z.literal('error'),
|
|
69
|
+
message: z.string(),
|
|
70
|
+
statusCode: z.number().optional(),
|
|
71
|
+
error: z.string().optional(),
|
|
72
|
+
countryCode: z.string().optional(),
|
|
73
|
+
countryBlockReason: z.string().optional(),
|
|
74
|
+
ipPrivacySignals: z.array(z.string()).optional(),
|
|
75
|
+
}),
|
|
76
|
+
])
|
|
77
|
+
export type AgentOutput = z.infer<typeof AgentOutputSchema>
|
|
78
|
+
|
|
79
|
+
export const AgentTemplateTypeList = [
|
|
80
|
+
// Base agents
|
|
81
|
+
'base',
|
|
82
|
+
'base_free',
|
|
83
|
+
'base_max',
|
|
84
|
+
'base_experimental',
|
|
85
|
+
'claude4_gemini_thinking',
|
|
86
|
+
'superagent',
|
|
87
|
+
'base_agent_builder',
|
|
88
|
+
|
|
89
|
+
// Ask mode
|
|
90
|
+
'ask',
|
|
91
|
+
|
|
92
|
+
// Planning / Thinking
|
|
93
|
+
'planner',
|
|
94
|
+
'dry_run',
|
|
95
|
+
'thinker',
|
|
96
|
+
|
|
97
|
+
// Other agents
|
|
98
|
+
'file_picker',
|
|
99
|
+
'file_explorer',
|
|
100
|
+
'researcher',
|
|
101
|
+
'reviewer',
|
|
102
|
+
'agent_builder',
|
|
103
|
+
'example_programmatic',
|
|
104
|
+
] as const
|
|
105
|
+
type UnderscoreToDash<S extends string> = S extends `${infer L}_${infer R}`
|
|
106
|
+
? `${L}-${UnderscoreToDash<R>}` // recurse on the remainder
|
|
107
|
+
: S
|
|
108
|
+
export const AgentTemplateTypes = Object.fromEntries(
|
|
109
|
+
AgentTemplateTypeList.map((name) => [name, name.replaceAll('_', '-')]),
|
|
110
|
+
) as { [K in (typeof AgentTemplateTypeList)[number]]: UnderscoreToDash<K> }
|
|
111
|
+
const agentTemplateTypeSchema = z.enum(AgentTemplateTypeList)
|
|
112
|
+
// Allow dynamic agent types by extending the base enum with string
|
|
113
|
+
export type AgentTemplateType =
|
|
114
|
+
| z.infer<typeof agentTemplateTypeSchema>
|
|
115
|
+
| (string & {})
|
|
116
|
+
|
|
117
|
+
export type SessionState = {
|
|
118
|
+
fileContext: ProjectFileContext
|
|
119
|
+
mainAgentState: AgentState
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function getInitialAgentState(): AgentState {
|
|
123
|
+
return {
|
|
124
|
+
agentId: 'main-agent',
|
|
125
|
+
agentType: null,
|
|
126
|
+
agentContext: {},
|
|
127
|
+
ancestorRunIds: [],
|
|
128
|
+
runId: undefined,
|
|
129
|
+
subagents: [],
|
|
130
|
+
childRunIds: [],
|
|
131
|
+
messageHistory: [],
|
|
132
|
+
stepsRemaining: MAX_AGENT_STEPS_DEFAULT,
|
|
133
|
+
creditsUsed: 0,
|
|
134
|
+
directCreditsUsed: 0,
|
|
135
|
+
output: undefined,
|
|
136
|
+
parentId: undefined,
|
|
137
|
+
systemPrompt: '',
|
|
138
|
+
toolDefinitions: {},
|
|
139
|
+
contextTokenCount: 0,
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export function getInitialSessionState(
|
|
143
|
+
fileContext: ProjectFileContext,
|
|
144
|
+
): SessionState {
|
|
145
|
+
return {
|
|
146
|
+
mainAgentState: getInitialAgentState(),
|
|
147
|
+
fileContext,
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SKILL_NAME_MAX_LENGTH,
|
|
5
|
+
SKILL_NAME_REGEX,
|
|
6
|
+
SKILL_DESCRIPTION_MAX_LENGTH,
|
|
7
|
+
} from '../constants/skills'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Zod schema for skill frontmatter metadata.
|
|
11
|
+
*
|
|
12
|
+
* Values are unconstrained on purpose: `metadata` is a free-form bag that
|
|
13
|
+
* publishers and registries nest their own structures into (skills.sh writes a
|
|
14
|
+
* `hermes:` block into every skill it serves). Requiring flat strings here
|
|
15
|
+
* rejected the whole skill over a field nothing reads.
|
|
16
|
+
*/
|
|
17
|
+
export const SkillMetadataSchema = z.record(z.string(), z.unknown())
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Zod schema for skill frontmatter (parsed from YAML).
|
|
21
|
+
*/
|
|
22
|
+
export const SkillFrontmatterSchema = z.object({
|
|
23
|
+
name: z
|
|
24
|
+
.string()
|
|
25
|
+
.min(1)
|
|
26
|
+
.max(SKILL_NAME_MAX_LENGTH)
|
|
27
|
+
.regex(
|
|
28
|
+
SKILL_NAME_REGEX,
|
|
29
|
+
'Name must be lowercase alphanumeric with single hyphen separators',
|
|
30
|
+
),
|
|
31
|
+
// clamped rather than rejected: an over-long description is a reason to show
|
|
32
|
+
// less of it, never a reason to make the skill unusable
|
|
33
|
+
description: z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1)
|
|
36
|
+
.transform((d) => d.slice(0, SKILL_DESCRIPTION_MAX_LENGTH)),
|
|
37
|
+
license: z.string().optional(),
|
|
38
|
+
'disable-model-invocation': z.boolean().optional(),
|
|
39
|
+
metadata: SkillMetadataSchema.optional(),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export type SkillFrontmatter = z.infer<typeof SkillFrontmatterSchema>
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Full skill definition including content and source path.
|
|
46
|
+
*/
|
|
47
|
+
export const SkillDefinitionSchema = z.object({
|
|
48
|
+
/** Skill name (must match directory name) */
|
|
49
|
+
name: z.string(),
|
|
50
|
+
/** Short description for agent discovery */
|
|
51
|
+
description: z.string(),
|
|
52
|
+
/** Optional license */
|
|
53
|
+
license: z.string().optional(),
|
|
54
|
+
/** Whether only the user may invoke this skill. */
|
|
55
|
+
disableModelInvocation: z.boolean().optional(),
|
|
56
|
+
/** Optional key-value metadata */
|
|
57
|
+
metadata: SkillMetadataSchema.optional(),
|
|
58
|
+
/** Full SKILL.md content (including frontmatter) */
|
|
59
|
+
content: z.string(),
|
|
60
|
+
/** Source file path */
|
|
61
|
+
filePath: z.string(),
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
export type SkillDefinition = z.infer<typeof SkillDefinitionSchema>
|
|
65
|
+
|
|
66
|
+
export function createSkillDefinition(params: {
|
|
67
|
+
frontmatter: SkillFrontmatter
|
|
68
|
+
content: string
|
|
69
|
+
filePath: string
|
|
70
|
+
}): SkillDefinition {
|
|
71
|
+
const { frontmatter, content, filePath } = params
|
|
72
|
+
return {
|
|
73
|
+
name: frontmatter.name,
|
|
74
|
+
description: frontmatter.description,
|
|
75
|
+
license: frontmatter.license,
|
|
76
|
+
disableModelInvocation: frontmatter['disable-model-invocation'],
|
|
77
|
+
metadata: frontmatter.metadata,
|
|
78
|
+
content,
|
|
79
|
+
filePath,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Collection of skills keyed by skill name.
|
|
85
|
+
*/
|
|
86
|
+
export type SkillsMap = Record<string, SkillDefinition>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a source of data.
|
|
3
|
+
*
|
|
4
|
+
* By default, can be a value or a promise.
|
|
5
|
+
*
|
|
6
|
+
* In the case that the type is a not function itself, this can also be a function that returns the value or promise.
|
|
7
|
+
*/
|
|
8
|
+
export type Source<T> =
|
|
9
|
+
| T
|
|
10
|
+
| Promise<T>
|
|
11
|
+
| (T extends (...args: unknown[]) => unknown ? never : () => T | Promise<T>)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChildProcess, SpawnOptions } from 'child_process'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Spawn function for running shell commands.
|
|
5
|
+
*
|
|
6
|
+
* Compatible with `child_process.spawn` from Node.js.
|
|
7
|
+
* Returns ChildProcess to support full streaming capabilities (stdin, stdout, stderr).
|
|
8
|
+
*/
|
|
9
|
+
export type AnvilSpawn = (
|
|
10
|
+
command: string,
|
|
11
|
+
args?: readonly string[],
|
|
12
|
+
options?: SpawnOptions,
|
|
13
|
+
) => ChildProcess
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core subscription information for an active subscription.
|
|
3
|
+
*/
|
|
4
|
+
export interface SubscriptionInfo {
|
|
5
|
+
id: string
|
|
6
|
+
status: string
|
|
7
|
+
billingPeriodEnd: string
|
|
8
|
+
cancelAtPeriodEnd: boolean
|
|
9
|
+
canceledAt: string | null
|
|
10
|
+
tier: number
|
|
11
|
+
scheduledTier?: number | null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Rate limit information for subscription usage.
|
|
16
|
+
*/
|
|
17
|
+
export interface SubscriptionRateLimit {
|
|
18
|
+
limited: boolean
|
|
19
|
+
reason?: 'block_exhausted' | 'weekly_limit'
|
|
20
|
+
canStartNewBlock: boolean
|
|
21
|
+
blockUsed?: number
|
|
22
|
+
blockLimit?: number
|
|
23
|
+
blockResetsAt?: string
|
|
24
|
+
weeklyUsed: number
|
|
25
|
+
weeklyLimit: number
|
|
26
|
+
weeklyResetsAt: string
|
|
27
|
+
weeklyPercentUsed: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Subscription limits configuration.
|
|
32
|
+
*/
|
|
33
|
+
export interface SubscriptionLimits {
|
|
34
|
+
creditsPerBlock: number
|
|
35
|
+
blockDurationHours: number
|
|
36
|
+
weeklyCreditsLimit: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Response when user has no active subscription.
|
|
41
|
+
*/
|
|
42
|
+
export interface NoSubscriptionResponse {
|
|
43
|
+
hasSubscription: false
|
|
44
|
+
/** Whether user prefers to fallback to a-la-carte credits when subscription limits are reached */
|
|
45
|
+
fallbackToALaCarte: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Response when user has an active subscription.
|
|
50
|
+
* All fields are required - no invalid states possible.
|
|
51
|
+
*/
|
|
52
|
+
export interface ActiveSubscriptionResponse {
|
|
53
|
+
hasSubscription: true
|
|
54
|
+
displayName: string
|
|
55
|
+
subscription: SubscriptionInfo
|
|
56
|
+
rateLimit: SubscriptionRateLimit
|
|
57
|
+
limits: SubscriptionLimits
|
|
58
|
+
|
|
59
|
+
/** Whether user prefers to fallback to a-la-carte credits when subscription limits are reached */
|
|
60
|
+
fallbackToALaCarte: boolean
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Discriminated union for subscription API response.
|
|
65
|
+
* Use `hasSubscription` to narrow the type.
|
|
66
|
+
*/
|
|
67
|
+
export type SubscriptionResponse = NoSubscriptionResponse | ActiveSubscriptionResponse
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
import { GrantTypeValues } from './grant'
|
|
4
|
+
|
|
5
|
+
export const usageDataSchema = z.object({
|
|
6
|
+
usageThisCycle: z.number(),
|
|
7
|
+
balance: z.object({
|
|
8
|
+
totalRemaining: z.number(),
|
|
9
|
+
totalDebt: z.number(),
|
|
10
|
+
netBalance: z.number(),
|
|
11
|
+
breakdown: z.record(z.enum(GrantTypeValues), z.number()),
|
|
12
|
+
}),
|
|
13
|
+
nextQuotaReset: z.coerce.date().nullable(),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type UsageData = z.infer<typeof usageDataSchema>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { getAdUserAgent } from '../ad-user-agent'
|
|
4
|
+
|
|
5
|
+
describe('getAdUserAgent', () => {
|
|
6
|
+
test.each([
|
|
7
|
+
['darwin', 'Macintosh; Intel Mac OS X'],
|
|
8
|
+
['win32', 'Windows NT 10.0'],
|
|
9
|
+
['linux', 'X11; Linux x86_64'],
|
|
10
|
+
])('returns a browser-like UA for %s', (platform, osFragment) => {
|
|
11
|
+
const userAgent = getAdUserAgent(platform)
|
|
12
|
+
|
|
13
|
+
expect(userAgent).toContain(osFragment)
|
|
14
|
+
expect(userAgent).toContain('Chrome/')
|
|
15
|
+
expect(userAgent).not.toStartWith('Bun/')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('falls back to Linux for an unknown platform', () => {
|
|
19
|
+
expect(getAdUserAgent('other')).toBe(getAdUserAgent('linux'))
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('accepts the device OS names used by the ads API', () => {
|
|
23
|
+
expect(getAdUserAgent('macos')).toBe(getAdUserAgent('darwin'))
|
|
24
|
+
expect(getAdUserAgent('windows')).toBe(getAdUserAgent('win32'))
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { AnalyticsEvent } from '@anvil/common/constants/analytics-events'
|
|
4
|
+
|
|
5
|
+
import { createAnalyticsDispatcher } from '../analytics-dispatcher'
|
|
6
|
+
|
|
7
|
+
describe('analytics dispatcher', () => {
|
|
8
|
+
const level = 'info'
|
|
9
|
+
const msg = 'hello'
|
|
10
|
+
|
|
11
|
+
it('no-ops in dev environment', () => {
|
|
12
|
+
const dispatcher = createAnalyticsDispatcher({
|
|
13
|
+
envName: 'dev',
|
|
14
|
+
bufferWhenNoUser: true,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const out = dispatcher.process({
|
|
18
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED, userId: 'u' },
|
|
19
|
+
level,
|
|
20
|
+
msg,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
expect(out).toEqual([])
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('emits payload when event and user are present', () => {
|
|
27
|
+
const dispatcher = createAnalyticsDispatcher({ envName: 'prod' })
|
|
28
|
+
|
|
29
|
+
const out = dispatcher.process({
|
|
30
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED, userId: 'u' },
|
|
31
|
+
level,
|
|
32
|
+
msg,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(out).toHaveLength(1)
|
|
36
|
+
expect(out[0]).toMatchObject({
|
|
37
|
+
event: AnalyticsEvent.APP_LAUNCHED,
|
|
38
|
+
userId: 'u',
|
|
39
|
+
properties: expect.objectContaining({
|
|
40
|
+
userId: 'u',
|
|
41
|
+
level,
|
|
42
|
+
msg,
|
|
43
|
+
}),
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('buffers when no user and flushes once user appears', () => {
|
|
48
|
+
const dispatcher = createAnalyticsDispatcher({
|
|
49
|
+
envName: 'prod',
|
|
50
|
+
bufferWhenNoUser: true,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Missing user; should buffer
|
|
54
|
+
const first = dispatcher.process({
|
|
55
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED },
|
|
56
|
+
level,
|
|
57
|
+
msg,
|
|
58
|
+
})
|
|
59
|
+
expect(first).toEqual([])
|
|
60
|
+
|
|
61
|
+
// With user; should flush buffered event first, then this one
|
|
62
|
+
const second = dispatcher.process({
|
|
63
|
+
data: {
|
|
64
|
+
eventId: AnalyticsEvent.AGENT_STEP,
|
|
65
|
+
userId: 'user-1',
|
|
66
|
+
},
|
|
67
|
+
level,
|
|
68
|
+
msg,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
expect(second).toHaveLength(2)
|
|
72
|
+
expect(second[0]).toMatchObject({
|
|
73
|
+
event: AnalyticsEvent.APP_LAUNCHED,
|
|
74
|
+
userId: 'user-1',
|
|
75
|
+
})
|
|
76
|
+
expect(second[1]).toMatchObject({
|
|
77
|
+
event: AnalyticsEvent.AGENT_STEP,
|
|
78
|
+
userId: 'user-1',
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('uses fallbackUserId when rebuilding buffered events', () => {
|
|
83
|
+
const dispatcher = createAnalyticsDispatcher({
|
|
84
|
+
envName: 'prod',
|
|
85
|
+
bufferWhenNoUser: true,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
dispatcher.process({
|
|
89
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED },
|
|
90
|
+
level,
|
|
91
|
+
msg,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const out = dispatcher.process({
|
|
95
|
+
data: {
|
|
96
|
+
eventId: AnalyticsEvent.AGENT_STEP,
|
|
97
|
+
},
|
|
98
|
+
level,
|
|
99
|
+
msg,
|
|
100
|
+
fallbackUserId: 'fallback-user',
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
expect(out).toHaveLength(2)
|
|
104
|
+
expect(out[0].userId).toBe('fallback-user')
|
|
105
|
+
expect(out[1].userId).toBe('fallback-user')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('ignores unknown events even when buffering is on', () => {
|
|
109
|
+
const dispatcher = createAnalyticsDispatcher({
|
|
110
|
+
envName: 'prod',
|
|
111
|
+
bufferWhenNoUser: true,
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const out = dispatcher.process({
|
|
115
|
+
data: { eventId: 'not-real' },
|
|
116
|
+
level,
|
|
117
|
+
msg,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(out).toEqual([])
|
|
121
|
+
})
|
|
122
|
+
})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { AnalyticsEvent } from '@anvil/common/constants/analytics-events'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
getAnalyticsEventId,
|
|
7
|
+
toTrackableAnalyticsPayload,
|
|
8
|
+
type AnalyticsLogData,
|
|
9
|
+
} from '../analytics-log'
|
|
10
|
+
|
|
11
|
+
describe('analytics-log helpers', () => {
|
|
12
|
+
const baseMsg = 'hello'
|
|
13
|
+
const baseLevel = 'info'
|
|
14
|
+
|
|
15
|
+
it('returns null for non-object data', () => {
|
|
16
|
+
expect(
|
|
17
|
+
toTrackableAnalyticsPayload({ data: null, level: baseLevel, msg: baseMsg }),
|
|
18
|
+
).toBeNull()
|
|
19
|
+
expect(
|
|
20
|
+
toTrackableAnalyticsPayload({ data: 'x', level: baseLevel, msg: baseMsg }),
|
|
21
|
+
).toBeNull()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('returns null when eventId is missing or unknown', () => {
|
|
25
|
+
expect(
|
|
26
|
+
toTrackableAnalyticsPayload({
|
|
27
|
+
data: {},
|
|
28
|
+
level: baseLevel,
|
|
29
|
+
msg: baseMsg,
|
|
30
|
+
}),
|
|
31
|
+
).toBeNull()
|
|
32
|
+
|
|
33
|
+
expect(
|
|
34
|
+
toTrackableAnalyticsPayload({
|
|
35
|
+
data: { eventId: 'not-real' },
|
|
36
|
+
level: baseLevel,
|
|
37
|
+
msg: baseMsg,
|
|
38
|
+
}),
|
|
39
|
+
).toBeNull()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('returns null when user cannot be resolved', () => {
|
|
43
|
+
expect(
|
|
44
|
+
toTrackableAnalyticsPayload({
|
|
45
|
+
data: { eventId: AnalyticsEvent.AGENT_STEP },
|
|
46
|
+
level: baseLevel,
|
|
47
|
+
msg: baseMsg,
|
|
48
|
+
}),
|
|
49
|
+
).toBeNull()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('builds payload when event and userId exist', () => {
|
|
53
|
+
const payload = toTrackableAnalyticsPayload({
|
|
54
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED, userId: 'u1', extra: 123 },
|
|
55
|
+
level: baseLevel,
|
|
56
|
+
msg: baseMsg,
|
|
57
|
+
})!
|
|
58
|
+
|
|
59
|
+
expect(payload.event).toBe(AnalyticsEvent.APP_LAUNCHED)
|
|
60
|
+
expect(payload.userId).toBe('u1')
|
|
61
|
+
expect(payload.properties).toMatchObject({
|
|
62
|
+
userId: 'u1',
|
|
63
|
+
extra: 123,
|
|
64
|
+
level: baseLevel,
|
|
65
|
+
msg: baseMsg,
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('falls back to nested and underscored user ids', () => {
|
|
70
|
+
const fromUser = toTrackableAnalyticsPayload({
|
|
71
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED, user: { id: 'nested' } },
|
|
72
|
+
level: baseLevel,
|
|
73
|
+
msg: baseMsg,
|
|
74
|
+
})
|
|
75
|
+
expect(fromUser?.userId).toBe('nested')
|
|
76
|
+
|
|
77
|
+
const fromUnderscore = toTrackableAnalyticsPayload({
|
|
78
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED, user_id: 'underscored' },
|
|
79
|
+
level: baseLevel,
|
|
80
|
+
msg: baseMsg,
|
|
81
|
+
})
|
|
82
|
+
expect(fromUnderscore?.userId).toBe('underscored')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('uses fallbackUserId when no user fields exist', () => {
|
|
86
|
+
const payload = toTrackableAnalyticsPayload({
|
|
87
|
+
data: { eventId: AnalyticsEvent.APP_LAUNCHED },
|
|
88
|
+
level: baseLevel,
|
|
89
|
+
msg: baseMsg,
|
|
90
|
+
fallbackUserId: 'fallback',
|
|
91
|
+
})!
|
|
92
|
+
|
|
93
|
+
expect(payload.userId).toBe('fallback')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('getAnalyticsEventId returns only known events', () => {
|
|
97
|
+
const data: AnalyticsLogData = { eventId: AnalyticsEvent.APP_LAUNCHED }
|
|
98
|
+
expect(getAnalyticsEventId(data)).toBe(AnalyticsEvent.APP_LAUNCHED)
|
|
99
|
+
expect(getAnalyticsEventId({ eventId: 'nope' })).toBeNull()
|
|
100
|
+
expect(getAnalyticsEventId(null)).toBeNull()
|
|
101
|
+
})
|
|
102
|
+
})
|