@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.
- package/package.json +74 -70
- 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,95 @@
|
|
|
1
|
+
import z from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
export const CLIENT_ENV_PREFIX = 'NEXT_PUBLIC_'
|
|
4
|
+
|
|
5
|
+
export const clientEnvSchema = z.object({
|
|
6
|
+
NEXT_PUBLIC_CB_ENVIRONMENT: z.enum(['dev', 'test', 'prod']),
|
|
7
|
+
NEXT_PUBLIC_ANVIL_APP_URL: z.url().min(1),
|
|
8
|
+
NEXT_PUBLIC_SUPPORT_EMAIL: z.email().min(1),
|
|
9
|
+
NEXT_PUBLIC_POSTHOG_API_KEY: z.string().min(1),
|
|
10
|
+
NEXT_PUBLIC_POSTHOG_HOST_URL: z.url().min(1),
|
|
11
|
+
NEXT_PUBLIC_GRAVITY_PIXEL_ID: z.uuid().optional(),
|
|
12
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
|
|
13
|
+
NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL: z.url().min(1),
|
|
14
|
+
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID: z.string().optional(),
|
|
15
|
+
NEXT_PUBLIC_WEB_PORT: z.coerce.number().min(1000),
|
|
16
|
+
/** Cloudflare Turnstile site key for the signup challenge. Public by design —
|
|
17
|
+
* the secret half is server-only (`TURNSTILE_SECRET_KEY`). Optional so a dev
|
|
18
|
+
* checkout without Turnstile configured still boots; the server gate decides
|
|
19
|
+
* whether a missing key means "skip" or "refuse". */
|
|
20
|
+
NEXT_PUBLIC_TURNSTILE_SITE_KEY: z.string().min(1).optional(),
|
|
21
|
+
/**
|
|
22
|
+
* Google reCAPTCHA site keys — BOTH versions, which run together rather than
|
|
23
|
+
* as alternatives. v3 scores the session invisibly; v2 asks the human to click
|
|
24
|
+
* a box. Public by design; the secret halves are `RECAPTCHA_V2_SECRET_KEY` and
|
|
25
|
+
* `RECAPTCHA_V3_SECRET_KEY`.
|
|
26
|
+
*
|
|
27
|
+
* These are two separate registrations in the reCAPTCHA console with two
|
|
28
|
+
* separate secrets, and the versions are NOT interchangeable: using a v2 key
|
|
29
|
+
* where a v3 one is expected throws `Invalid site key type`, mints no token,
|
|
30
|
+
* and is indistinguishable at the gate from a bot. Either may be omitted to
|
|
31
|
+
* run only the other; both optional so a dev checkout still boots.
|
|
32
|
+
*/
|
|
33
|
+
NEXT_PUBLIC_RECAPTCHA_V2_SITE_KEY: z.string().min(1).optional(),
|
|
34
|
+
NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY: z.string().min(1).optional(),
|
|
35
|
+
/**
|
|
36
|
+
* Whether the v2 widget is a checkbox everyone clicks or an invisible check.
|
|
37
|
+
*
|
|
38
|
+
* `checkbox` buys nothing against bots that `invisible` does not: both are the
|
|
39
|
+
* same key type hitting the same risk engine, and both escalate to the same
|
|
40
|
+
* image challenge when Google is suspicious. The choice is purely how much
|
|
41
|
+
* friction to show a clean user, which is why it is one env value and not a
|
|
42
|
+
* design. NOTE that the key itself is registered as one or the other, so this
|
|
43
|
+
* has to match the registration — an invisible-registered key rejects
|
|
44
|
+
* `checkbox` outright.
|
|
45
|
+
*
|
|
46
|
+
* Optional rather than `.default('checkbox')`, with the default applied at the
|
|
47
|
+
* point of use. A `.default()` here would make this the only field in this
|
|
48
|
+
* schema whose OUTPUT type is required, and `clientEnv` is built as an object
|
|
49
|
+
* literal by fixtures across agent-runtime, evals and web — so it breaks all
|
|
50
|
+
* of them at the type level over a value none of them care about. Adding a
|
|
51
|
+
* DEFAULTED client env var is quietly a breaking change; an optional one is
|
|
52
|
+
* not.
|
|
53
|
+
*/
|
|
54
|
+
NEXT_PUBLIC_RECAPTCHA_V2_SIZE: z.enum(['checkbox', 'invisible']).optional(),
|
|
55
|
+
/** Human Behavior session-replay write key for Anvil Web. Public by
|
|
56
|
+
* design — it only authorizes ingestion. Optional so a dev checkout without
|
|
57
|
+
* it boots with replay simply switched off. */
|
|
58
|
+
NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY: z.string().min(1).optional(),
|
|
59
|
+
/** Overrides the SDK's default ingestion host; only set to point a
|
|
60
|
+
* deployment at a non-default Human Behavior endpoint. */
|
|
61
|
+
NEXT_PUBLIC_HUMANBEHAVIOR_INGESTION_URL: z.url().optional(),
|
|
62
|
+
} satisfies Record<`${typeof CLIENT_ENV_PREFIX}${string}`, any>)
|
|
63
|
+
export const clientEnvVars = clientEnvSchema.keyof().options
|
|
64
|
+
export type ClientEnvVar = (typeof clientEnvVars)[number]
|
|
65
|
+
export type ClientInput = {
|
|
66
|
+
[K in (typeof clientEnvVars)[number]]: string | undefined
|
|
67
|
+
}
|
|
68
|
+
export type ClientEnv = z.infer<typeof clientEnvSchema>
|
|
69
|
+
|
|
70
|
+
// Bun will inject all these values, so we need to reference them individually (no for-loops)
|
|
71
|
+
export const clientProcessEnv: ClientInput = {
|
|
72
|
+
NEXT_PUBLIC_CB_ENVIRONMENT: process.env.NEXT_PUBLIC_CB_ENVIRONMENT,
|
|
73
|
+
NEXT_PUBLIC_ANVIL_APP_URL: process.env.NEXT_PUBLIC_ANVIL_APP_URL,
|
|
74
|
+
NEXT_PUBLIC_SUPPORT_EMAIL: process.env.NEXT_PUBLIC_SUPPORT_EMAIL,
|
|
75
|
+
NEXT_PUBLIC_POSTHOG_API_KEY: process.env.NEXT_PUBLIC_POSTHOG_API_KEY,
|
|
76
|
+
NEXT_PUBLIC_POSTHOG_HOST_URL: process.env.NEXT_PUBLIC_POSTHOG_HOST_URL,
|
|
77
|
+
NEXT_PUBLIC_GRAVITY_PIXEL_ID: process.env.NEXT_PUBLIC_GRAVITY_PIXEL_ID,
|
|
78
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:
|
|
79
|
+
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
|
|
80
|
+
NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL:
|
|
81
|
+
process.env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL,
|
|
82
|
+
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID:
|
|
83
|
+
process.env.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION_ID,
|
|
84
|
+
NEXT_PUBLIC_WEB_PORT: process.env.NEXT_PUBLIC_WEB_PORT,
|
|
85
|
+
NEXT_PUBLIC_TURNSTILE_SITE_KEY: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY,
|
|
86
|
+
NEXT_PUBLIC_RECAPTCHA_V2_SITE_KEY:
|
|
87
|
+
process.env.NEXT_PUBLIC_RECAPTCHA_V2_SITE_KEY,
|
|
88
|
+
NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY:
|
|
89
|
+
process.env.NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY,
|
|
90
|
+
NEXT_PUBLIC_RECAPTCHA_V2_SIZE: process.env.NEXT_PUBLIC_RECAPTCHA_V2_SIZE,
|
|
91
|
+
NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY:
|
|
92
|
+
process.env.NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY,
|
|
93
|
+
NEXT_PUBLIC_HUMANBEHAVIOR_INGESTION_URL:
|
|
94
|
+
process.env.NEXT_PUBLIC_HUMANBEHAVIOR_INGESTION_URL,
|
|
95
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { clientEnvSchema, clientProcessEnv } from './env-schema'
|
|
2
|
+
|
|
3
|
+
const parsedEnv = clientEnvSchema.safeParse(clientProcessEnv)
|
|
4
|
+
if (!parsedEnv.success) {
|
|
5
|
+
console.error('Environment validation failed:', parsedEnv.error.issues)
|
|
6
|
+
throw new Error(`Invalid environment configuration: ${parsedEnv.error.message}`)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const env = parsedEnv.data
|
|
10
|
+
|
|
11
|
+
// Only log environment in non-production
|
|
12
|
+
if (env.NEXT_PUBLIC_CB_ENVIRONMENT !== 'prod') {
|
|
13
|
+
console.log('Using environment:', env.NEXT_PUBLIC_CB_ENVIRONMENT)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Derived environment constants for convenience
|
|
17
|
+
export const IS_DEV = env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev'
|
|
18
|
+
export const IS_TEST = env.NEXT_PUBLIC_CB_ENVIRONMENT === 'test'
|
|
19
|
+
export const IS_PROD = env.NEXT_PUBLIC_CB_ENVIRONMENT === 'prod'
|
|
20
|
+
export const IS_CI = process.env.ANVIL_GITHUB_ACTIONS === 'true'
|
|
21
|
+
|
|
22
|
+
// Debug flag for logging analytics events in dev mode
|
|
23
|
+
// Set to true when actively debugging analytics - affects both CLI and backend
|
|
24
|
+
export const DEBUG_ANALYTICS = false
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
export const GRAVITY_CAPI_ENDPOINT = 'https://api.trygravity.ai/gateway/events'
|
|
2
|
+
export const GRAVITY_FIRST_MESSAGE_EVENT = 'FirstMessage'
|
|
3
|
+
|
|
4
|
+
export const ANVIL_GRAVITY_SURFACES = [
|
|
5
|
+
'cli',
|
|
6
|
+
'desktop',
|
|
7
|
+
'web',
|
|
8
|
+
'cloud',
|
|
9
|
+
'chat',
|
|
10
|
+
] as const
|
|
11
|
+
export type AnvilGravitySurface = (typeof ANVIL_GRAVITY_SURFACES)[number]
|
|
12
|
+
export type AnvilServiceGravitySurface = Extract<
|
|
13
|
+
AnvilGravitySurface,
|
|
14
|
+
'web' | 'cloud' | 'chat'
|
|
15
|
+
>
|
|
16
|
+
|
|
17
|
+
export function isAnvilGravitySurface(
|
|
18
|
+
value: unknown,
|
|
19
|
+
): value is AnvilGravitySurface {
|
|
20
|
+
return ANVIL_GRAVITY_SURFACES.includes(value as AnvilGravitySurface)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isAnvilServiceGravitySurface(
|
|
24
|
+
value: unknown,
|
|
25
|
+
): value is AnvilServiceGravitySurface {
|
|
26
|
+
return value === 'web' || value === 'cloud' || value === 'chat'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type GravityCapiUserData = {
|
|
30
|
+
click_id?: string | null
|
|
31
|
+
visitor_id?: string | null
|
|
32
|
+
session_id?: string | null
|
|
33
|
+
client_user_agent?: string | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Attribution and device data returned by window.gravityPixel.getCAPIData(). */
|
|
37
|
+
export type GravityCapiData = {
|
|
38
|
+
user_data?: GravityCapiUserData | null
|
|
39
|
+
event_source_url?: string | null
|
|
40
|
+
client_context?: Record<string, unknown> | null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type GravityConversionResult = {
|
|
44
|
+
event_id?: string
|
|
45
|
+
status?: string
|
|
46
|
+
attributed?: boolean
|
|
47
|
+
error?: unknown
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function boundedString(value: unknown, maxLength: number): string | undefined {
|
|
51
|
+
return typeof value === 'string' && value.trim() && value.length <= maxLength
|
|
52
|
+
? value
|
|
53
|
+
: undefined
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function boundedObject(
|
|
57
|
+
value: unknown,
|
|
58
|
+
maxJsonLength: number,
|
|
59
|
+
): Record<string, unknown> | undefined {
|
|
60
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
61
|
+
return undefined
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return new TextEncoder().encode(JSON.stringify(value)).byteLength <=
|
|
65
|
+
maxJsonLength
|
|
66
|
+
? (value as Record<string, unknown>)
|
|
67
|
+
: undefined
|
|
68
|
+
} catch {
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Sanitizes the untrusted browser result from gravityPixel.getCAPIData(). */
|
|
74
|
+
export function sanitizeGravityCapiData(
|
|
75
|
+
raw: unknown,
|
|
76
|
+
fallbackEventSourceUrl?: unknown,
|
|
77
|
+
): GravityCapiData | undefined {
|
|
78
|
+
const value =
|
|
79
|
+
raw && typeof raw === 'object' && !Array.isArray(raw)
|
|
80
|
+
? (raw as Record<string, unknown>)
|
|
81
|
+
: undefined
|
|
82
|
+
const rawUser =
|
|
83
|
+
value?.user_data &&
|
|
84
|
+
typeof value.user_data === 'object' &&
|
|
85
|
+
!Array.isArray(value.user_data)
|
|
86
|
+
? (value.user_data as Record<string, unknown>)
|
|
87
|
+
: undefined
|
|
88
|
+
const eventSourceUrl =
|
|
89
|
+
boundedString(fallbackEventSourceUrl, 8192) ??
|
|
90
|
+
boundedString(value?.event_source_url, 8192)
|
|
91
|
+
const clientContext = boundedObject(value?.client_context, 32_768)
|
|
92
|
+
|
|
93
|
+
if (!value && !eventSourceUrl) return undefined
|
|
94
|
+
return {
|
|
95
|
+
user_data: rawUser
|
|
96
|
+
? {
|
|
97
|
+
click_id: boundedString(rawUser.click_id, 4096),
|
|
98
|
+
visitor_id: boundedString(rawUser.visitor_id, 4096),
|
|
99
|
+
session_id: boundedString(rawUser.session_id, 4096),
|
|
100
|
+
client_user_agent: boundedString(rawUser.client_user_agent, 4096),
|
|
101
|
+
}
|
|
102
|
+
: undefined,
|
|
103
|
+
event_source_url: eventSourceUrl,
|
|
104
|
+
client_context: clientContext,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function gravityFirstMessageEventId(userId: string): string {
|
|
109
|
+
return `anvil-first-message-${userId}`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function buildGravityFirstMessagePayload(params: {
|
|
113
|
+
userId: string
|
|
114
|
+
email?: string | null
|
|
115
|
+
surface: AnvilGravitySurface
|
|
116
|
+
gravity?: GravityCapiData | null
|
|
117
|
+
userAgent?: string | null
|
|
118
|
+
eventTime?: number
|
|
119
|
+
}) {
|
|
120
|
+
const pixelUser = params.gravity?.user_data ?? {}
|
|
121
|
+
const userData = {
|
|
122
|
+
...(pixelUser.click_id ? { click_id: pixelUser.click_id } : {}),
|
|
123
|
+
...(pixelUser.visitor_id ? { visitor_id: pixelUser.visitor_id } : {}),
|
|
124
|
+
...(pixelUser.session_id ? { session_id: pixelUser.session_id } : {}),
|
|
125
|
+
...(pixelUser.client_user_agent || params.userAgent
|
|
126
|
+
? {
|
|
127
|
+
client_user_agent:
|
|
128
|
+
pixelUser.client_user_agent ?? params.userAgent ?? undefined,
|
|
129
|
+
}
|
|
130
|
+
: {}),
|
|
131
|
+
...(params.email ? { em: [params.email] } : {}),
|
|
132
|
+
external_id: [params.userId],
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
data: [
|
|
137
|
+
{
|
|
138
|
+
event_name: GRAVITY_FIRST_MESSAGE_EVENT,
|
|
139
|
+
event_time: params.eventTime ?? Math.floor(Date.now() / 1000),
|
|
140
|
+
event_id: gravityFirstMessageEventId(params.userId),
|
|
141
|
+
action_source: 'website',
|
|
142
|
+
...(params.gravity?.event_source_url
|
|
143
|
+
? { event_source_url: params.gravity.event_source_url }
|
|
144
|
+
: {}),
|
|
145
|
+
user_data: userData,
|
|
146
|
+
...(params.gravity?.client_context
|
|
147
|
+
? { client_context: params.gravity.client_context }
|
|
148
|
+
: {}),
|
|
149
|
+
custom_data: {
|
|
150
|
+
content_name: 'Anvil first message',
|
|
151
|
+
content_category: params.surface,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Sends the account-level first-message conversion. The caller owns retry and
|
|
160
|
+
* persistence; this function throws unless Gravity confirms a terminal result.
|
|
161
|
+
*/
|
|
162
|
+
export async function sendGravityFirstMessageConversion(params: {
|
|
163
|
+
apiKey: string
|
|
164
|
+
userId: string
|
|
165
|
+
email?: string | null
|
|
166
|
+
surface: AnvilGravitySurface
|
|
167
|
+
gravity?: GravityCapiData | null
|
|
168
|
+
userAgent?: string | null
|
|
169
|
+
fetchImpl?: typeof fetch
|
|
170
|
+
}): Promise<GravityConversionResult> {
|
|
171
|
+
const fetchImpl = params.fetchImpl ?? fetch
|
|
172
|
+
const response = await fetchImpl(GRAVITY_CAPI_ENDPOINT, {
|
|
173
|
+
method: 'POST',
|
|
174
|
+
headers: {
|
|
175
|
+
Authorization: `Bearer ${params.apiKey}`,
|
|
176
|
+
'Content-Type': 'application/json',
|
|
177
|
+
'User-Agent': 'anvil/1.0 (gravity-capi)',
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify(buildGravityFirstMessagePayload(params)),
|
|
180
|
+
signal: AbortSignal.timeout(3_000),
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
const responseText = await response.text()
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`Gravity CAPI rejected FirstMessage (${response.status}): ${responseText.slice(0, 500)}`,
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let body: { results?: GravityConversionResult[] }
|
|
191
|
+
try {
|
|
192
|
+
body = JSON.parse(responseText) as { results?: GravityConversionResult[] }
|
|
193
|
+
} catch {
|
|
194
|
+
throw new Error('Gravity CAPI returned invalid JSON for FirstMessage')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const result = body.results?.[0]
|
|
198
|
+
if (!result?.status) {
|
|
199
|
+
throw new Error('Gravity CAPI returned no result for FirstMessage')
|
|
200
|
+
}
|
|
201
|
+
if (!['ok', 'duplicate', 'test_ok', 'skipped'].includes(result.status)) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Gravity CAPI failed FirstMessage with status ${result.status}`,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
return result
|
|
207
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
2
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
|
|
4
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
|
|
5
|
+
|
|
6
|
+
import { getErrorObject } from '../util/error'
|
|
7
|
+
|
|
8
|
+
import type { MCPConfig } from '../types/mcp'
|
|
9
|
+
import type { ToolResultOutput } from '../types/messages/content-part'
|
|
10
|
+
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'
|
|
11
|
+
import type {
|
|
12
|
+
BlobResourceContents,
|
|
13
|
+
CallToolResult,
|
|
14
|
+
TextResourceContents,
|
|
15
|
+
} from '@modelcontextprotocol/sdk/types.js'
|
|
16
|
+
|
|
17
|
+
// Cap on how much of a failed stdio server's stderr we retain for the error
|
|
18
|
+
// message — enough to show the real failure without unbounded growth.
|
|
19
|
+
const STDERR_BUFFER_CAP = 8192
|
|
20
|
+
|
|
21
|
+
const runningClients: Record<string, Client> = {}
|
|
22
|
+
const listToolsCache: Record<
|
|
23
|
+
string,
|
|
24
|
+
ReturnType<typeof Client.prototype.listTools>
|
|
25
|
+
> = {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Substitutes environment variable references ($VAR_NAME) in a string with their values.
|
|
29
|
+
* Supports both simple replacement ("$VAR_NAME") and interpolation ("Bearer $VAR_NAME").
|
|
30
|
+
*/
|
|
31
|
+
function substituteEnvInValue(value: string): string {
|
|
32
|
+
return value.replace(/\$([A-Z_][A-Z0-9_]*)/g, (match, varName) => {
|
|
33
|
+
const envValue = process.env[varName]
|
|
34
|
+
if (envValue === undefined) {
|
|
35
|
+
// Return original if env var not found
|
|
36
|
+
return match
|
|
37
|
+
}
|
|
38
|
+
return envValue
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Substitutes environment variable references in all values of a record.
|
|
44
|
+
*/
|
|
45
|
+
function substituteEnvInRecord(
|
|
46
|
+
record: Record<string, string>,
|
|
47
|
+
): Record<string, string> {
|
|
48
|
+
const result: Record<string, string> = {}
|
|
49
|
+
for (const [key, value] of Object.entries(record)) {
|
|
50
|
+
result[key] = substituteEnvInValue(value)
|
|
51
|
+
}
|
|
52
|
+
return result
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function hashConfig(config: MCPConfig): string {
|
|
56
|
+
if (config.type === 'stdio') {
|
|
57
|
+
return JSON.stringify({
|
|
58
|
+
command: config.command,
|
|
59
|
+
args: config.args,
|
|
60
|
+
env: config.env,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
if (config.type === 'http') {
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
type: 'http',
|
|
66
|
+
url: config.url,
|
|
67
|
+
params: config.params,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
if (config.type === 'sse') {
|
|
71
|
+
return JSON.stringify({
|
|
72
|
+
type: 'sse',
|
|
73
|
+
url: config.url,
|
|
74
|
+
params: config.params,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
config.type satisfies never
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Internal error in hashConfig: invalid MCP config type ${config.type}`,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function getMCPClient(config: MCPConfig): Promise<string> {
|
|
84
|
+
let key = hashConfig(config)
|
|
85
|
+
if (key in runningClients) {
|
|
86
|
+
return key
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let transport: Transport
|
|
90
|
+
// Buffer the child process's stderr so that a server which crashes during
|
|
91
|
+
// startup produces an actionable error instead of the opaque MCP SDK message
|
|
92
|
+
// "MCP error -32000: Connection closed".
|
|
93
|
+
let stderrBuffer = ''
|
|
94
|
+
if (config.type === 'stdio') {
|
|
95
|
+
const stdioTransport = new StdioClientTransport({
|
|
96
|
+
command: config.command,
|
|
97
|
+
args: config.args,
|
|
98
|
+
env: substituteEnvInRecord(config.env),
|
|
99
|
+
stderr: 'pipe',
|
|
100
|
+
})
|
|
101
|
+
// When stderr is 'pipe' the SDK exposes a PassThrough immediately (before
|
|
102
|
+
// the process is spawned), so attaching here captures even early output
|
|
103
|
+
// from a child that dies during the connection handshake.
|
|
104
|
+
stdioTransport.stderr?.on('data', (chunk: Buffer) => {
|
|
105
|
+
if (stderrBuffer.length < STDERR_BUFFER_CAP) {
|
|
106
|
+
stderrBuffer += chunk.toString('utf8')
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
transport = stdioTransport
|
|
110
|
+
} else {
|
|
111
|
+
const url = new URL(config.url)
|
|
112
|
+
for (const [key, value] of Object.entries(config.params)) {
|
|
113
|
+
url.searchParams.set(key, value)
|
|
114
|
+
}
|
|
115
|
+
const headers = substituteEnvInRecord(config.headers)
|
|
116
|
+
if (config.type === 'http') {
|
|
117
|
+
transport = new StreamableHTTPClientTransport(url, {
|
|
118
|
+
requestInit: {
|
|
119
|
+
headers,
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
} else if (config.type === 'sse') {
|
|
123
|
+
transport = new SSEClientTransport(url, {
|
|
124
|
+
requestInit: {
|
|
125
|
+
headers,
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
} else {
|
|
129
|
+
config.type satisfies never
|
|
130
|
+
throw new Error(`Internal error: invalid MCP config type ${config.type}`)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const client = new Client({
|
|
135
|
+
name: 'anvil',
|
|
136
|
+
version: '1.0.0',
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
await client.connect(transport)
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const baseMessage = getErrorObject(error).message
|
|
143
|
+
if (config.type === 'stdio') {
|
|
144
|
+
const commandStr = [config.command, ...(config.args ?? [])].join(' ')
|
|
145
|
+
const detail = stderrBuffer.trim()
|
|
146
|
+
throw new Error(
|
|
147
|
+
`${baseMessage}. Failed to start MCP server via \`${commandStr}\`. ` +
|
|
148
|
+
`Ensure the command is installed and runnable (e.g. an up-to-date ` +
|
|
149
|
+
`node/npm/npx, or python/uvx) and that any required env vars are set.` +
|
|
150
|
+
(detail ? `\nServer stderr:\n${detail}` : ''),
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
throw new Error(
|
|
154
|
+
`${baseMessage}. Failed to connect to MCP server at ${config.url}.`,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
runningClients[key] = client
|
|
158
|
+
|
|
159
|
+
return key
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function listMCPTools(
|
|
163
|
+
clientId: string,
|
|
164
|
+
...args: Parameters<typeof Client.prototype.listTools>
|
|
165
|
+
): ReturnType<typeof Client.prototype.listTools> {
|
|
166
|
+
const client = runningClients[clientId]
|
|
167
|
+
if (!client) {
|
|
168
|
+
throw new Error(`listTools: client not found with id: ${clientId}`)
|
|
169
|
+
}
|
|
170
|
+
if (!listToolsCache[clientId]) {
|
|
171
|
+
listToolsCache[clientId] = client.listTools(...args)
|
|
172
|
+
}
|
|
173
|
+
return listToolsCache[clientId]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getResourceData(
|
|
177
|
+
resource: TextResourceContents | BlobResourceContents,
|
|
178
|
+
): string {
|
|
179
|
+
if ('text' in resource) return resource.text as string
|
|
180
|
+
if ('blob' in resource) return resource.blob as string
|
|
181
|
+
return ''
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export async function callMCPTool(
|
|
185
|
+
clientId: string,
|
|
186
|
+
...args: Parameters<typeof Client.prototype.callTool>
|
|
187
|
+
): Promise<ToolResultOutput[]> {
|
|
188
|
+
const client = runningClients[clientId]
|
|
189
|
+
if (!client) {
|
|
190
|
+
throw new Error(`callTool: client not found with id: ${clientId}`)
|
|
191
|
+
}
|
|
192
|
+
const callResult = await client.callTool(...args)
|
|
193
|
+
const result = callResult as CallToolResult
|
|
194
|
+
const content = result.content
|
|
195
|
+
|
|
196
|
+
return content.map((c: (typeof content)[number]) => {
|
|
197
|
+
if (c.type === 'text') {
|
|
198
|
+
return {
|
|
199
|
+
type: 'json',
|
|
200
|
+
value: c.text,
|
|
201
|
+
} satisfies ToolResultOutput
|
|
202
|
+
}
|
|
203
|
+
if (c.type === 'audio') {
|
|
204
|
+
return {
|
|
205
|
+
type: 'media',
|
|
206
|
+
data: c.data,
|
|
207
|
+
mediaType: c.mimeType,
|
|
208
|
+
} satisfies ToolResultOutput
|
|
209
|
+
}
|
|
210
|
+
if (c.type === 'image') {
|
|
211
|
+
return {
|
|
212
|
+
type: 'media',
|
|
213
|
+
data: c.data,
|
|
214
|
+
mediaType: c.mimeType,
|
|
215
|
+
} satisfies ToolResultOutput
|
|
216
|
+
}
|
|
217
|
+
if (c.type === 'resource') {
|
|
218
|
+
return {
|
|
219
|
+
type: 'media',
|
|
220
|
+
data: getResourceData(c.resource),
|
|
221
|
+
mediaType: c.resource.mimeType ?? 'text/plain',
|
|
222
|
+
} satisfies ToolResultOutput
|
|
223
|
+
}
|
|
224
|
+
const fallbackValue =
|
|
225
|
+
'uri' in c && typeof (c as { uri: unknown }).uri === 'string'
|
|
226
|
+
? (c as { uri: string }).uri
|
|
227
|
+
: JSON.stringify(c)
|
|
228
|
+
return {
|
|
229
|
+
type: 'json',
|
|
230
|
+
value: fallbackValue,
|
|
231
|
+
} satisfies ToolResultOutput
|
|
232
|
+
})
|
|
233
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Import from '@anvil/common/constants' or specific files instead:
|
|
3
|
+
* - '@anvil/common/constants/model-config' for model-related constants
|
|
4
|
+
* - '@anvil/common/constants/limits' for billing and numeric limits
|
|
5
|
+
* - '@anvil/common/constants/ui' for auth/user state
|
|
6
|
+
* - '@anvil/common/constants/paths' for file paths and markers
|
|
7
|
+
*
|
|
8
|
+
* This file re-exports all constants for backwards compatibility.
|
|
9
|
+
*/
|
|
10
|
+
export * from './constants'
|